https://gcc.gnu.org/g:9f3f376a5c6baa7e3d627d6e98e538622e6d53dd
commit r14-12711-g9f3f376a5c6baa7e3d627d6e98e538622e6d53dd Author: Jakub Jelinek <[email protected]> Date: Sat Jun 27 21:33:00 2026 +0200 s390: Fix up *brx_stage1_<GPR:mode> [PR125992] The following testcase is miscompiled since r16-3301 but the problem is much older. The *brx_stage1_<GPR:mode> define_insn_and_split pattern doesn't describe that it clobbers CC_REGNUM, but splits (before reload) into something which does clobber CC_REGNUM unconditionally. Since r16-3301 on this testcase the late_combine1 pass figures it can extend the lifetime of CC_REGNUM across such an instruction, but when it is in split1 pass split into something that does clobber CC_REGNUM, the value from earlier comparison till later use is not preserved anymore. The following patch fixes it by adding clobber for CC_REGNUM even to the *brx_stage1_<GPR:mode> pattern, so that df/late_combine etc. know that it is CC_REGNUM is clobbered by it. I had to put the clobber before the match_scratch clobber, otherwise there is endless loop trying to split this insn in split1 pass, the insn it is split into matches the pattern again and is split again etc. forever. Even with this patch combine can match this insn, we have code to add the missing clobbers if the register isn't live across it. 2026-06-27 Jakub Jelinek <[email protected]> PR target/125992 * config/s390/s390.md (*brx_stage1_<GPR:mode>): Add CC_REGNUM clobber. * gcc.target/s390/pr125992.c: New test. Reviewed-by: Stefan Schulze Frielinghaus <[email protected]> (cherry picked from commit 13529401b15fe82c0b1d44b0b0a8bf5d2d72a1b3) Diff: --- gcc/config/s390/s390.md | 1 + gcc/testsuite/gcc.target/s390/pr125992.c | 41 ++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/gcc/config/s390/s390.md b/gcc/config/s390/s390.md index c364880af0ae..2e24836d40a9 100644 --- a/gcc/config/s390/s390.md +++ b/gcc/config/s390/s390.md @@ -9678,6 +9678,7 @@ (pc))) (set (match_operand:GPR 4 "nonimmediate_operand" "") (plus:GPR (match_dup 1) (match_dup 2))) + (clobber (reg:CC CC_REGNUM)) (clobber (match_scratch:GPR 5 ""))] "" "#" diff --git a/gcc/testsuite/gcc.target/s390/pr125992.c b/gcc/testsuite/gcc.target/s390/pr125992.c new file mode 100644 index 000000000000..a7d4b799ebee --- /dev/null +++ b/gcc/testsuite/gcc.target/s390/pr125992.c @@ -0,0 +1,41 @@ +/* PR target/125992 */ +/* { dg-do run { target s390_useable_hw } } */ +/* { dg-options "-O2 -march=z13" } */ + +long a, b, c, d[4]; + +[[gnu::noipa]] long +foo () +{ + return d[c++]; +} + +[[gnu::noipa]] void +bar () +{ + long e = 0; + for (;;) + { + e += a; + a = foo (); + if (b + a > e) + return; + if (a == 0) + break; + if (a > 0) + b += a; + } +} + +int +main () +{ + a = 16; + b = -64; + c = 0; + d[0] = 64; + d[1] = 128; + bar (); + if (b != 0) + __builtin_abort (); +}
