https://gcc.gnu.org/g:3f6fb81133dfa2b8f843b328fd6b697534e7b3fe
commit r17-4706-g3f6fb81133dfa2b8f843b328fd6b697534e7b3fe Author: Stian Halseth <[email protected]> Date: Sun Sep 27 21:51:28 2026 -0600 [PATCH v3] ifcvt: Do not clobber a live condition-code register in find_cond_trap [PR127578] 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. --- 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. PR rtl-optimization/127578 gcc/ChangeLog: * 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: * lib/target-supports.exp (check_effective_target_cbcond_hw): New. * gcc.target/sparc/cbcond-trap-1.c: New test. Diff: --- gcc/doc/sourcebuild.texi | 4 +++ gcc/ifcvt.cc | 3 +++ gcc/testsuite/gcc.target/sparc/cbcond-trap-1.c | 34 ++++++++++++++++++++++++++ gcc/testsuite/lib/target-supports.exp | 9 +++++++ 4 files changed, 50 insertions(+) diff --git a/gcc/doc/sourcebuild.texi b/gcc/doc/sourcebuild.texi index b02cb28db512..3aa9fcbb5778 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 618c2976c5d7..ab9d35699cba 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 000000000000..8fc3ddcc8e3e --- /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 5eb44cb3ee42..ae04b6a8daa1 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 { } {
