Re: [PATCH] aarch64: Add missing CC clobber to max/min-of-add/sub patterns [PR116815]
Andrea Pinski <[email protected]> Tue, 4 Aug 2026 17:10:29 -0700
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <CALvbMcAGxdtWECwc-CekSOeQDnNnXSDkt+LAAby3J34tz1pAHg@mail.gmail.com> |
On Tue, Aug 4, 2026 at 1:30=E2=80=AFAM <[email protected]> wrote: > > From: Kyrylo Tkachov <[email protected]> > > *aarch64_plus_within_<optab><mode>3_<ovf_commutate> and > *aarch64_minus_within_<optab><mode>3 split into a flag-setting ADDS or SU= BS > followed by a CSEL, but their insn patterns do not say that they write th= e > condition codes. > > For > > unsigned f (unsigned a, unsigned b, unsigned c, unsigned d) > { > unsigned s =3D a + b; > unsigned m =3D s > a ? s : a; > return (c < d && a < b) ? m : d; > } > > combine produces > > (parallel [(set (reg:SI 0 x0) > (umax:SI (plus:SI (reg:SI 107) (reg:SI 108)) > (reg:SI 107))) > (clobber (scratch:SI))]) > > which claims to leave the flags alone. The compare feeding the enclosing > CCMP chain is therefore treated as still live and is removed, and split1 > then emits an ADDS that overwrites the flags the outer CSEL reads: > > adds w1, w0, w1 > csel w1, w1, w0, cc > csel w0, w1, w3, cc > > so f (5, 7, 9, 2) returns 12 rather than 2. > > Add the (clobber (reg:CC CC_REGNUM)) that the neighbouring > *aarch64_minmax_plus pattern already carries. The comparison is then kep= t: > > cmp w2, w3 > ccmp w0, w1, 2, cc > bcs .L2 > adds w1, w0, w1 > csel w3, w1, w0, cc > > Bootstrapped and tested on aarch64-none-linux-gnu. > Pushing to trunk and later to the affected branches. > > gcc/ChangeLog: > > PR middle-end/116815 > * config/aarch64/aarch64.md > (*aarch64_plus_within_<optab><mode>3_<ovf_commutate>): Add a > clobber of CC_REGNUM. > (*aarch64_minus_within_<optab><mode>3): Likewise. Ok > > gcc/testsuite/ChangeLog: > > PR middle-end/116815 > * gcc.target/aarch64/pr116815-4.c: New test. > > Signed-off-by: Kyrylo Tkachov <[email protected]> > --- > gcc/config/aarch64/aarch64.md | 6 +- > gcc/testsuite/gcc.target/aarch64/pr116815-4.c | 94 +++++++++++++++++++ > 2 files changed, 98 insertions(+), 2 deletions(-) > create mode 100644 gcc/testsuite/gcc.target/aarch64/pr116815-4.c > > diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.m= d > index b2185c63819..59af2bd2088 100644 > --- a/gcc/config/aarch64/aarch64.md > +++ b/gcc/config/aarch64/aarch64.md > @@ -4554,7 +4554,8 @@ > (plus:GPI (match_operand:GPI 1 "register_operand" "r") > (match_operand:GPI 2 "register_operand" "r")) > (match_dup ovf_commutate))) > - (clobber (match_scratch:GPI 3 "=3Dr"))] > + (clobber (match_scratch:GPI 3 "=3Dr")) > + (clobber (reg:CC CC_REGNUM))] > "!TARGET_CSSC" > "#" > "&& 1" > @@ -4584,7 +4585,8 @@ > (minus:GPI (match_operand:GPI 1 "register_operand" "r") > (match_operand:GPI 2 "register_operand" "r")) > (match_dup 1))) > - (clobber (match_scratch:GPI 3 "=3Dr"))] > + (clobber (match_scratch:GPI 3 "=3Dr")) > + (clobber (reg:CC CC_REGNUM))] > "!TARGET_CSSC" > "#" > "&& 1" > diff --git a/gcc/testsuite/gcc.target/aarch64/pr116815-4.c b/gcc/testsuit= e/gcc.target/aarch64/pr116815-4.c > new file mode 100644 > index 00000000000..6c640f58542 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/aarch64/pr116815-4.c > @@ -0,0 +1,94 @@ > +/* { dg-do run } */ > +/* { dg-options "-O2" } */ > + > +/* PR middle-end/116815 */ > + > +/* The max/min-of-add/sub patterns split into a flag-setting ADDS/SUBS > + followed by a CSEL, so they have to declare that they clobber the > + condition codes. Without that clobber the compare feeding an enclosi= ng > + CCMP chain is treated as still live across the insn and gets deleted, > + so the wrong value is selected. */ > + > +#pragma GCC target "+nocssc" > + > +__attribute__ ((noipa)) unsigned > +umax_plus (unsigned a, unsigned b, unsigned c, unsigned d) > +{ > + unsigned s =3D a + b; > + unsigned m =3D s > a ? s : a; > + return (c < d && a < b) ? m : d; > +} > + > +__attribute__ ((noipa)) unsigned > +umin_plus (unsigned a, unsigned b, unsigned c, unsigned d) > +{ > + unsigned s =3D a + b; > + unsigned m =3D s < a ? s : a; > + return (c < d && a < b) ? m : d; > +} > + > +__attribute__ ((noipa)) unsigned > +umax_minus (unsigned a, unsigned b, unsigned c, unsigned d) > +{ > + unsigned s =3D a - b; > + unsigned m =3D s > a ? s : a; > + return (c < d && a < b) ? m : d; > +} > + > +__attribute__ ((noipa)) unsigned > +umin_minus (unsigned a, unsigned b, unsigned c, unsigned d) > +{ > + unsigned s =3D a - b; > + unsigned m =3D s < a ? s : a; > + return (c < d && a < b) ? m : d; > +} > + > +__attribute__ ((noipa)) unsigned long long > +umax_plus_di (unsigned long long a, unsigned long long b, > + unsigned long long c, unsigned long long d) > +{ > + unsigned long long s =3D a + b; > + unsigned long long m =3D s > a ? s : a; > + return (c < d && a < b) ? m : d; > +} > + > +__attribute__ ((noipa)) unsigned long long > +umin_minus_di (unsigned long long a, unsigned long long b, > + unsigned long long c, unsigned long long d) > +{ > + unsigned long long s =3D a - b; > + unsigned long long m =3D s < a ? s : a; > + return (c < d && a < b) ? m : d; > +} > + > +int > +main (void) > +{ > + /* c < d is false, so every call must return d. */ > + if (umax_plus (5, 7, 9, 2) !=3D 2) > + __builtin_abort (); > + if (umin_plus (5, 7, 9, 2) !=3D 2) > + __builtin_abort (); > + if (umax_minus (5, 7, 9, 2) !=3D 2) > + __builtin_abort (); > + if (umin_minus (5, 7, 9, 2) !=3D 2) > + __builtin_abort (); > + if (umax_plus_di (5, 7, 9, 2) !=3D 2) > + __builtin_abort (); > + if (umin_minus_di (5, 7, 9, 2) !=3D 2) > + __builtin_abort (); > + > + /* a < b is false, so these must return d too. */ > + if (umax_plus (7, 5, 1, 2) !=3D 2) > + __builtin_abort (); > + if (umax_minus (7, 5, 1, 2) !=3D 2) > + __builtin_abort (); > + > + /* Both true: the max/min result is selected. */ > + if (umax_plus (5, 7, 1, 2) !=3D 12) > + __builtin_abort (); > + if (umin_plus (5, 7, 1, 2) !=3D 5) > + __builtin_abort (); > + > + return 0; > +} > -- > 2.50.1 (Apple Git-155) >