On Fri, Jan 31, 2025 at 7:10 PM Aleksandar Rakic <aleksandar.ra...@htecgroup.com> wrote: > > From: Mihailo Stojanovic <mistojano...@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 <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