Hi! 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. Bootstrapped/regtested on s390x-linux, also tested on the veusz package which now passes its testsuite (and didn't before). Ok for trunk/16 and perhaps even older release branches (where it is just latent)? 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. --- gcc/config/s390/s390.md.jj 2026-06-02 08:15:04.576141861 +0200 +++ gcc/config/s390/s390.md 2026-06-26 01:23:35.038623318 +0200 @@ -10256,6 +10256,7 @@ (define_insn_and_split "*brx_stage1_<GPR (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 ""))] "" "#" --- gcc/testsuite/gcc.target/s390/pr125992.c.jj 2026-06-26 08:58:11.720734276 +0200 +++ gcc/testsuite/gcc.target/s390/pr125992.c 2026-06-26 08:57:45.265070843 +0200 @@ -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 (); +} Jakub
