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 <[email protected]>
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 <[email protected]>
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