From: Mihailo Stojanovic <mistojano...@wavecomp.com>

gcc/
        * config/mips/mips.cc (mips_rtx_costs): Reduce branch cost of
        conditional branches.
        (mips_prune_insertions_deletions): Target hook which checks
        whether a basic block is possibly if-convertible. Adjusts the
        insertion and deletion maps accordingly.
        (check_bb): Check whether a basic block is a THEN or ELSE block
        of IF-THEN-ELSE construct and whether it consists only of a
        single set instruction. This is a condition for marking the
        block as possibly if-convertible.
        (bb_valid_for_noce): Helper function.
        (last_active_insn): Same.
        (first_active_insn): Same.
        (insn_valid_noce_process_p): Same.
        (noce_operand_ok): Same.
        * config/mips/mips.opt: Add an option which disables the
        mips_prune_insertions_deletions hook.
        * doc/tm.texi.in: Add a macro definition for the new target
        hook.
        * gcse.c (compute_pre_data): Add the target hook call, which
        will modify the insertion and deletion bitmaps.
        * target.def: Define the target hook.
        * targhooks.h: Add default target hook prototype.
        * targhooks.c: Define the default target hook prototype.
        * doc/tm.texi: Regenerated.

Cherry-picked 64e5b4b4ff53872482454908a29c94665e40d25c
from https://github.com/MIPS/gcc

Signed-off-by: Mihailo Stojanovic <mistojano...@wavecomp.com>
Signed-off-by: Faraz Shahbazker <fshahbaz...@wavecomp.com>
Signed-off-by: Aleksandar Rakic <aleksandar.ra...@htecgroup.com>
---
 gcc/config/mips/mips.cc  | 238 +++++++++++++++++++++++++++++++++++++++
 gcc/config/mips/mips.opt |   3 +
 gcc/doc/tm.texi          |   5 +
 gcc/doc/tm.texi.in       |   2 +
 gcc/gcse.cc              |   3 +
 gcc/target.def           |   8 ++
 gcc/targhooks.cc         |   9 ++
 gcc/targhooks.h          |   5 +
 8 files changed, 273 insertions(+)

diff --git a/gcc/config/mips/mips.cc b/gcc/config/mips/mips.cc
index 4521cac15c7..d23c30a43be 100644
--- a/gcc/config/mips/mips.cc
+++ b/gcc/config/mips/mips.cc
@@ -5754,6 +5754,8 @@ mips_rtx_costs (rtx x, machine_mode mode, int outer_code,
        default:
          break;
        }
+      if (GET_CODE (SET_DEST (x)) != PC)
+       *total = 0;
       return false;
 
     case IF_THEN_ELSE:
@@ -25872,6 +25874,239 @@ mips_noce_conversion_profitable_p (rtx_insn *seq, 
struct noce_if_info *if_info)
   return speed && cost <= if_info->max_seq_cost;
 }
 
