find_cond_trap emits the sequence from gen_cond_trap before cond_earliest.
On SPARC that sequence is a comparison followed by a trap on the condition
codes, but the branch it replaces need not read them: a cbcond tests
general registers, so a condition code set earlier can be live across
TEST_BB and read by a later branch, which then tests the wrong value.
The fix for PR126501 added noce_clobbers_live_cc_p for the same problem in
the noce paths. Use it here too.
On sparc64 with -mcbcond this miscompiles a switch over a sparse enum whose
default arm is unreachable, which is why LLVM 23 does not build there.
Bootstrapped on sparc64-unknown-linux-gnu. The C and C++ testsuites,
run against an otherwise identical unpatched tree, change only in the
new test, which fails without the patch and passes with it.
gcc/ChangeLog:
PR rtl-optimization/127578
* doc/sourcebuild.texi (cbcond_hw): Document.
* ifcvt.cc (find_cond_trap): Reject a sequence that clobbers a
condition-code register live out of TEST_BB.
gcc/testsuite/ChangeLog:
PR rtl-optimization/127578
* lib/target-supports.exp (check_effective_target_cbcond_hw): New.
* gcc.target/sparc/cbcond-trap-1.c: New test.
---
Changes since v2: document cbcond_hw in doc/sourcebuild.texi.
Changes since v1: reuse noce_clobbers_live_cc_p, the check that
end_ifcvt_sequence already makes, instead of adding a new liveness check.
gcc/doc/sourcebuild.texi | 4 +++
gcc/ifcvt.cc | 3 ++
.../gcc.target/sparc/cbcond-trap-1.c | 34 +++++++++++++++++++
gcc/testsuite/lib/target-supports.exp | 9 +++++
4 files changed, 50 insertions(+)
create mode 100644 gcc/testsuite/gcc.target/sparc/cbcond-trap-1.c
diff --git a/gcc/doc/sourcebuild.texi b/gcc/doc/sourcebuild.texi
index b02cb28..3aa9fcb 100644
--- a/gcc/doc/sourcebuild.texi
+++ b/gcc/doc/sourcebuild.texi
@@ -2758,6 +2758,10 @@ Target supports the execution of @code{avxvnniint16}
instructions.
Target runtime permits dereferencing a null pointer without trapping, for
example because address zero is mapped and readable.
+@item cbcond_hw
+Test system can execute SPARC compare-and-branch (@code{cbcond})
+instructions.
+
@item cell_hw
Test system can execute AltiVec and Cell PPU instructions.
diff --git a/gcc/ifcvt.cc b/gcc/ifcvt.cc
index 618c297..ab9d356 100644
--- a/gcc/ifcvt.cc
+++ b/gcc/ifcvt.cc
@@ -6114,6 +6114,9 @@ find_cond_trap (basic_block test_bb, edge then_edge, edge
else_edge)
: recog_memoized (x) < 0)
return false;
+ if (noce_clobbers_live_cc_p (test_bb, seq))
+ return false;
+
/* Emit the new insns before cond_earliest. */
emit_insn_before_setloc (seq, cond_earliest, INSN_LOCATION (trap));
diff --git a/gcc/testsuite/gcc.target/sparc/cbcond-trap-1.c
b/gcc/testsuite/gcc.target/sparc/cbcond-trap-1.c
new file mode 100644
index 0000000..8fc3ddc
--- /dev/null
+++ b/gcc/testsuite/gcc.target/sparc/cbcond-trap-1.c
@@ -0,0 +1,34 @@
+/* { dg-do run { target cbcond_hw } } */
+/* { dg-options "-O2 -mcpu=niagara4" } */
+
+/* find_cond_trap used to emit the comparison of the conditional trap on top
+ of a %icc value that was still live, because a cbcond jump does not read
+ the CC. */
+
+struct S { unsigned short bt; unsigned char kind; unsigned bw; };
+
+__attribute__((noinline)) void f (struct S *s)
+{
+ switch (s->bt)
+ {
+ case 1: s->bw = 8; s->kind = 1; break;
+ case 2: s->bw = 16; s->kind = 1; break;
+ case 4: s->bw = 32; s->kind = 1; break;
+ case 8: s->bw = 64; s->kind = 1; break;
+ case 16: s->bw = 16; s->kind = 2; break;
+ case 32: s->bw = 16; s->kind = 3; break;
+ case 64: s->bw = 32; s->kind = 3; break;
+ case 128: s->bw = 64; s->kind = 3; break;
+ case 256: s->bw = 8; s->kind = 4; break;
+ case 512: s->bw = 8; s->kind = 5; break;
+ default: __builtin_trap ();
+ }
+}
+
+int
+main (void)
+{
+ struct S s = { 1, 0, 0 };
+ f (&s);
+ return s.bw == 8 ? 0 : 1;
+}
diff --git a/gcc/testsuite/lib/target-supports.exp
b/gcc/testsuite/lib/target-supports.exp
index 5eb44cb..ae04b6a 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -8564,6 +8564,15 @@ proc check_effective_target_ultrasparc_vis3_hw { } {
} "-mcpu=niagara3"]
}
+# Return 1 if the test environment supports executing SPARC compare-and-branch
+# instructions. We check this by attempting: "cwbe %g0, %g0, .+4"
+
+proc check_effective_target_cbcond_hw { } {
+ return [check_runtime cbcond_hw {
+ int main() { __asm__(".word 0x12c00020"); return 0; }
+ } "-mcpu=niagara4"]
+}
+
# Return 1 if this is a SPARC-V9 target.
proc check_effective_target_sparc_v9 { } {
--
2.43.0