On Fri, Sep 11, 2026 at 6:09 AM <[email protected]> wrote: > > From: Kyrylo Tkachov <[email protected]> > > Equivalent unsigned saturating subtraction forms can reverse the comparison > operands or the conditional arms: > > B < A ? A - B : 0 > A < B ? 0 : A - B > > The middle end can keep either comparison operand order. Control flow with > two returns can also reverse the conditional arms. > > Recognize both forms and reversed comparisons in the multiply-by-predicate > form. > > AArch64 -O2: > > before: > > sub w2, w0, w1 > cmp w1, w0 > csel w0, w2, wzr, cc > > after: > > subs w0, w0, w1 > csel w0, w0, wzr, cs > > The vector form replaces a comparison, a subtraction, and an AND with one > UQSUB. > > Bootstrapped and tested on aarch64-none-linux-gnu. > > Ok for trunk?
Ok. > > Changes since v2: > - Rebase on current trunk. > > gcc/ChangeLog: > > * match-sat-alu.pd (unsigned_integer_sat_sub): Accept commuted > comparison operand orders and the arm order from a two-return source. > > gcc/testsuite/ChangeLog: > > * gcc.target/aarch64/sat_u_sub_swapped-1.c: New test. > > Signed-off-by: Kyrylo Tkachov <[email protected]> > --- > gcc/match-sat-alu.pd | 25 +++++++++++------ > .../gcc.target/aarch64/sat_u_sub_swapped-1.c | 27 +++++++++++++++++++ > 2 files changed, 44 insertions(+), 8 deletions(-) > create mode 100644 gcc/testsuite/gcc.target/aarch64/sat_u_sub_swapped-1.c > > diff --git a/gcc/match-sat-alu.pd b/gcc/match-sat-alu.pd > index 03bba82e4a6..2f6b842d86e 100644 > --- a/gcc/match-sat-alu.pd > +++ b/gcc/match-sat-alu.pd > @@ -144,22 +144,31 @@ along with GCC; see the file COPYING3. If not see > /* Saturation sub for unsigned integer. */ > (if (INTEGRAL_TYPE_P (type) && TYPE_UNSIGNED (type)) > (match (unsigned_integer_sat_sub @0 @1) > - /* SAT_U_SUB = X > Y ? X - Y : 0 */ > - (cond^ (gt @0 @1) (minus @0 @1) integer_zerop) > + /* SAT_U_SUB = X > Y ? X - Y : 0, and the commuted comparison. */ > + (cond^ (gt:c @0 @1) (minus @0 @1) integer_zerop) > (if (types_match (type, @0, @1)))) > (match (unsigned_integer_sat_sub @0 @1) > - /* SAT_U_SUB = X >= Y ? X - Y : 0 */ > - (cond^ (ge @0 @1) (convert? (minus (convert1? @0) (convert1? @1))) > + /* SAT_U_SUB = X >= Y ? X - Y : 0, and the commuted comparison. */ > + (cond^ (ge:c @0 @1) (convert? (minus (convert1? @0) (convert1? @1))) > integer_zerop) > (if (TYPE_UNSIGNED (TREE_TYPE (@0)) && types_match (@0, @1)))) > (match (unsigned_integer_sat_sub @0 @1) > - /* SAT_U_SUB = (X - Y) * (X > Y) */ > - (mult:c (minus @0 @1) (convert (gt @0 @1))) > + /* SAT_U_SUB = (X - Y) * (X > Y), and the commuted comparison. */ > + (mult:c (minus @0 @1) (convert (gt:c @0 @1))) > (if (types_match (type, @0, @1)))) > (match (unsigned_integer_sat_sub @0 @1) > - /* SAT_U_SUB = (X - Y) * (X >= Y) */ > - (mult:c (minus @0 @1) (convert (ge @0 @1))) > + /* SAT_U_SUB = (X - Y) * (X >= Y), and the commuted comparison. */ > + (mult:c (minus @0 @1) (convert (ge:c @0 @1))) > (if (types_match (type, @0, @1)))) > + /* A source with two returns can keep zero on the taken arm. Accept a > + commuted comparison in this form too. */ > + (match (unsigned_integer_sat_sub @0 @1) > + (cond^ (lt:c @0 @1) integer_zerop (minus @0 @1)) > + (if (types_match (type, @0, @1)))) > + (match (unsigned_integer_sat_sub @0 @1) > + (cond^ (le:c @0 @1) integer_zerop > + (convert? (minus (convert1? @0) (convert1? @1)))) > + (if (TYPE_UNSIGNED (TREE_TYPE (@0)) && types_match (@0, @1)))) > /* The wrapped difference exceeds the minuend exactly when the subtraction > borrows, so a source that names the difference and then tests it against > the minuend is a saturating subtract. */ > diff --git a/gcc/testsuite/gcc.target/aarch64/sat_u_sub_swapped-1.c > b/gcc/testsuite/gcc.target/aarch64/sat_u_sub_swapped-1.c > new file mode 100644 > index 00000000000..fb42b6b07e3 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/aarch64/sat_u_sub_swapped-1.c > @@ -0,0 +1,27 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O2 -fdump-tree-optimized" } */ > + > +typedef unsigned char u8; > +typedef unsigned short u16; > +typedef unsigned int u32; > +typedef unsigned long long u64; > + > +/* The same saturating subtract with the subtrahend written on the left of > + the comparison. GIMPLE orders comparison operands by SSA version, so > + which spelling survives does not follow the source. */ > + > +#define DEF(N, T) \ > + T f1_##N (T a, T b) { return b < a ? a - b : 0; } \ > + T f2_##N (T a, T b) { return b <= a ? a - b : 0; } \ > + T f3_##N (T a, T b) { return (T) ((a - b) * (T) (b < a)); } \ > + T f4_##N (T a, T b) { return (T) ((a - b) * (T) (b <= a)); } \ > + T f5_##N (T a, T b) { if (b >= a) return 0; return a - b; } \ > + T f6_##N (T a, T b) { return b >= a ? 0 : a - b; } \ > + T f7_##N (T a, T b) { if (a < b) return 0; return a - b; } > + > +DEF (8, u8) > +DEF (16, u16) > +DEF (32, u32) > +DEF (64, u64) > + > +/* { dg-final { scan-tree-dump-times "\\.SAT_SUB " 28 "optimized" } } */ > -- > 2.50.1 (Apple Git-155) >