+
+/* Return true if OP is ok for if-then-else processing.  */
+
+static int
+noce_operand_ok (const_rtx op)
+{
+  if (side_effects_p (op))
+    return FALSE;
+
+  /* We special-case memories, so handle any of them with
+     no address side effects.  */
+  if (MEM_P (op))
+    return ! side_effects_p (XEXP (op, 0));
+
+  return ! may_trap_p (op);
+}
+
+
+/* Helper for bb_valid_for_noce_process_p.  Validate that
+   the rtx insn INSN is a single set that does not set
+   the conditional register CC and is in general valid for
+   if-conversion.  */
+
+static bool
+insn_valid_noce_process_p (rtx_insn *insn)
+{
+  if (!insn
+      || !NONJUMP_INSN_P (insn))
+      return false;
+
+  rtx sset = single_set (insn);
+
+  /* Currently support only simple single sets in test_bb.  */
+  if (!sset
+      || !noce_operand_ok (SET_DEST (sset))
+      || !noce_operand_ok (SET_SRC (sset)))
+    return false;
+
+  return true;
+}
+
+/* Return the first non-jump active insn in the basic block.  */
+
+static rtx_insn *
+first_active_insn (basic_block bb)
+{
+  rtx_insn *insn = BB_HEAD (bb);
+
+  if (LABEL_P (insn))
+    {
+      if (insn == BB_END (bb))
+       return NULL;
+      insn = NEXT_INSN (insn);
+    }
+
+  while (NOTE_P (insn) || DEBUG_INSN_P (insn))
+    {
+      if (insn == BB_END (bb))
+       return NULL;
+      insn = NEXT_INSN (insn);
+    }
+
+  if (JUMP_P (insn))
+    return NULL;
+
+  return insn;
+}
+
+static rtx_insn *
+last_active_insn (basic_block bb, int skip_use_p)
+{
+  rtx_insn *insn = BB_END (bb);
+  rtx_insn *head = BB_HEAD (bb);
+
+  while (NOTE_P (insn)
+        || JUMP_P (insn)
+        || DEBUG_INSN_P (insn)
+        || (skip_use_p
+            && NONJUMP_INSN_P (insn)
+            && GET_CODE (PATTERN (insn)) == USE))
+    {
+      if (insn == head)
+       return NULL;
+      insn = PREV_INSN (insn);
+    }
+
+  if (LABEL_P (insn))
+    return NULL;
+
+  return insn;
+}
+
+static bool
+bb_valid_for_noce (basic_block test_bb, bool *simple)
+{
+  if (!test_bb)
+    return false;
+
+  rtx_insn *last_insn = last_active_insn (test_bb, FALSE);
+
+  if (!insn_valid_noce_process_p (last_insn))
+    return false;
+
+  rtx_insn *first_insn = first_active_insn (test_bb);
+  rtx first_set = single_set (first_insn);
+
+  if (!first_set)
+    return false;
+
+  *simple = first_insn == last_insn;
+  return true;
+}
+
+#define NULL_BLOCK     ((basic_block) NULL)
+
+static bool
+check_bb (basic_block test_bb, sbitmap *ifcv_blocks)
+{
+  /* The kind of block we're looking for has exactly two successors.  */
+  if (EDGE_COUNT (test_bb->succs) != 2)
+    return false;
+
+  edge then_edge = EDGE_SUCC (test_bb, 0);
+  edge else_edge = EDGE_SUCC (test_bb, 1);
+
+  /* The THEN edge is canonically the one that falls through.  */
+  if (then_edge->flags & EDGE_FALLTHRU)
+    ;
+  else if (else_edge->flags & EDGE_FALLTHRU)
+    std::swap (then_edge, else_edge);
+  else
+    /* Otherwise this must be a multiway branch of some sort.  */
+    return false;
+
+  basic_block then_bb, else_bb;
+
+  /* Recognize an IF-THEN-ELSE-JOIN block.  */
+  if (single_pred_p (then_edge->dest)
+       && single_succ_p (then_edge->dest)
+       && single_pred_p (else_edge->dest)
+       && single_succ_p (else_edge->dest)
+       && single_succ (then_edge->dest) == single_succ (else_edge->dest))
+    {
+       then_bb = then_edge->dest;
+       else_bb = else_edge->dest;
+    }
+  /* Recognize an IF-THEN-JOIN block.  */
+  else if (single_pred_p (then_edge->dest)
+            && single_succ_p (then_edge->dest)
+            && single_succ (then_edge->dest) == else_edge->dest)
+    {
+       then_bb = then_edge->dest;
+       else_bb = NULL_BLOCK;
+    }
+  /* Recognize an IF-ELSE-JOIN block.  We can have those because the order
+     of basic blocks in cfglayout mode does not matter, so the fallthrough
+     edge can go to any basic block (and not just to bb->next_bb, like in
+     cfgrtl mode).  */
+  else if (single_pred_p (else_edge->dest)
+            && single_succ_p (else_edge->dest)
+            && single_succ (else_edge->dest) == then_edge->dest)
+    {
+       /* The noce transformations do not apply to IF-ELSE-JOIN blocks.
+          To make this work, we have to invert the THEN and ELSE blocks
+          and reverse the jump condition.  */
+       then_bb = else_edge->dest;
+       else_bb = NULL_BLOCK;
+    }
+  else
+    /* Not a form we can handle.  */
+    return FALSE;
+
+  bool then_simple = false;
+  bool else_simple = false;
+
+  if (bb_valid_for_noce (then_bb, &then_simple) && then_simple)
+    bitmap_set_bit (*ifcv_blocks, then_bb->index);
+  if (bb_valid_for_noce (else_bb, &else_simple) && else_simple)
+    bitmap_set_bit (*ifcv_blocks, else_bb->index);
+
+  return false;
+}
+
+void
+mips_prune_insertions_deletions (struct edge_list* edge_list,
+                                unsigned int n_elems,
+                                sbitmap *pre_insert_map,
+                                sbitmap *pre_delete_map)
+{
+  basic_block bb;
+  unsigned int i, j;
+  sbitmap_iterator sbi;
+  unsigned int bb_num = (unsigned) last_basic_block_for_fn (cfun);
+  sbitmap ifcv_blocks = sbitmap_alloc (bb_num);
+  sbitmap insertions = sbitmap_alloc (n_elems);
+  bitmap_clear (ifcv_blocks);
+  bitmap_clear (insertions);
+
+  if (TARGET_PRUNE_INSERT_DELETE)
+    return;
+
+  FOR_EACH_BB_FN (bb, cfun)
+    check_bb (bb, &ifcv_blocks);
+
+  int num_edges = NUM_EDGES (edge_list);
+  int e;
+  for (e = 0; e < num_edges; e++)
+    {
+      basic_block pred = INDEX_EDGE_PRED_BB (edge_list, e);
+      basic_block succ = INDEX_EDGE_SUCC_BB (edge_list, e);
+
+      if (bitmap_bit_p (ifcv_blocks, pred->index)
+         || bitmap_bit_p (ifcv_blocks, succ->index))
+       {
+         EXECUTE_IF_SET_IN_BITMAP (pre_insert_map[e], 0, i, sbi)
+           bitmap_set_bit (insertions, i);
+
+         bitmap_clear (pre_insert_map[e]);
+       }
+    }
+
+  for (i = 0; i < bb_num; i++)
+    {
+      EXECUTE_IF_SET_IN_BITMAP (pre_delete_map[i], 0, j, sbi)
+       {
+         if (bitmap_bit_p (insertions, j))
+           bitmap_clear_bit (pre_delete_map[i], j);
+       }
+    }
+
+  sbitmap_free (ifcv_blocks);
+  sbitmap_free (insertions);
+}
 
 /* Initialize the GCC target structure.  */
 #undef TARGET_ASM_ALIGNED_HI_OP
