https://gcc.gnu.org/g:d7f4fc514a7f5d951e9738fb3c23a14cf49bfd8d

commit r17-3945-gd7f4fc514a7f5d951e9738fb3c23a14cf49bfd8d
Author: Kyrylo Tkachov <[email protected]>
Date:   Thu Jul 30 18:13:05 2026 +0200

    match-sat-alu.pd: Recognize borrow-test saturating subtraction
    
    For unsigned subtraction, the wrapped difference is greater than the minuend
    exactly when the subtraction borrows.  These forms are therefore saturating
    subtraction:
    
      R = X - Y
      R > X ? 0 : R
      R <= X ? R : 0
    
    Recognize both comparison operand orders and both result arm orders.
    
    AArch64 -O3, vector body:
    
    before:
    
            sub     v30.4s, v31.4s, v30.4s
            cmhs    v31.4s, v31.4s, v30.4s
            and     v31.16b, v31.16b, v30.16b
    
    after:
    
            uqsub   v30.4s, v31.4s, v30.4s
    
    Three vector operations become one.
    Remove four existing expected-failure markers for the supported forms.
    
    Bootstrapped and tested on aarch64-none-linux-gnu.
    
    gcc/ChangeLog:
    
            * match-sat-alu.pd (unsigned_integer_sat_sub): Add the four
            forms that compare the difference with the minuend.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.target/aarch64/sat_u_sub_borrow-1.c: New test.
            * gcc.target/aarch64/saturating_arithmetic_1.c: Remove the xfail
            on usub.
            * gcc.target/aarch64/sve/saturating_arithmetic_1.c: Remove the
            xfail on usubq.
            * gcc.target/aarch64/sve/saturating_arithmetic_3.c: Likewise.
            * gcc.target/aarch64/sve/saturating_arithmetic_4.c: Likewise.
    
    Signed-off-by: Kyrylo Tkachov <[email protected]>

Diff:
---
 gcc/match-sat-alu.pd                               |  9 +++++++++
 .../gcc.target/aarch64/sat_u_sub_borrow-1.c        | 22 ++++++++++++++++++++++
 .../gcc.target/aarch64/saturating_arithmetic_1.c   |  2 +-
 .../aarch64/sve/saturating_arithmetic_1.c          |  2 +-
 .../aarch64/sve/saturating_arithmetic_3.c          |  2 +-
 .../aarch64/sve/saturating_arithmetic_4.c          |  2 +-
 6 files changed, 35 insertions(+), 4 deletions(-)

diff --git a/gcc/match-sat-alu.pd b/gcc/match-sat-alu.pd
index 22855726d90a..bfba3f64d8e0 100644
--- a/gcc/match-sat-alu.pd
+++ b/gcc/match-sat-alu.pd
@@ -131,6 +131,15 @@ along with GCC; see the file COPYING3.  If not see
   /* SAT_U_SUB = (X - Y) * (X >= Y)  */
   (mult:c (minus @0 @1) (convert (ge @0 @1)))
   (if (types_match (type, @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.  */
+ (match (unsigned_integer_sat_sub @0 @1)
+  /* SAT_U_SUB = (X - Y) > X ? 0 : X - Y, and the commuted comparison.  */
+  (cond^ (gt:c (minus@2 @0 @1) @0) integer_zerop @2))
+ (match (unsigned_integer_sat_sub @0 @1)
+  /* SAT_U_SUB = (X - Y) <= X ? X - Y : 0, and the commuted comparison.  */
+  (cond^ (le:c (minus@2 @0 @1) @0) @2 integer_zerop))
  (match (unsigned_integer_sat_sub @0 @1)
   /* DIFF = SUB_OVERFLOW (X, Y)
      SAT_U_SUB = REALPART (DIFF) | (IMAGPART (DIFF) + (-1))  */
diff --git a/gcc/testsuite/gcc.target/aarch64/sat_u_sub_borrow-1.c 
b/gcc/testsuite/gcc.target/aarch64/sat_u_sub_borrow-1.c
new file mode 100644
index 000000000000..8b86cb929228
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sat_u_sub_borrow-1.c
@@ -0,0 +1,22 @@
+/* { 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 wrapped difference is larger than the minuend exactly when the
+   subtraction borrowed, so each of these is a saturating subtract.  */
+
+#define DEF(N, T)                                              \
+  T f1_##N (T a, T b) { T r = a - b; return r > a ? 0 : r; }   \
+  T f2_##N (T a, T b) { T r = a - b; if (r > a) r = 0; return r; } \
+  T f3_##N (T a, T b) { T r = a - b; return r <= a ? r : 0; }
+
+DEF (8, u8)
+DEF (16, u16)
+DEF (32, u32)
+DEF (64, u64)
+
+/* { dg-final { scan-tree-dump-times "\\.SAT_SUB " 12 "optimized" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/saturating_arithmetic_1.c 
b/gcc/testsuite/gcc.target/aarch64/saturating_arithmetic_1.c
index 8fc1569845b5..c73a024edec6 100644
--- a/gcc/testsuite/gcc.target/aarch64/saturating_arithmetic_1.c
+++ b/gcc/testsuite/gcc.target/aarch64/saturating_arithmetic_1.c
@@ -19,7 +19,7 @@
 **     ret
 */
 /*
-** usub: { xfail *-*-* }
+** usub:
 **     dup     v([0-9]+).8b, w[01]
 **     dup     v([0-9]+).8b, w[01]
 **     uqsub   b([0-9]+), b\1, b\2
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/saturating_arithmetic_1.c 
b/gcc/testsuite/gcc.target/aarch64/sve/saturating_arithmetic_1.c
index 6936e9a27044..4cfab740c408 100644
--- a/gcc/testsuite/gcc.target/aarch64/sve/saturating_arithmetic_1.c
+++ b/gcc/testsuite/gcc.target/aarch64/sve/saturating_arithmetic_1.c
@@ -39,7 +39,7 @@
 ** ...
 */
 /*
-** usubq: { xfail *-*-* }
+** usubq:
 ** ...
 **     ld1b\tz([0-9]+)\.b, .*
 **     ld1b\tz([0-9]+)\.b, .*
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/saturating_arithmetic_3.c 
b/gcc/testsuite/gcc.target/aarch64/sve/saturating_arithmetic_3.c
index 14e2de59b1ed..def7c82e2564 100644
--- a/gcc/testsuite/gcc.target/aarch64/sve/saturating_arithmetic_3.c
+++ b/gcc/testsuite/gcc.target/aarch64/sve/saturating_arithmetic_3.c
@@ -40,7 +40,7 @@
 ** ...
 */
 /*
-** usubq: { xfail *-*-* }
+** usubq:
 ** ...
 **     ld1w\tz([0-9]+)\.s, .*
 **     ld1w\tz([0-9]+)\.s, .*
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/saturating_arithmetic_4.c 
b/gcc/testsuite/gcc.target/aarch64/sve/saturating_arithmetic_4.c
index 05a5786b4abd..5b9f8740ed41 100644
--- a/gcc/testsuite/gcc.target/aarch64/sve/saturating_arithmetic_4.c
+++ b/gcc/testsuite/gcc.target/aarch64/sve/saturating_arithmetic_4.c
@@ -40,7 +40,7 @@
 ** ...
 */
 /*
-** usubq: { xfail *-*-* }
+** usubq:
 ** ...
 **     ld1d\tz([0-9]+)\.d, .*
 **     ld1d\tz([0-9]+)\.d, .*

Reply via email to