Consider the following RTL: (code_label 11 10 26 4 2 (nil) [1 uses]) (note 26 11 12 4 [bb 4] NOTE_INSN_BASIC_BLOCK) (insn 12 26 15 4 (set (reg:SI 65) (if_then_else:SI (eq (reg:CCZ 33 %cc) (const_int 0 [0])) (const_int 1 [0x1]) (const_int 0 [0]))) "pr80080-4.c":9 1674 {*movsicc}) (insn 15 12 16 4 (parallel [ (set (reg:CCZ 33 %cc) (compare:CCZ (reg:SI 65) (const_int 0 [0]))) (clobber (scratch:SI)) ]) "pr80080-4.c":9 1216 {*tstsi_cconly_extimm}) (jump_insn 16 15 17 4 (set (pc) (if_then_else (ne (reg:CCZ 33 %cc) (const_int 0 [0])) (label_ref:DI 23) (pc))) "pr80080-4.c":9 1897 {*cjump_64})
Combine simplifies this into: (code_label 11 10 26 4 2 (nil) [1 uses]) (note 26 11 12 4 [bb 4] NOTE_INSN_BASIC_BLOCK) (note 12 26 15 4 NOTE_INSN_DELETED) (note 15 12 16 4 NOTE_INSN_DELETED) (jump_insn 16 15 17 4 (set (pc) (if_then_else (eq (reg:CCZ 33 %cc) (const_int 0 [0])) (label_ref:DI 23) (pc))) "pr80080-4.c":9 1897 {*cjump_64}) opening up the possibility to perform jump threading. Since this happens infrequently, perform jump threading only when there is a changed basic block, whose sole side effect is a trailing jump. Also remove redundant usage of TV_JUMP, because rebuild_jump_labels () and cleanup_cfg () already have their own timevars. gcc/ChangeLog: 2018-09-05 Ilya Leoshkevich <i...@linux.ibm.com> PR target/80080 * combine.c (is_single_jump_bb): New function. (struct combine_summary): New struct. (combine_instructions): Instead of returning new_direct_jump_p, fill struct combine_summary. In addition to the existing new_direct_jump_p, it contains a new new_single_jump_p field, which controls whether or not jump threading should be performed after combine. (rest_of_handle_combine): Perform jump threading if there is a possibility that it would be profitable. Remove redundant usage of TV_JUMP. gcc/testsuite/ChangeLog: 2018-09-05 Ilya Leoshkevich <i...@linux.ibm.com> PR target/80080 * gcc.target/s390/pr80080-4.c: New test. --- gcc/combine.c | 89 +++++++++++++++++++---- gcc/testsuite/gcc.target/s390/pr80080-4.c | 16 ++++ 2 files changed, 89 insertions(+), 16 deletions(-) create mode 100644 gcc/testsuite/gcc.target/s390/pr80080-4.c diff --git a/gcc/combine.c b/gcc/combine.c index a2649b6d5a1..65f5d7d092b 100644 --- a/gcc/combine.c +++ b/gcc/combine.c @@ -1139,13 +1139,42 @@ insn_a_feeds_b (rtx_insn *a, rtx_insn *b) return false; } +/* Return true iff the only side effect of BB is its trailing jump_insn. */ + +static bool +is_single_jump_bb (basic_block bb) +{ + rtx_insn *end = BB_END (bb); + rtx_insn *insn; + + if (!JUMP_P (end)) + return false; + + for (insn = BB_HEAD (bb); insn != end; insn = NEXT_INSN (insn)) + if (INSN_P (insn) && side_effects_p (PATTERN (insn))) + return false; + return true; +} + +/* Summary of changes performed by the combiner. */ +struct combine_summary { + /* True if the combiner has turned an indirect jump instruction into a direct + jump. */ + bool new_direct_jump_p; + + /* True if the combiner changed at least one basic block in a way that it + ended up containing a single jump_insn. */ + bool new_single_jump_p; +}; + /* Main entry point for combiner. F is the first insn of the function. NREGS is the first unused pseudo-reg number. - Return nonzero if the combiner has turned an indirect jump - instruction into a direct jump. */ -static int -combine_instructions (rtx_insn *f, unsigned int nregs) + If performed changes satisfy certain criteria, set the corresponding fields + of SUMMARY to true. */ +static void +combine_instructions (rtx_insn *f, unsigned int nregs, + struct combine_summary *summary) { rtx_insn *insn, *next; rtx_insn *prev; @@ -1158,7 +1187,7 @@ combine_instructions (rtx_insn *f, unsigned int nregs) for (first = f; first && !NONDEBUG_INSN_P (first); ) first = NEXT_INSN (first); if (!first) - return 0; + return; combine_attempts = 0; combine_merges = 0; @@ -1251,6 +1280,7 @@ combine_instructions (rtx_insn *f, unsigned int nregs) FOR_EACH_BB_FN (this_basic_block, cfun) { rtx_insn *last_combined_insn = NULL; + bool bb_changed = false; /* Ignore instruction combination in basic blocks that are going to be removed as unreachable anyway. See PR82386. */ @@ -1302,6 +1332,7 @@ combine_instructions (rtx_insn *f, unsigned int nregs) last_combined_insn)) != 0) { statistics_counter_event (cfun, "two-insn combine", 1); + bb_changed = true; goto retry; } @@ -1323,6 +1354,7 @@ combine_instructions (rtx_insn *f, unsigned int nregs) last_combined_insn)) != 0) { statistics_counter_event (cfun, "three-insn combine", 1); + bb_changed = true; goto retry; } } @@ -1349,7 +1381,10 @@ combine_instructions (rtx_insn *f, unsigned int nregs) if ((next = try_combine (insn, prev, nextlinks->insn, NULL, &new_direct_jump_p, last_combined_insn)) != 0) - goto retry; + { + bb_changed = true; + goto retry; + } } /* Do the same for an insn that explicitly references CC0. */ @@ -1363,13 +1398,19 @@ combine_instructions (rtx_insn *f, unsigned int nregs) if ((next = try_combine (insn, prev, NULL, NULL, &new_direct_jump_p, last_combined_insn)) != 0) - goto retry; + { + bb_changed = true; + goto retry; + } FOR_EACH_LOG_LINK (nextlinks, prev) if ((next = try_combine (insn, prev, nextlinks->insn, NULL, &new_direct_jump_p, last_combined_insn)) != 0) + { + bb_changed = true; goto retry; + } } /* Finally, see if any of the insns that this insn links to @@ -1387,7 +1428,10 @@ combine_instructions (rtx_insn *f, unsigned int nregs) && (next = try_combine (insn, links->insn, prev, NULL, &new_direct_jump_p, last_combined_insn)) != 0) - goto retry; + { + bb_changed = true; + goto retry; + } } /* Try combining an insn with two different insns whose results it @@ -1403,6 +1447,7 @@ combine_instructions (rtx_insn *f, unsigned int nregs) { statistics_counter_event (cfun, "three-insn combine", 1); + bb_changed = true; goto retry; } @@ -1431,6 +1476,7 @@ combine_instructions (rtx_insn *f, unsigned int nregs) last_combined_insn)) != 0) { statistics_counter_event (cfun, "four-insn combine", 1); + bb_changed = true; goto retry; } /* I0, I1 -> I2, I2 -> I3. */ @@ -1442,6 +1488,7 @@ combine_instructions (rtx_insn *f, unsigned int nregs) last_combined_insn)) != 0) { statistics_counter_event (cfun, "four-insn combine", 1); + bb_changed = true; goto retry; } } @@ -1459,6 +1506,7 @@ combine_instructions (rtx_insn *f, unsigned int nregs) last_combined_insn)) != 0) { statistics_counter_event (cfun, "four-insn combine", 1); + bb_changed = true; goto retry; } /* I0 -> I1; I1, I2 -> I3. */ @@ -1469,6 +1517,7 @@ combine_instructions (rtx_insn *f, unsigned int nregs) last_combined_insn)) != 0) { statistics_counter_event (cfun, "four-insn combine", 1); + bb_changed = true; goto retry; } } @@ -1510,6 +1559,7 @@ combine_instructions (rtx_insn *f, unsigned int nregs) if (next) { statistics_counter_event (cfun, "insn-with-note combine", 1); + bb_changed = true; goto retry; } SET_SRC (set) = orig_src; @@ -1523,6 +1573,10 @@ combine_instructions (rtx_insn *f, unsigned int nregs) retry: ; } + + if (flag_thread_jumps) + summary->new_single_jump_p + |= bb_changed && is_single_jump_bb (this_basic_block); } default_rtl_profile (); @@ -1557,7 +1611,7 @@ retry: /* Make recognizer allow volatile MEMs again. */ init_recog (); - return new_direct_jump_p; + summary->new_direct_jump_p = new_direct_jump_p; } /* Wipe the last_xxx fields of reg_stat in preparation for another pass. */ @@ -14939,7 +14993,7 @@ dump_combine_total_stats (FILE *file) static unsigned int rest_of_handle_combine (void) { - int rebuild_jump_labels_after_combine; + struct combine_summary summary; df_set_flags (DF_LR_RUN_DCE + DF_DEFER_INSN_RESCAN); df_note_add_problem (); @@ -14948,22 +15002,25 @@ rest_of_handle_combine (void) regstat_init_n_sets_and_refs (); reg_n_sets_max = max_reg_num (); - rebuild_jump_labels_after_combine - = combine_instructions (get_insns (), max_reg_num ()); + memset (&summary, 0, sizeof (summary)); + combine_instructions (get_insns (), max_reg_num (), &summary); /* Combining insns may have turned an indirect jump into a direct jump. Rebuild the JUMP_LABEL fields of jumping instructions. */ - if (rebuild_jump_labels_after_combine) + if (summary.new_direct_jump_p) { if (dom_info_available_p (CDI_DOMINATORS)) free_dominance_info (CDI_DOMINATORS); - timevar_push (TV_JUMP); rebuild_jump_labels (get_insns ()); - cleanup_cfg (0); - timevar_pop (TV_JUMP); } + /* Combining insns can change basic blocks in a way that they end up + containing a single jump_insn. This creates an opportunity to improve + code with jump threading. */ + if (summary.new_direct_jump_p || summary.new_single_jump_p) + cleanup_cfg (summary.new_single_jump_p ? CLEANUP_THREADING : 0); + regstat_free_n_sets_and_refs (); return 0; } diff --git a/gcc/testsuite/gcc.target/s390/pr80080-4.c b/gcc/testsuite/gcc.target/s390/pr80080-4.c new file mode 100644 index 00000000000..91d31ec7845 --- /dev/null +++ b/gcc/testsuite/gcc.target/s390/pr80080-4.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-march=z196 -O2" } */ + +extern void bar(int *mem); + +void foo4(int *mem) +{ + int oldval = 0; + if (!__atomic_compare_exchange_n (mem, (void *) &oldval, 1, + 1, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) + { + bar (mem); + } +} + +/* { dg-final { scan-assembler "\n\tlt\t.*\n\tjne\t(\\.L\\d+)\n(.*\n)*\tcs\t.*\n\tber\t%r14\n\\1:\n\tjg\tbar\n" } } */ -- 2.18.0