@@ -26217,6 +26452,9 @@ mips_noce_conversion_profitable_p (rtx_insn *seq, 
struct noce_if_info *if_info)
 #undef TARGET_NOCE_CONVERSION_PROFITABLE_P
 #define TARGET_NOCE_CONVERSION_PROFITABLE_P mips_noce_conversion_profitable_p
 
+#undef TARGET_PRUNE_INSERTIONS_DELETIONS
+#define TARGET_PRUNE_INSERTIONS_DELETIONS mips_prune_insertions_deletions
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-mips.h"
diff --git a/gcc/config/mips/mips.opt b/gcc/config/mips/mips.opt
index be347155286..804f4fecbc9 100644
--- a/gcc/config/mips/mips.opt
+++ b/gcc/config/mips/mips.opt
@@ -570,6 +570,9 @@ Target Undocumented Var(TARGET_USE_SAVE_RESTORE) Init(-1)
 muse-copyw-ucopyw
 Target Undocumented Var(TARGET_USE_COPYW_UCOPYW) Init(-1)
 
+mno-prune-insert-delete
+Target Undocumented Var(TARGET_PRUNE_INSERT_DELETE)
+
 minline-intermix
 Target Var(TARGET_INLINE_INTERMIX)
 Allow inlining even if the compression flags differ between caller and callee.
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 109e40384b6..aac034524e7 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -7323,6 +7323,11 @@ The default implementation of this hook uses the
 and uses a multiple of @code{BRANCH_COST} otherwise.
 @end deftypefn
 
