[55/61] Performance drop in mips-img-linux-gnu-gcc 7.x
Checks
Commit Message
From: Mihailo Stojanovic <mistojanovic@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 <mistojanovic@wavecomp.com>
Signed-off-by: Faraz Shahbazker <fshahbazker@wavecomp.com>
Signed-off-by: Aleksandar Rakic <aleksandar.rakic@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(+)
Comments
On Fri, Jan 31, 2025 at 7:10 PM Aleksandar Rakic
<aleksandar.rakic@htecgroup.com> wrote:
>
> From: Mihailo Stojanovic <mistojanovic@wavecomp.com>
This looks like a target specific hack, this should be addressed generally
instead of opening up gcse internals to a target hook.
This should also at least come with a testcase.
> 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 <mistojanovic@wavecomp.com>
> Signed-off-by: Faraz Shahbazker <fshahbazker@wavecomp.com>
> Signed-off-by: Aleksandar Rakic <aleksandar.rakic@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
@@ -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"
@@ -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.
@@ -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
@@ -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
@@ -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;
}
@@ -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\
@@ -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"
@@ -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 */