+@deftypefn {Target Hook} void TARGET_PRUNE_INSERTIONS_DELETIONS (struct 
edge_list *@var{edge_list}, unsigned int @var{n_elems}, sbitmap 
*@var{pre_insert_map}, sbitmap *@var{pre_delete_map})
+This hook gives the target a possibility to stop the code motion during
+  GCSE pass for basic blocks which have a potential to be if-converted.
+@end deftypefn
+
 @deftypefn {Target Hook} bool TARGET_NOCE_CONVERSION_PROFITABLE_P (rtx_insn 
*@var{seq}, struct noce_if_info *@var{if_info})
 This hook returns true if the instruction sequence @code{seq} is a good
 candidate as a replacement for the if-convertible sequence described in
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index 93bcd747e37..4d81a1729de 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -4744,6 +4744,8 @@ Define this macro if a non-short-circuit operation 
produced by
 
 @hook TARGET_MAX_NOCE_IFCVT_SEQ_COST
 
+@hook TARGET_PRUNE_INSERTIONS_DELETIONS
+
 @hook TARGET_NOCE_CONVERSION_PROFITABLE_P
 
 @hook TARGET_NEW_ADDRESS_PROFITABLE_P
diff --git a/gcc/gcse.cc b/gcc/gcse.cc
index 31b92f30fa1..12e252d826d 100644
--- a/gcc/gcse.cc
+++ b/gcc/gcse.cc
@@ -1893,6 +1893,9 @@ compute_pre_data (void)
 
   prune_insertions_deletions (expr_hash_table.n_elems);
 
+  targetm.prune_insertions_deletions (edge_list, expr_hash_table.n_elems,
+                                     pre_insert_map, pre_delete_map);
+
   return edge_list;
 }
 
diff --git a/gcc/target.def b/gcc/target.def
index 523ae7ec9aa..80f0f1ef53b 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -7056,6 +7056,14 @@ You need not define this hook if 
@code{WORD_REGISTER_OPERATIONS} is not\n\
 defined to 1.",
  unsigned int, (void), default_min_arithmetic_precision)
 
+/* Function to update PRE deletion and insertion bitmaps.  */
+DEFHOOK
+(prune_insertions_deletions,
+ "This hook gives the target a possibility to stop the code motion during\n\
+  GCSE pass for basic blocks which have a potential to be if-converted.",
+ void, (struct edge_list *edge_list, unsigned int n_elems, sbitmap 
*pre_insert_map, sbitmap *pre_delete_map),
+ default_prune_insertions_deletions)
+
 DEFHOOKPOD
 (atomic_test_and_set_trueval,
  "This value should be set if the result written by\n\
diff --git a/gcc/targhooks.cc b/gcc/targhooks.cc
index 304b35ed772..f1e0a157c9e 100644
--- a/gcc/targhooks.cc
+++ b/gcc/targhooks.cc
@@ -2843,4 +2843,13 @@ default_memtag_untagged_pointer (rtx tagged_pointer, rtx 
target)
   return untagged_base;
 }
 
+void
+default_prune_insertions_deletions (struct edge_list *
+                                   edge_list ATTRIBUTE_UNUSED,
+                                   unsigned int n_elems ATTRIBUTE_UNUSED,
+                                   sbitmap *pre_insert_map ATTRIBUTE_UNUSED,
+                                   sbitmap *pre_delete_map ATTRIBUTE_UNUSED)
+{
+}
+
 #include "gt-targhooks.h"
diff --git a/gcc/targhooks.h b/gcc/targhooks.h
index 2704d6008f1..2e3d05a1e92 100644
--- a/gcc/targhooks.h
+++ b/gcc/targhooks.h
@@ -309,4 +309,9 @@ extern rtx default_memtag_set_tag (rtx, rtx, rtx);
 extern rtx default_memtag_extract_tag (rtx, rtx);
 extern rtx default_memtag_untagged_pointer (rtx, rtx);
 
+extern void default_prune_insertions_deletions (struct edge_list *edge_list,
+                                               unsigned int n_elems,
+                                               sbitmap *pre_insert_map,
+                                               sbitmap *pre_delete_map);
+
 #endif /* GCC_TARGHOOKS_H */
-- 
2.34.1

Reply via email to