From: Pan Li <[email protected]>

Given there are lots of sat alu patterns in match.pd, and
there will more in short future.  Move all of them into
a separated file for better org.

The below test suites are passed for this patch:
1. The rv64gcv fully regression tests.
2. The x86 bootstrap tests.
3. The x86 fully regression tests.

gcc/ChangeLog:

        * Makefile.in: Add match-sat-alu.pd as dependency.
        * match.pd: Remove saturation alu related patterns.
        * match-sat-alu.pd: Add new file for saturation alu patterns.

Signed-off-by: Pan Li <[email protected]>
---
 gcc/Makefile.in      |   2 +-
 gcc/match-sat-alu.pd | 566 ++++++++++++++++++++++++++++++++++++++++++
 gcc/match.pd         | 572 ++-----------------------------------------
 3 files changed, 584 insertions(+), 556 deletions(-)
 create mode 100644 gcc/match-sat-alu.pd

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 5e656c3c25b..e86884853bc 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -3055,7 +3055,7 @@ $(GENERIC_MATCH_PD_SEQ_SRC): s-generic-match 
generic-match-head.cc; @true
 generic-match-auto.h: s-generic-match; @true
 
 s-gimple-match: build/genmatch$(build_exeext) \
-           $(srcdir)/match.pd cfn-operators.pd
+           $(srcdir)/match.pd $(srcdir)/match-sat-alu.pd cfn-operators.pd
        $(RUN_GEN) build/genmatch$(build_exeext) --gimple \
            --header=tmp-gimple-match-auto.h --include=gimple-match-auto.h \
            $(srcdir)/match.pd $(patsubst %, tmp-%, $(GIMPLE_MATCH_PD_SEQ_SRC))
diff --git a/gcc/match-sat-alu.pd b/gcc/match-sat-alu.pd
new file mode 100644
index 00000000000..483c37b6d9f
--- /dev/null
+++ b/gcc/match-sat-alu.pd
@@ -0,0 +1,566 @@
+/* Match-and-simplify Saturation ALU patterns for shared GENERIC and GIMPLE
+   folding,  included by match.pd for clear organizational structure.
+   This file is consumed by genmatch which produces gimple-match.cc
+   and generic-match.cc from it.
+
+   Copyright (C) 2014-2026 Free Software Foundation, Inc.
+   Contributed by Pan Li <[email protected]>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+
+/* Saturation add for unsigned integer.  */
+(if (INTEGRAL_TYPE_P (type) && TYPE_UNSIGNED (type))
+ (match (usadd_overflow_mask @0 @1)
+  /* SAT_U_ADD = (X + Y) | -(X > (X + Y)).
+     Overflow_Mask = -(X > (X + Y)).  */
+  (negate (convert (gt @0 (plus:c @0 @1))))
+  (if (types_match (type, @0, @1))))
+ (match (usadd_overflow_mask @0 @1)
+  /* SAT_U_ADD = (X + Y) | -(X > (X + Y)).
+     Overflow_Mask = -((X + Y) < X).  */
+  (negate (convert (lt (plus:c @0 @1) @0)))
+  (if (types_match (type, @0, @1))))
+ (match (unsigned_integer_sat_add @0 @1)
+  /* SAT_U_ADD = (X + Y) | Overflow_Mask  */
+  (bit_ior:c (plus:c @0 @1) (usadd_overflow_mask @0 @1))
+  (if (types_match (type, @0, @1))))
+ (match (unsigned_integer_sat_add @0 @1)
+  /* SAT_U_ADD = (X + Y) >= X ? (X + Y) : -1  */
+  (cond^ (ge (plus:c@2 @0 @1) @0) @2 integer_minus_onep)
+  (if (types_match (type, @0, @1))))
+ (match (unsigned_integer_sat_add @0 @1)
+  /* SAT_U_ADD = (X + Y) < X ? -1 : (X + Y)  */
+  (cond^ (lt (plus:c@2 @0 @1) @0) integer_minus_onep @2)
+  (if (types_match (type, @0, @1))))
+ (match (unsigned_integer_sat_add @0 @1)
+  /* SAT_U_ADD = X <= (X + Y) ? (X + Y) : -1  */
+  (cond^ (le @0 (plus:c@2 @0 @1)) @2 integer_minus_onep)
+  (if (types_match (type, @0, @1))))
+ (match (unsigned_integer_sat_add @0 @1)
+  /* SAT_U_ADD = X > (X + Y) ? -1 : (X + Y)  */
+  (cond^ (gt @0 (plus:c@2 @0 @1)) integer_minus_onep @2)
+  (if (types_match (type, @0, @1))))
+ (match (unsigned_integer_sat_add @0 @1)
+  /* SAT_U_ADD = (X + IMM) >= x ? (X + IMM) : -1  */
+  (plus (min @0 INTEGER_CST@2) INTEGER_CST@1)
+  (if (types_match (type, @0, @1))
+   (with
+    {
+     unsigned precision = TYPE_PRECISION (type);
+     wide_int cst_1 = wi::to_wide (@1);
+     wide_int cst_2 = wi::to_wide (@2);
+     wide_int max = wi::mask (precision, false, precision);
+     wide_int sum = wi::add (cst_1, cst_2);
+    }
+    (if (wi::eq_p (max, sum))))))
+ (match (unsigned_integer_sat_add @0 @1)
+  /* SUM = ADD_OVERFLOW (X, Y)
+     SAT_U_ADD = REALPART (SUM) | -IMAGPART (SUM)   */
+  (bit_ior:c (realpart (IFN_ADD_OVERFLOW@2 @0 @1)) (negate (imagpart @2)))
+  (if (types_match (type, @0, @1))))
+ (match (unsigned_integer_sat_add @0 @1)
+  /* SUM = ADD_OVERFLOW (X, Y)
+     SAT_U_ADD = REALPART (SUM) | -(IMAGPART (SUM) != 0)   */
+  (bit_ior:c (realpart (IFN_ADD_OVERFLOW@2 @0 @1))
+            (negate (convert (ne (imagpart @2) integer_zerop))))
+  (if (types_match (type, @0, @1))))
+ (match (unsigned_integer_sat_add @0 @1)
+  /* SUM = ADD_OVERFLOW (X, Y)
+     SAT_U_ADD = IMAGPART (SUM) == 0 ? REALPART (SUM) : -1   */
+  (cond^ (eq (imagpart (IFN_ADD_OVERFLOW@2 @0 @1)) integer_zerop)
+        (realpart @2) integer_minus_onep)
+  (if (types_match (type, @0, @1))))
+ (match (unsigned_integer_sat_add @0 @1)
+  /* SUM = ADD_OVERFLOW (X, Y)
+     SAT_U_ADD = IMAGPART (SUM) != 0 ? -1 : REALPART (SUM)  */
+  (cond^ (ne (imagpart (IFN_ADD_OVERFLOW@2 @0 @1)) integer_zerop)
+        integer_minus_onep (realpart @2))
+  (if (types_match (type, @0, @1))))
+ (match (unsigned_integer_sat_add @0 @1)
+  /* SUM = ADD_OVERFLOW (X, IMM)
+     SAT_U_ADD = IMAGPART (SUM) != 0 ? -1 : REALPART (SUM)  */
+  (cond^ (ne (imagpart (IFN_ADD_OVERFLOW@2 @0 INTEGER_CST@1)) integer_zerop)
+        integer_minus_onep (realpart @2))
+  (if (types_match (type, @0) && int_fits_type_p (@1, type))))
+ (match (unsigned_integer_sat_add @0 @1)
+  /* WIDEN_SUM = (WT)X + (WT)Y
+     SAT_U_ADD = WIDEN_SUM > MAX ? MAX : (NT)WIDEN_SUM  */
+  (cond^ (le (plus (convert@2 @0) (convert@3 @1)) INTEGER_CST@4)
+        (plus:c @0 @1) integer_minus_onep)
+  (if (types_match (type, @0, @1) && types_match (@2, @3))
+   (with
+    {
+     unsigned precision = TYPE_PRECISION (type);
+     unsigned widen_precision = TYPE_PRECISION (TREE_TYPE (@2));
+     wide_int max = wi::mask (precision, false, widen_precision);
+     wide_int c4 = wi::to_wide (@4);
+    }
+    (if (wi::eq_p (c4, max) && widen_precision > precision))))))
+
+/* 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)
+  (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)))
+                   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)))
+  (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)))
+  (if (types_match (type, @0, @1))))
+ (match (unsigned_integer_sat_sub @0 @1)
+  /* DIFF = SUB_OVERFLOW (X, Y)
+     SAT_U_SUB = REALPART (DIFF) | (IMAGPART (DIFF) + (-1))  */
+  (bit_and:c (realpart (IFN_SUB_OVERFLOW@2 @0 @1))
+   (plus (imagpart @2) integer_minus_onep))
+  (if (types_match (type, @0, @1))))
+ (match (unsigned_integer_sat_sub @0 @1)
+  /* DIFF = SUB_OVERFLOW (X, Y)
+     SAT_U_SUB = REALPART (DIFF) * (IMAGPART (DIFF) ^ (1))  */
+  (mult:c (realpart (IFN_SUB_OVERFLOW@2 @0 @1))
+   (bit_xor (imagpart @2) integer_onep))
+  (if (types_match (type, @0, @1))))
+ (match (unsigned_integer_sat_sub @0 @1)
+  /* DIFF = SUB_OVERFLOW (X, Y)
+     SAT_U_SUB = IMAGPART (DIFF) == 0 ? REALPART (DIFF) : 0  */
+  (cond^ (eq (imagpart (IFN_SUB_OVERFLOW@2 @0 @1)) integer_zerop)
+        (realpart @2) integer_zerop)
+  (if (types_match (type, @0, @1))))
+ (match (unsigned_integer_sat_sub @0 @1)
+  /* DIFF = SUB_OVERFLOW (X, Y)
+     SAT_U_SUB = IMAGPART (DIFF) != 0 ? 0 : REALPART (DIFF)  */
+  (cond^ (ne (imagpart (IFN_SUB_OVERFLOW@2 @0 @1)) integer_zerop)
+        integer_zerop (realpart @2))
+  (if (types_match (type, @0, @1))))
+ (match (unsigned_integer_sat_sub @0 @1)
+  /* SAT_U_SUB = IMM > Y ? (IMM - Y) : 0
+     SAT_U_SUB = IMM >= Y ? (IMM - Y) : 0  */
+  (cond^ (le @1 INTEGER_CST@2) (minus INTEGER_CST@0 @1) integer_zerop)
+  (if (types_match (type, @1) && int_fits_type_p (@0, type))
+   (with
+    {
+     unsigned precision = TYPE_PRECISION (type);
+     wide_int max = wi::mask (precision, false, precision);
+     wide_int c0 = wi::to_wide (@0);
+     wide_int c2 = wi::to_wide (@2);
+     wide_int c2_add_1 = wi::add (c2, wi::uhwi (1, precision));
+     bool equal_p = wi::eq_p (c0, c2);
+     bool less_than_1_p = !wi::eq_p (c2, max) && wi::eq_p (c2_add_1, c0);
+    }
+    (if (equal_p || less_than_1_p)))))
+ (match (unsigned_integer_sat_sub @0 @1)
+  /* SAT_U_SUB = (MAX - 1) >= Y ? ((MAX - 1) - Y) : 0  */
+  (cond^ (ne @1 INTEGER_CST@2) (minus INTEGER_CST@0 @1) integer_zerop)
+  (if (types_match (type, @1))
+   (with
+    {
+     unsigned precision = TYPE_PRECISION (type);
+     wide_int max = wi::mask (precision, false, precision);
+     wide_int c0 = wi::to_wide (@0);
+     wide_int c2 = wi::to_wide (@2);
+     wide_int c0_add_1 = wi::add (c0, wi::uhwi (1, precision));
+    }
+    (if (wi::eq_p (c2, max) && wi::eq_p (c0_add_1, max))))))
+ (match (unsigned_integer_sat_sub @0 @1)
+  /* SAT_U_SUB = 1 >= Y ? (1 - Y) : 0  */
+  (cond^ (le @1 integer_onep@0) (bit_xor @1 integer_onep@0) integer_zerop)
+  (if (types_match (type, @1))))
+ (match (unsigned_integer_sat_sub @0 @1)
+  /* SAT_U_SUB = X > IMM  ? (X - IMM) : 0.
+     SAT_U_SUB = X >= IMM ? (X - IMM) : 0.  */
+  (plus (max @0 INTEGER_CST@1) INTEGER_CST@2)
+  (if (types_match (type, @1) && int_fits_type_p (@1, type))
+   (with
+    {
+     unsigned precision = TYPE_PRECISION (type);
+     wide_int c1 = wi::to_wide (@1);
+     wide_int c2 = wi::to_wide (@2);
+     wide_int sum = wi::add (c1, c2);
+    }
+    (if (wi::eq_p (sum, wi::uhwi (0, precision))))))))
+
+(if (INTEGRAL_TYPE_P (type) && TYPE_UNSIGNED (type))
+ (match (unsigned_integer_narrow_clip @0)
+  /* SAT_U_TRUNC<NT>(MAX (0, X)) =
+            (UT)X & ~(NT)(-1) ? (-X) >> TYPE_PRECISION(X) - 1 : X
+
+     The gimple representation uses X > ~(NT)(-1) instead of
+     using & so match on gt instead of bit_and.  */
+  (convert (cond^ (gt (nop_convert? @0) INTEGER_CST@1)
+        (rshift:s (nop_convert? (negate (nop_convert? @0))) INTEGER_CST@2)
+        @0))
+  (if (! TYPE_UNSIGNED (TREE_TYPE (@0)))
+   (with
+    {
+     unsigned itype_precision = TYPE_PRECISION (TREE_TYPE (@0));
+     unsigned otype_precision = TYPE_PRECISION (type);
+     wide_int trunc_max = wi::mask (otype_precision, false, itype_precision);
+     wide_int int_cst_1 = wi::to_wide (@1, itype_precision);
+     wide_int int_cst_2 = wi::to_wide (@2, itype_precision);
+     wide_int shift_amount = wi::uhwi (itype_precision - 1,
+                                 itype_precision); // AKA itype_bits - 1
+     int cmp = 0;
+     cmp = wi::cmp (int_cst_2, shift_amount, TYPE_SIGN (TREE_TYPE (@0)));
+    }
+    (if (otype_precision < itype_precision && wi::eq_p (trunc_max,
+    int_cst_1) && (cmp >= 0)))))))
+
+/* Saturation truncate for unsigned integer.  */
+(if (INTEGRAL_TYPE_P (type) && TYPE_UNSIGNED (type))
+ (match (unsigned_integer_sat_trunc @0)
+  /* SAT_U_TRUNC = (NT)x | (NT)(-(X > (WT)(NT)(-1)))  */
+  (bit_ior:c (negate (convert (gt @0 INTEGER_CST@1))) (convert @0))
+  (if (TYPE_UNSIGNED (TREE_TYPE (@0)))
+   (with
+    {
+     unsigned itype_precision = TYPE_PRECISION (TREE_TYPE (@0));
+     unsigned otype_precision = TYPE_PRECISION (type);
+     wide_int trunc_max = wi::mask (otype_precision, false, itype_precision);
+     wide_int int_cst = wi::to_wide (@1, itype_precision);
+    }
+    (if (otype_precision < itype_precision && wi::eq_p (trunc_max, 
int_cst))))))
+ (match (unsigned_integer_sat_trunc @0)
+  /* SAT_U_TRUNC = (NT)(MIN_EXPR (X, IMM))
+     If Op_0 def is MIN_EXPR and not single_use.  Aka below pattern:
+
+     _18 = MIN_EXPR <left_8, 4294967295>; // op_0 def
+     iftmp.0_11 = (unsigned int) _18;     // op_0
+     stream.avail_out = iftmp.0_11;
+     left_37 = left_8 - _18;              // op_0 use
+
+     Transfer to .SAT_TRUNC will have MIN_EXPR still live.  Then the backend
+     (for example x86/riscv) will have 2-3 more insns generation for .SAT_TRUNC
+     besides the MIN_EXPR.  Thus,  keep the normal truncation as is should be
+     the better choose.  */
+  (convert (min@2 @0 INTEGER_CST@1))
+  (if (TYPE_UNSIGNED (TREE_TYPE (@0)) && single_use (@2))
+   (with
+    {
+     unsigned itype_precision = TYPE_PRECISION (TREE_TYPE (@0));
+     unsigned otype_precision = TYPE_PRECISION (type);
+     wide_int trunc_max = wi::mask (otype_precision, false, itype_precision);
+     wide_int int_cst = wi::to_wide (@1, itype_precision);
+    }
+    (if (otype_precision < itype_precision && wi::eq_p (trunc_max, 
int_cst))))))
+ (match (unsigned_integer_sat_trunc @0)
+  /* SAT_U_TRUNC = (NT)X | ((NT)(X <= (WT)-1) + (NT)-1)  */
+  (bit_ior:c (plus:c (convert (le @0 INTEGER_CST@1)) INTEGER_CST@2)
+            (convert @0))
+  (if (TYPE_UNSIGNED (TREE_TYPE (@0)))
+   (with
+    {
+     unsigned itype_precision = TYPE_PRECISION (TREE_TYPE (@0));
+     unsigned otype_precision = TYPE_PRECISION (type);
+     wide_int trunc_max = wi::mask (otype_precision, false, itype_precision);
+     wide_int max = wi::mask (otype_precision, false, otype_precision);
+     wide_int int_cst_1 = wi::to_wide (@1);
+     wide_int int_cst_2 = wi::to_wide (@2);
+    }
+    (if (wi::eq_p (trunc_max, int_cst_1) && wi::eq_p (max, int_cst_2)))))))
+
+(if (INTEGRAL_TYPE_P (type) && !TYPE_UNSIGNED (type))
+ /* SAT_VAL = (-(T)(X < 0) ^ MAX)  */
+ (match (signed_integer_sat_val @0)
+  (bit_xor:c (nop_convert? (negate
+                           (nop_convert? (convert (lt @0 integer_zerop)))))
+            max_value)))
+
+/* Saturation add for signed integer.  */
+(if (INTEGRAL_TYPE_P (type) && !TYPE_UNSIGNED (type))
+ (match (signed_integer_sat_add @0 @1)
+  /* T SUM = (T)((UT)X + (UT)Y)
+     SAT_S_ADD = (X ^ SUM) & !(X ^ Y) < 0 ? (-(T)(X < 0) ^ MAX) : SUM  */
+  (cond^ (lt (bit_and:c (bit_xor:c @0 (nop_convert@2 (plus (nop_convert @0)
+                                                          (nop_convert @1))))
+                       (bit_not (bit_xor:c @0 @1)))
+            integer_zerop)
+        (signed_integer_sat_val @0)
+        @2))
+ (match (signed_integer_sat_add @0 @1)
+  /* T SUM = (T)((UT)X + (UT)Y)
+     SAT_S_ADD = (X ^ SUM) & !(X ^ Y) >= 0 ? SUM : (-(T)(X < 0) ^ MAX)  */
+  (cond^ (ge (bit_and:c (bit_xor @0 (nop_convert@2 (plus (nop_convert @0)
+                                                        (nop_convert @1))))
+                       (bit_not (bit_xor:c @0 @1)))
+            integer_zerop)
+        @2
+        (bit_xor:c (negate (convert (lt @0 integer_zerop))) max_value)))
+ (match (signed_integer_sat_add @0 @1)
+  /* T SUM = (T)((UT)X + (UT)Y)
+     SAT_S_ADD = (X ^ Y) < 0 && (X ^ SUM) >= 0 ? (-(T)(X < 0) ^ MAX) : SUM  */
+  (cond^ (bit_and:c (lt (bit_xor @0 (nop_convert@2 (plus (nop_convert @0)
+                                                        (nop_convert @1))))
+                       integer_zerop)
+                   (ge (bit_xor:c @0 @1) integer_zerop))
+        (signed_integer_sat_val @0)
+        @2))
+ (match (signed_integer_sat_add @0 @1)
+  /* T SUM = (T)((UT)X + (UT)IMM)
+     SAT_S_ADD = (X ^ SUM) < 0 && (X ^ IMM) >= 0 ? (-(T)(X < 0) ^ MAX) : SUM  
*/
+  (cond^ (bit_and:c (lt (bit_xor @0 (nop_convert@2 (plus (nop_convert @0)
+                                                        INTEGER_CST@1)))
+                       integer_zerop)
+                   (ge (bit_xor:c @0 INTEGER_CST@3) integer_zerop))
+        (signed_integer_sat_val @0)
+        @2)
+  (if (wi::eq_p (wi::to_wide (@1), wi::to_wide (@3)))))
+ (match (signed_integer_sat_add @0 @1)
+   /* SUM = .ADD_OVERFLOW (X, Y)
+      SAT_S_ADD = IMAGPART_EXPR (SUM) != 0 ? (-(T)(X < 0) ^ MAX) : SUM  */
+  (cond^ (ne (imagpart (IFN_ADD_OVERFLOW:c@2 @0 @1)) integer_zerop)
+        (signed_integer_sat_val @0)
+        (realpart @2)))
+ (match (signed_integer_sat_add @0 @1)
+  /* T SUM = (T)((UT)X + (UT)Y)
+     SAT_S_ADD = (X ^ SUM) < 0 & ~((X ^ Y) < 0) ? (-(T)(X < 0) ^ MAX) : SUM  */
+  (cond^ (bit_and:c (lt (bit_xor @0 (nop_convert@2 (plus (nop_convert @0)
+                                                        (nop_convert @1))))
+                       integer_zerop)
+                   (bit_not (lt (bit_xor:c @0 @1) integer_zerop)))
+        (signed_integer_sat_val @0)
+        @2))
+ (match (signed_integer_sat_add @0 @1)
+  /* T SUM = (T)((UT)X + (UT)IMM);
+     SAT_S_ADD = (X ^ IMM) < 0 ? SUM : (X ^ SUM) >= 0 ? SUM
+                                                     : (x < 0) ? MIN : MAX  */
+  (cond^ (lt (bit_and:c (bit_xor:c @0 (nop_convert@2 (plus (nop_convert @0)
+                                                          INTEGER_CST@1)))
+                       (bit_xor:c @0 INTEGER_CST@3)) integer_zerop)
+        (signed_integer_sat_val @0)
+        @2)
+  (if (wi::bit_and (wi::to_wide (@1), wi::to_wide (@3)) == 0)))
+
+(match (signed_integer_sat_add @0 @1)
+  /* T SUM = (T)((UT)X + (UT)-1);
+     SAT_S_ADD = (X ^ -1) < 0 ? SUM : (X ^ SUM) >= 0 ? SUM
+                                                     : (x < 0) ? MIN : MAX  */
+  (convert (cond^ (lt (bit_and:c @0 (nop_convert (negate (nop_convert @0))))
+             integer_zerop)
+        INTEGER_CST@2
+        (plus (nop_convert @0) integer_all_onesp@1)))
+   (with
+    {
+     unsigned precision = TYPE_PRECISION (type);
+     wide_int c1 = wi::to_wide (@1);
+     wide_int c2 = wi::to_wide (@2);
+     wide_int sum = wi::add (c1, c2);
+    }
+    (if (wi::eq_p (sum, wi::max_value (precision, SIGNED))))))
+
+(match (signed_integer_sat_add @0 @1)
+  /* T SUM = (T)((UT)X + (UT)IMM)
+     SAT_S_ADD = (X ^ SUM) < 0 && (X ^ IMM) >= 0 ? (-(T)(X < 0) ^ MAX) : SUM  
*/
+   (cond^ (ge (bit_ior:c (bit_xor:c @0 INTEGER_CST@1)
+                       (bit_not (bit_xor:c @0 (nop_convert@2 (plus 
(nop_convert @0)
+                       INTEGER_CST@3)))))
+                   integer_zerop)
+           (signed_integer_sat_val @0)
+           @2)
+   (if (wi::eq_p (wi::to_wide (@1), wi::to_wide (@3))))))
+
+/* Saturation sub for signed integer.  */
+(if (INTEGRAL_TYPE_P (type) && !TYPE_UNSIGNED (type))
+ (match (signed_integer_sat_sub @0 @1)
+  /* T Z = (T)((UT)X - (UT)Y);
+     SAT_S_SUB = (X ^ Y) & (X ^ Z) < 0 ? (-(T)(X < 0) ^ MAX) : Z  */
+  (cond^ (lt (bit_and:c (bit_xor:c @0 @1)
+                       (bit_xor @0 (nop_convert@2 (minus (nop_convert @0)
+                                                         (nop_convert @1)))))
+            integer_zerop)
+        (signed_integer_sat_val @0)
+        @2))
+ (match (signed_integer_sat_sub @0 @1)
+  /* T Z = (T)((UT)X - (UT)Y);
+     SAT_S_SUB = (X ^ Y) & (X ^ Z) >= 0 ? Z : (-(T)(X < 0) ^ MAX)  */
+  (cond^ (ge (bit_and:c (bit_xor:c @0 @1)
+                       (bit_xor @0 (nop_convert@2 (minus (nop_convert @0)
+                                                         (nop_convert @1)))))
+            integer_zerop)
+        @2
+        (signed_integer_sat_val @0)))
+ (match (signed_integer_sat_sub @0 @1)
+  /* T Z = (T)((UT)X - (UT)Y);
+     SAT_S_SUB = (X ^ Y) < 0 & (X ^ Z) < 0 ? (-(T)(X < 0) ^ MAX) : Z  */
+  (cond^ (bit_and:c (lt (bit_xor @0 (nop_convert@2 (minus (nop_convert @0)
+                                                         (nop_convert @1))))
+                       integer_zerop)
+                   (lt (bit_xor:c @0 @1) integer_zerop))
+        (signed_integer_sat_val @0)
+        @2))
+ (match (signed_integer_sat_sub @0 @1)
+  /* Z = .SUB_OVERFLOW (X, Y)
+     SAT_S_SUB = IMAGPART (Z) != 0 ? (-(T)(X < 0) ^ MAX) : REALPART (Z)  */
+  (cond^ (ne (imagpart (IFN_SUB_OVERFLOW@2 @0 @1)) integer_zerop)
+        (signed_integer_sat_val @0)
+        (realpart @2))
+  (if (types_match (type, @0, @1)))))
+
+/* Saturation truncate for signed integer.  */
+(if (INTEGRAL_TYPE_P (type) && !TYPE_UNSIGNED (type))
+ (match (signed_integer_sat_trunc @0)
+  /* SAT_S_TRUNC(X) = (unsigned)X + NT_MAX + 1  > Unsigned_MAX ? (NT)X  */
+  (cond^ (gt (plus:c (convert@4 @0) INTEGER_CST@1) INTEGER_CST@2)
+        (bit_xor:c (nop_convert?
+                    (negate (nop_convert? (convert (lt @0 integer_zerop)))))
+                   INTEGER_CST@3)
+        (convert @0))
+  (if (!TYPE_UNSIGNED (TREE_TYPE (@0)) && TYPE_UNSIGNED (TREE_TYPE (@4)))
+   (with
+    {
+     unsigned itype_prec = TYPE_PRECISION (TREE_TYPE (@0));
+     unsigned otype_prec = TYPE_PRECISION (type);
+     wide_int offset = wi::uhwi (HOST_WIDE_INT_1U << (otype_prec - 1),
+                                itype_prec); // Aka 128 for int8_t
+     wide_int limit_0 = wi::mask (otype_prec, false, itype_prec); // Aka 255
+     wide_int limit_1 = wi::uhwi ((HOST_WIDE_INT_1U << otype_prec) - 3,
+                                 itype_prec); // Aka 253
+     wide_int limit_2 = wi::uhwi ((HOST_WIDE_INT_1U << otype_prec) - 2,
+                                 itype_prec); // Aka 254
+     wide_int otype_max = wi::mask (otype_prec - 1, false, otype_prec);
+     wide_int itype_max = wi::mask (otype_prec - 1, false, itype_prec);
+     wide_int int_cst_1 = wi::to_wide (@1);
+     wide_int int_cst_2 = wi::to_wide (@2);
+     wide_int int_cst_3 = wi::to_wide (@3);
+    }
+    (if (((wi::eq_p (int_cst_1, offset) && wi::eq_p (int_cst_2, limit_0))
+        || (wi::eq_p (int_cst_1, itype_max) && wi::eq_p (int_cst_2, limit_2))
+        || (wi::eq_p (int_cst_1, offset) && wi::eq_p (int_cst_2, limit_2))
+        || (wi::eq_p (int_cst_1, itype_max) && wi::eq_p (int_cst_2, limit_1)))
+        && wi::eq_p (int_cst_3, otype_max)))))))
+
+/* Saturation mult for unsigned integer.  */
+(if (INTEGRAL_TYPE_P (type) && TYPE_UNSIGNED (type))
+ (for mult_op (mult widen_mult)
+  (match (usmul_widen_mult @0 @1)
+   (mult_op:c (convert@2 @0) (convert @1))
+    (if (types_match (@0, @1) && TYPE_UNSIGNED (TREE_TYPE (@0)))
+     (with
+      {
+       unsigned prec = TYPE_PRECISION (TREE_TYPE (@0));
+       unsigned cvt2_prec = TYPE_PRECISION (TREE_TYPE (@2));
+       bool widen_cvt_p = cvt2_prec > prec;
+      }
+      (if (widen_cvt_p))))))
+ (match (usmul_widen_mult @0 @1)
+  (widen_mult:c @0 @1)
+   (if (types_match (@0, @1))))
+ (match (unsigned_integer_sat_mul @0 @1)
+  /* SAT_U_MUL (X, Y) = {
+       WT x = (WT)a * (WT)b;
+       T max = -1;
+       if (x > (WT)(max))
+        return max;
+       else
+        return (T)x;
+     }
+     while WT is uint128_t, T is uint8_t, uint16_t, uint32_t or uint64_t.  */
+  (convert (min (usmul_widen_mult@3 @0 @1) INTEGER_CST@2))
+  (if (types_match (type, @0, @1))
+   (with
+    {
+      unsigned prec = TYPE_PRECISION (type);
+      unsigned widen_prec = TYPE_PRECISION (TREE_TYPE (@3));
+      wide_int max = wi::mask (prec, false, widen_prec);
+      bool c2_is_max_p = wi::eq_p (wi::to_wide (@2), max);
+    }
+    (if (c2_is_max_p)))))
+  (match (unsigned_integer_sat_mul @0 @1)
+   /* SAT_U_MUL (X, Y) = {
+       T result;
+       if (__builtin_mul_overflow (X, Y, &result))
+         return -1;
+       else
+         return result;
+      }
+      while T can be uint8_t, uint16_t, uint32_t and uint64_t.  */
+   (cond^ (ne (imagpart (IFN_MUL_OVERFLOW:c@2 @0 @1)) integer_zerop)
+          integer_minus_onep (realpart @2))
+   (if (types_match (type, @0, @1))))
+  (match (unsigned_integer_sat_mul @0 @1)
+   /* SAT_U_MUL (X, Y) = {
+       WT x = (WT)a * (WT)b;
+       if ((x >> sizeof(a) * 8) == 0)
+         return (T)x;
+       else
+         return (T)-1;
+      }
+      while WT is uint128_t, T is uint8_t, uint16_t, uint32_t or uint64_t.  */
+   (convert (cond^ (eq (rshift (mult:c@3 (convert @0) (convert @1))
+                              INTEGER_CST@2)
+                      integer_zerop)
+                  @3 INTEGER_CST@4))
+   (if (types_match (type, @0, @1))
+    (with
+     {
+      unsigned prec = TYPE_PRECISION (type);
+      unsigned widen_prec = TYPE_PRECISION (TREE_TYPE (@3));
+      wide_int c4 = wi::to_wide (@4);
+      wide_int max = wi::mask (prec, false, widen_prec);
+      bool c4_is_max_p = wi::eq_p (c4, max);
+      unsigned c2 = tree_to_uhwi (@2);
+      bool c2_is_type_precision_p = c2 == prec;
+     }
+     (if (widen_prec > prec && c2_is_type_precision_p && c4_is_max_p)))))
+  (match (unsigned_integer_sat_mul @0 @1)
+   /* SAT_U_MUL (X, Y) = {
+       WT x = (WT)a * (WT)b;
+       NT hi = x >> (sizeof(NT) * 8);
+       NT lo = (NT)x;
+       return lo | -!!hi;
+      } while WT is uint128_t, uint64_t, uint32_t, uint16_t,
+       and T is uint64_t, uint32_t, uint16_t, uint8_t.  */
+   (bit_ior:c
+    (convert?
+     (negate
+      (convert (ne (convert2? (rshift @3 INTEGER_CST@2)) integer_zerop))))
+    (convert (usmul_widen_mult@3 @0 @1)))
+   (if (types_match (type, @0, @1))
+    (with
+     {
+      unsigned prec = TYPE_PRECISION (type);
+      bool c2_is_type_precision_p = tree_to_uhwi (@2) == prec;
+     }
+     (if (c2_is_type_precision_p)))))
+  (match (unsigned_integer_sat_mul @0 @1)
+   /* SAT_U_MUL (X, Y) = {
+       WT x = (WT)a * (WT)b;
+       NT max = -1;
+       bool overflow_p = x > (WT)max;
+       return -(NT)(overflow_p) | (NT)x;
+      } while WT is uint128_t, uint64_t, uint32_t, uint16_t,
+       and T is uint64_t, uint32_t, uint16_t, uint8_t.  */
+   (bit_ior:c (negate (convert (gt @3 INTEGER_CST@2)))
+             (convert (usmul_widen_mult@3 @0 @1)))
+   (if (types_match (type, @0, @1))
+    (with
+     {
+      unsigned prec = TYPE_PRECISION (type);
+      unsigned widen_prec = TYPE_PRECISION (TREE_TYPE (@3));
+      wide_int max = wi::mask (prec, false, widen_prec);
+      bool c2_is_max_p = wi::eq_p (wi::to_wide (@2), max);
+     }
+     (if (c2_is_max_p)))))
+)
diff --git a/gcc/match.pd b/gcc/match.pd
index 7db8ce7580f..4d8cdd68d4c 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -3321,561 +3321,6 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
        || POINTER_TYPE_P (itype))
       && wi::eq_p (wi::to_wide (int_cst), wi::max_value (itype))))))
 
-#if GIMPLE
-/* Saturation add for unsigned integer.  */
-(if (INTEGRAL_TYPE_P (type) && TYPE_UNSIGNED (type))
- (match (usadd_overflow_mask @0 @1)
-  /* SAT_U_ADD = (X + Y) | -(X > (X + Y)).
-     Overflow_Mask = -(X > (X + Y)).  */
-  (negate (convert (gt @0 (plus:c @0 @1))))
-  (if (types_match (type, @0, @1))))
- (match (usadd_overflow_mask @0 @1)
-  /* SAT_U_ADD = (X + Y) | -(X > (X + Y)).
-     Overflow_Mask = -((X + Y) < X).  */
-  (negate (convert (lt (plus:c @0 @1) @0)))
-  (if (types_match (type, @0, @1))))
- (match (unsigned_integer_sat_add @0 @1)
-  /* SAT_U_ADD = (X + Y) | Overflow_Mask  */
-  (bit_ior:c (plus:c @0 @1) (usadd_overflow_mask @0 @1))
-  (if (types_match (type, @0, @1))))
- (match (unsigned_integer_sat_add @0 @1)
-  /* SAT_U_ADD = (X + Y) >= X ? (X + Y) : -1  */
-  (cond^ (ge (plus:c@2 @0 @1) @0) @2 integer_minus_onep)
-  (if (types_match (type, @0, @1))))
- (match (unsigned_integer_sat_add @0 @1)
-  /* SAT_U_ADD = (X + Y) < X ? -1 : (X + Y)  */
-  (cond^ (lt (plus:c@2 @0 @1) @0) integer_minus_onep @2)
-  (if (types_match (type, @0, @1))))
- (match (unsigned_integer_sat_add @0 @1)
-  /* SAT_U_ADD = X <= (X + Y) ? (X + Y) : -1  */
-  (cond^ (le @0 (plus:c@2 @0 @1)) @2 integer_minus_onep)
-  (if (types_match (type, @0, @1))))
- (match (unsigned_integer_sat_add @0 @1)
-  /* SAT_U_ADD = X > (X + Y) ? -1 : (X + Y)  */
-  (cond^ (gt @0 (plus:c@2 @0 @1)) integer_minus_onep @2)
-  (if (types_match (type, @0, @1))))
- (match (unsigned_integer_sat_add @0 @1)
-  /* SAT_U_ADD = (X + IMM) >= x ? (X + IMM) : -1  */
-  (plus (min @0 INTEGER_CST@2) INTEGER_CST@1)
-  (if (types_match (type, @0, @1))
-   (with
-    {
-     unsigned precision = TYPE_PRECISION (type);
-     wide_int cst_1 = wi::to_wide (@1);
-     wide_int cst_2 = wi::to_wide (@2);
-     wide_int max = wi::mask (precision, false, precision);
-     wide_int sum = wi::add (cst_1, cst_2);
-    }
-    (if (wi::eq_p (max, sum))))))
- (match (unsigned_integer_sat_add @0 @1)
-  /* SUM = ADD_OVERFLOW (X, Y)
-     SAT_U_ADD = REALPART (SUM) | -IMAGPART (SUM)   */
-  (bit_ior:c (realpart (IFN_ADD_OVERFLOW@2 @0 @1)) (negate (imagpart @2)))
-  (if (types_match (type, @0, @1))))
- (match (unsigned_integer_sat_add @0 @1)
-  /* SUM = ADD_OVERFLOW (X, Y)
-     SAT_U_ADD = REALPART (SUM) | -(IMAGPART (SUM) != 0)   */
-  (bit_ior:c (realpart (IFN_ADD_OVERFLOW@2 @0 @1))
-            (negate (convert (ne (imagpart @2) integer_zerop))))
-  (if (types_match (type, @0, @1))))
- (match (unsigned_integer_sat_add @0 @1)
-  /* SUM = ADD_OVERFLOW (X, Y)
-     SAT_U_ADD = IMAGPART (SUM) == 0 ? REALPART (SUM) : -1   */
-  (cond^ (eq (imagpart (IFN_ADD_OVERFLOW@2 @0 @1)) integer_zerop)
-        (realpart @2) integer_minus_onep)
-  (if (types_match (type, @0, @1))))
- (match (unsigned_integer_sat_add @0 @1)
-  /* SUM = ADD_OVERFLOW (X, Y)
-     SAT_U_ADD = IMAGPART (SUM) != 0 ? -1 : REALPART (SUM)  */
-  (cond^ (ne (imagpart (IFN_ADD_OVERFLOW@2 @0 @1)) integer_zerop)
-        integer_minus_onep (realpart @2))
-  (if (types_match (type, @0, @1))))
- (match (unsigned_integer_sat_add @0 @1)
-  /* SUM = ADD_OVERFLOW (X, IMM)
-     SAT_U_ADD = IMAGPART (SUM) != 0 ? -1 : REALPART (SUM)  */
-  (cond^ (ne (imagpart (IFN_ADD_OVERFLOW@2 @0 INTEGER_CST@1)) integer_zerop)
-        integer_minus_onep (realpart @2))
-  (if (types_match (type, @0) && int_fits_type_p (@1, type))))
- (match (unsigned_integer_sat_add @0 @1)
-  /* WIDEN_SUM = (WT)X + (WT)Y
-     SAT_U_ADD = WIDEN_SUM > MAX ? MAX : (NT)WIDEN_SUM  */
-  (cond^ (le (plus (convert@2 @0) (convert@3 @1)) INTEGER_CST@4)
-        (plus:c @0 @1) integer_minus_onep)
-  (if (types_match (type, @0, @1) && types_match (@2, @3))
-   (with
-    {
-     unsigned precision = TYPE_PRECISION (type);
-     unsigned widen_precision = TYPE_PRECISION (TREE_TYPE (@2));
-     wide_int max = wi::mask (precision, false, widen_precision);
-     wide_int c4 = wi::to_wide (@4);
-    }
-    (if (wi::eq_p (c4, max) && widen_precision > precision))))))
-
-/* 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)
-  (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)))
-                   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)))
-  (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)))
-  (if (types_match (type, @0, @1))))
- (match (unsigned_integer_sat_sub @0 @1)
-  /* DIFF = SUB_OVERFLOW (X, Y)
-     SAT_U_SUB = REALPART (DIFF) | (IMAGPART (DIFF) + (-1))  */
-  (bit_and:c (realpart (IFN_SUB_OVERFLOW@2 @0 @1))
-   (plus (imagpart @2) integer_minus_onep))
-  (if (types_match (type, @0, @1))))
- (match (unsigned_integer_sat_sub @0 @1)
-  /* DIFF = SUB_OVERFLOW (X, Y)
-     SAT_U_SUB = REALPART (DIFF) * (IMAGPART (DIFF) ^ (1))  */
-  (mult:c (realpart (IFN_SUB_OVERFLOW@2 @0 @1))
-   (bit_xor (imagpart @2) integer_onep))
-  (if (types_match (type, @0, @1))))
- (match (unsigned_integer_sat_sub @0 @1)
-  /* DIFF = SUB_OVERFLOW (X, Y)
-     SAT_U_SUB = IMAGPART (DIFF) == 0 ? REALPART (DIFF) : 0  */
-  (cond^ (eq (imagpart (IFN_SUB_OVERFLOW@2 @0 @1)) integer_zerop)
-        (realpart @2) integer_zerop)
-  (if (types_match (type, @0, @1))))
- (match (unsigned_integer_sat_sub @0 @1)
-  /* DIFF = SUB_OVERFLOW (X, Y)
-     SAT_U_SUB = IMAGPART (DIFF) != 0 ? 0 : REALPART (DIFF)  */
-  (cond^ (ne (imagpart (IFN_SUB_OVERFLOW@2 @0 @1)) integer_zerop)
-        integer_zerop (realpart @2))
-  (if (types_match (type, @0, @1))))
- (match (unsigned_integer_sat_sub @0 @1)
-  /* SAT_U_SUB = IMM > Y ? (IMM - Y) : 0
-     SAT_U_SUB = IMM >= Y ? (IMM - Y) : 0  */
-  (cond^ (le @1 INTEGER_CST@2) (minus INTEGER_CST@0 @1) integer_zerop)
-  (if (types_match (type, @1) && int_fits_type_p (@0, type))
-   (with
-    {
-     unsigned precision = TYPE_PRECISION (type);
-     wide_int max = wi::mask (precision, false, precision);
-     wide_int c0 = wi::to_wide (@0);
-     wide_int c2 = wi::to_wide (@2);
-     wide_int c2_add_1 = wi::add (c2, wi::uhwi (1, precision));
-     bool equal_p = wi::eq_p (c0, c2);
-     bool less_than_1_p = !wi::eq_p (c2, max) && wi::eq_p (c2_add_1, c0);
-    }
-    (if (equal_p || less_than_1_p)))))
- (match (unsigned_integer_sat_sub @0 @1)
-  /* SAT_U_SUB = (MAX - 1) >= Y ? ((MAX - 1) - Y) : 0  */
-  (cond^ (ne @1 INTEGER_CST@2) (minus INTEGER_CST@0 @1) integer_zerop)
-  (if (types_match (type, @1))
-   (with
-    {
-     unsigned precision = TYPE_PRECISION (type);
-     wide_int max = wi::mask (precision, false, precision);
-     wide_int c0 = wi::to_wide (@0);
-     wide_int c2 = wi::to_wide (@2);
-     wide_int c0_add_1 = wi::add (c0, wi::uhwi (1, precision));
-    }
-    (if (wi::eq_p (c2, max) && wi::eq_p (c0_add_1, max))))))
- (match (unsigned_integer_sat_sub @0 @1)
-  /* SAT_U_SUB = 1 >= Y ? (1 - Y) : 0  */
-  (cond^ (le @1 integer_onep@0) (bit_xor @1 integer_onep@0) integer_zerop)
-  (if (types_match (type, @1))))
- (match (unsigned_integer_sat_sub @0 @1)
-  /* SAT_U_SUB = X > IMM  ? (X - IMM) : 0.
-     SAT_U_SUB = X >= IMM ? (X - IMM) : 0.  */
-  (plus (max @0 INTEGER_CST@1) INTEGER_CST@2)
-  (if (types_match (type, @1) && int_fits_type_p (@1, type))
-   (with
-    {
-     unsigned precision = TYPE_PRECISION (type);
-     wide_int c1 = wi::to_wide (@1);
-     wide_int c2 = wi::to_wide (@2);
-     wide_int sum = wi::add (c1, c2);
-    }
-    (if (wi::eq_p (sum, wi::uhwi (0, precision))))))))
-
-(if (INTEGRAL_TYPE_P (type) && TYPE_UNSIGNED (type))
- (match (unsigned_integer_narrow_clip @0)
-  /* SAT_U_TRUNC<NT>(MAX (0, X)) =
-            (UT)X & ~(NT)(-1) ? (-X) >> TYPE_PRECISION(X) - 1 : X
-
-     The gimple representation uses X > ~(NT)(-1) instead of
-     using & so match on gt instead of bit_and.  */
-  (convert (cond^ (gt (nop_convert? @0) INTEGER_CST@1)
-        (rshift:s (nop_convert? (negate (nop_convert? @0))) INTEGER_CST@2)
-        @0))
-  (if (! TYPE_UNSIGNED (TREE_TYPE (@0)))
-   (with
-    {
-     unsigned itype_precision = TYPE_PRECISION (TREE_TYPE (@0));
-     unsigned otype_precision = TYPE_PRECISION (type);
-     wide_int trunc_max = wi::mask (otype_precision, false, itype_precision);
-     wide_int int_cst_1 = wi::to_wide (@1, itype_precision);
-     wide_int int_cst_2 = wi::to_wide (@2, itype_precision);
-     wide_int shift_amount = wi::uhwi (itype_precision - 1,
-                                 itype_precision); // AKA itype_bits - 1
-     int cmp = 0;
-     cmp = wi::cmp (int_cst_2, shift_amount, TYPE_SIGN (TREE_TYPE (@0)));
-    }
-    (if (otype_precision < itype_precision && wi::eq_p (trunc_max,
-    int_cst_1) && (cmp >= 0)))))))
-
-/* Saturation truncate for unsigned integer.  */
-(if (INTEGRAL_TYPE_P (type) && TYPE_UNSIGNED (type))
- (match (unsigned_integer_sat_trunc @0)
-  /* SAT_U_TRUNC = (NT)x | (NT)(-(X > (WT)(NT)(-1)))  */
-  (bit_ior:c (negate (convert (gt @0 INTEGER_CST@1))) (convert @0))
-  (if (TYPE_UNSIGNED (TREE_TYPE (@0)))
-   (with
-    {
-     unsigned itype_precision = TYPE_PRECISION (TREE_TYPE (@0));
-     unsigned otype_precision = TYPE_PRECISION (type);
-     wide_int trunc_max = wi::mask (otype_precision, false, itype_precision);
-     wide_int int_cst = wi::to_wide (@1, itype_precision);
-    }
-    (if (otype_precision < itype_precision && wi::eq_p (trunc_max, 
int_cst))))))
- (match (unsigned_integer_sat_trunc @0)
-  /* SAT_U_TRUNC = (NT)(MIN_EXPR (X, IMM))
-     If Op_0 def is MIN_EXPR and not single_use.  Aka below pattern:
-
-     _18 = MIN_EXPR <left_8, 4294967295>; // op_0 def
-     iftmp.0_11 = (unsigned int) _18;     // op_0
-     stream.avail_out = iftmp.0_11;
-     left_37 = left_8 - _18;              // op_0 use
-
-     Transfer to .SAT_TRUNC will have MIN_EXPR still live.  Then the backend
-     (for example x86/riscv) will have 2-3 more insns generation for .SAT_TRUNC
-     besides the MIN_EXPR.  Thus,  keep the normal truncation as is should be
-     the better choose.  */
-  (convert (min@2 @0 INTEGER_CST@1))
-  (if (TYPE_UNSIGNED (TREE_TYPE (@0)) && single_use (@2))
-   (with
-    {
-     unsigned itype_precision = TYPE_PRECISION (TREE_TYPE (@0));
-     unsigned otype_precision = TYPE_PRECISION (type);
-     wide_int trunc_max = wi::mask (otype_precision, false, itype_precision);
-     wide_int int_cst = wi::to_wide (@1, itype_precision);
-    }
-    (if (otype_precision < itype_precision && wi::eq_p (trunc_max, 
int_cst))))))
- (match (unsigned_integer_sat_trunc @0)
-  /* SAT_U_TRUNC = (NT)X | ((NT)(X <= (WT)-1) + (NT)-1)  */
-  (bit_ior:c (plus:c (convert (le @0 INTEGER_CST@1)) INTEGER_CST@2)
-            (convert @0))
-  (if (TYPE_UNSIGNED (TREE_TYPE (@0)))
-   (with
-    {
-     unsigned itype_precision = TYPE_PRECISION (TREE_TYPE (@0));
-     unsigned otype_precision = TYPE_PRECISION (type);
-     wide_int trunc_max = wi::mask (otype_precision, false, itype_precision);
-     wide_int max = wi::mask (otype_precision, false, otype_precision);
-     wide_int int_cst_1 = wi::to_wide (@1);
-     wide_int int_cst_2 = wi::to_wide (@2);
-    }
-    (if (wi::eq_p (trunc_max, int_cst_1) && wi::eq_p (max, int_cst_2)))))))
-
-(if (INTEGRAL_TYPE_P (type) && !TYPE_UNSIGNED (type))
- /* SAT_VAL = (-(T)(X < 0) ^ MAX)  */
- (match (signed_integer_sat_val @0)
-  (bit_xor:c (nop_convert? (negate
-                           (nop_convert? (convert (lt @0 integer_zerop)))))
-            max_value)))
-
-/* Saturation add for signed integer.  */
-(if (INTEGRAL_TYPE_P (type) && !TYPE_UNSIGNED (type))
- (match (signed_integer_sat_add @0 @1)
-  /* T SUM = (T)((UT)X + (UT)Y)
-     SAT_S_ADD = (X ^ SUM) & !(X ^ Y) < 0 ? (-(T)(X < 0) ^ MAX) : SUM  */
-  (cond^ (lt (bit_and:c (bit_xor:c @0 (nop_convert@2 (plus (nop_convert @0)
-                                                          (nop_convert @1))))
-                       (bit_not (bit_xor:c @0 @1)))
-            integer_zerop)
-        (signed_integer_sat_val @0)
-        @2))
- (match (signed_integer_sat_add @0 @1)
-  /* T SUM = (T)((UT)X + (UT)Y)
-     SAT_S_ADD = (X ^ SUM) & !(X ^ Y) >= 0 ? SUM : (-(T)(X < 0) ^ MAX)  */
-  (cond^ (ge (bit_and:c (bit_xor @0 (nop_convert@2 (plus (nop_convert @0)
-                                                        (nop_convert @1))))
-                       (bit_not (bit_xor:c @0 @1)))
-            integer_zerop)
-        @2
-        (bit_xor:c (negate (convert (lt @0 integer_zerop))) max_value)))
- (match (signed_integer_sat_add @0 @1)
-  /* T SUM = (T)((UT)X + (UT)Y)
-     SAT_S_ADD = (X ^ Y) < 0 && (X ^ SUM) >= 0 ? (-(T)(X < 0) ^ MAX) : SUM  */
-  (cond^ (bit_and:c (lt (bit_xor @0 (nop_convert@2 (plus (nop_convert @0)
-                                                        (nop_convert @1))))
-                       integer_zerop)
-                   (ge (bit_xor:c @0 @1) integer_zerop))
-        (signed_integer_sat_val @0)
-        @2))
- (match (signed_integer_sat_add @0 @1)
-  /* T SUM = (T)((UT)X + (UT)IMM)
-     SAT_S_ADD = (X ^ SUM) < 0 && (X ^ IMM) >= 0 ? (-(T)(X < 0) ^ MAX) : SUM  
*/
-  (cond^ (bit_and:c (lt (bit_xor @0 (nop_convert@2 (plus (nop_convert @0)
-                                                        INTEGER_CST@1)))
-                       integer_zerop)
-                   (ge (bit_xor:c @0 INTEGER_CST@3) integer_zerop))
-        (signed_integer_sat_val @0)
-        @2)
-  (if (wi::eq_p (wi::to_wide (@1), wi::to_wide (@3)))))
- (match (signed_integer_sat_add @0 @1)
-   /* SUM = .ADD_OVERFLOW (X, Y)
-      SAT_S_ADD = IMAGPART_EXPR (SUM) != 0 ? (-(T)(X < 0) ^ MAX) : SUM  */
-  (cond^ (ne (imagpart (IFN_ADD_OVERFLOW:c@2 @0 @1)) integer_zerop)
-        (signed_integer_sat_val @0)
-        (realpart @2)))
- (match (signed_integer_sat_add @0 @1)
-  /* T SUM = (T)((UT)X + (UT)Y)
-     SAT_S_ADD = (X ^ SUM) < 0 & ~((X ^ Y) < 0) ? (-(T)(X < 0) ^ MAX) : SUM  */
-  (cond^ (bit_and:c (lt (bit_xor @0 (nop_convert@2 (plus (nop_convert @0)
-                                                        (nop_convert @1))))
-                       integer_zerop)
-                   (bit_not (lt (bit_xor:c @0 @1) integer_zerop)))
-        (signed_integer_sat_val @0)
-        @2))
- (match (signed_integer_sat_add @0 @1)
-  /* T SUM = (T)((UT)X + (UT)IMM);
-     SAT_S_ADD = (X ^ IMM) < 0 ? SUM : (X ^ SUM) >= 0 ? SUM
-                                                     : (x < 0) ? MIN : MAX  */
-  (cond^ (lt (bit_and:c (bit_xor:c @0 (nop_convert@2 (plus (nop_convert @0)
-                                                          INTEGER_CST@1)))
-                       (bit_xor:c @0 INTEGER_CST@3)) integer_zerop)
-        (signed_integer_sat_val @0)
-        @2)
-  (if (wi::bit_and (wi::to_wide (@1), wi::to_wide (@3)) == 0)))
-
-(match (signed_integer_sat_add @0 @1)
-  /* T SUM = (T)((UT)X + (UT)-1);
-     SAT_S_ADD = (X ^ -1) < 0 ? SUM : (X ^ SUM) >= 0 ? SUM
-                                                     : (x < 0) ? MIN : MAX  */
-  (convert (cond^ (lt (bit_and:c @0 (nop_convert (negate (nop_convert @0))))
-             integer_zerop)
-        INTEGER_CST@2
-        (plus (nop_convert @0) integer_all_onesp@1)))
-   (with
-    {
-     unsigned precision = TYPE_PRECISION (type);
-     wide_int c1 = wi::to_wide (@1);
-     wide_int c2 = wi::to_wide (@2);
-     wide_int sum = wi::add (c1, c2);
-    }
-    (if (wi::eq_p (sum, wi::max_value (precision, SIGNED))))))
-
-(match (signed_integer_sat_add @0 @1)
-  /* T SUM = (T)((UT)X + (UT)IMM)
-     SAT_S_ADD = (X ^ SUM) < 0 && (X ^ IMM) >= 0 ? (-(T)(X < 0) ^ MAX) : SUM  
*/
-   (cond^ (ge (bit_ior:c (bit_xor:c @0 INTEGER_CST@1)
-                       (bit_not (bit_xor:c @0 (nop_convert@2 (plus 
(nop_convert @0)
-                       INTEGER_CST@3)))))
-                   integer_zerop)
-           (signed_integer_sat_val @0)
-           @2)
-   (if (wi::eq_p (wi::to_wide (@1), wi::to_wide (@3))))))
-
-/* Saturation sub for signed integer.  */
-(if (INTEGRAL_TYPE_P (type) && !TYPE_UNSIGNED (type))
- (match (signed_integer_sat_sub @0 @1)
-  /* T Z = (T)((UT)X - (UT)Y);
-     SAT_S_SUB = (X ^ Y) & (X ^ Z) < 0 ? (-(T)(X < 0) ^ MAX) : Z  */
-  (cond^ (lt (bit_and:c (bit_xor:c @0 @1)
-                       (bit_xor @0 (nop_convert@2 (minus (nop_convert @0)
-                                                         (nop_convert @1)))))
-            integer_zerop)
-        (signed_integer_sat_val @0)
-        @2))
- (match (signed_integer_sat_sub @0 @1)
-  /* T Z = (T)((UT)X - (UT)Y);
-     SAT_S_SUB = (X ^ Y) & (X ^ Z) >= 0 ? Z : (-(T)(X < 0) ^ MAX)  */
-  (cond^ (ge (bit_and:c (bit_xor:c @0 @1)
-                       (bit_xor @0 (nop_convert@2 (minus (nop_convert @0)
-                                                         (nop_convert @1)))))
-            integer_zerop)
-        @2
-        (signed_integer_sat_val @0)))
- (match (signed_integer_sat_sub @0 @1)
-  /* T Z = (T)((UT)X - (UT)Y);
-     SAT_S_SUB = (X ^ Y) < 0 & (X ^ Z) < 0 ? (-(T)(X < 0) ^ MAX) : Z  */
-  (cond^ (bit_and:c (lt (bit_xor @0 (nop_convert@2 (minus (nop_convert @0)
-                                                         (nop_convert @1))))
-                       integer_zerop)
-                   (lt (bit_xor:c @0 @1) integer_zerop))
-        (signed_integer_sat_val @0)
-        @2))
- (match (signed_integer_sat_sub @0 @1)
-  /* Z = .SUB_OVERFLOW (X, Y)
-     SAT_S_SUB = IMAGPART (Z) != 0 ? (-(T)(X < 0) ^ MAX) : REALPART (Z)  */
-  (cond^ (ne (imagpart (IFN_SUB_OVERFLOW@2 @0 @1)) integer_zerop)
-        (signed_integer_sat_val @0)
-        (realpart @2))
-  (if (types_match (type, @0, @1)))))
-
-/* Saturation truncate for signed integer.  */
-(if (INTEGRAL_TYPE_P (type) && !TYPE_UNSIGNED (type))
- (match (signed_integer_sat_trunc @0)
-  /* SAT_S_TRUNC(X) = (unsigned)X + NT_MAX + 1  > Unsigned_MAX ? (NT)X  */
-  (cond^ (gt (plus:c (convert@4 @0) INTEGER_CST@1) INTEGER_CST@2)
-        (bit_xor:c (nop_convert?
-                    (negate (nop_convert? (convert (lt @0 integer_zerop)))))
-                   INTEGER_CST@3)
-        (convert @0))
-  (if (!TYPE_UNSIGNED (TREE_TYPE (@0)) && TYPE_UNSIGNED (TREE_TYPE (@4)))
-   (with
-    {
-     unsigned itype_prec = TYPE_PRECISION (TREE_TYPE (@0));
-     unsigned otype_prec = TYPE_PRECISION (type);
-     wide_int offset = wi::uhwi (HOST_WIDE_INT_1U << (otype_prec - 1),
-                                itype_prec); // Aka 128 for int8_t
-     wide_int limit_0 = wi::mask (otype_prec, false, itype_prec); // Aka 255
-     wide_int limit_1 = wi::uhwi ((HOST_WIDE_INT_1U << otype_prec) - 3,
-                                 itype_prec); // Aka 253
-     wide_int limit_2 = wi::uhwi ((HOST_WIDE_INT_1U << otype_prec) - 2,
-                                 itype_prec); // Aka 254
-     wide_int otype_max = wi::mask (otype_prec - 1, false, otype_prec);
-     wide_int itype_max = wi::mask (otype_prec - 1, false, itype_prec);
-     wide_int int_cst_1 = wi::to_wide (@1);
-     wide_int int_cst_2 = wi::to_wide (@2);
-     wide_int int_cst_3 = wi::to_wide (@3);
-    }
-    (if (((wi::eq_p (int_cst_1, offset) && wi::eq_p (int_cst_2, limit_0))
-        || (wi::eq_p (int_cst_1, itype_max) && wi::eq_p (int_cst_2, limit_2))
-        || (wi::eq_p (int_cst_1, offset) && wi::eq_p (int_cst_2, limit_2))
-        || (wi::eq_p (int_cst_1, itype_max) && wi::eq_p (int_cst_2, limit_1)))
-        && wi::eq_p (int_cst_3, otype_max)))))))
-
-/* Saturation mult for unsigned integer.  */
-(if (INTEGRAL_TYPE_P (type) && TYPE_UNSIGNED (type))
- (for mult_op (mult widen_mult)
-  (match (usmul_widen_mult @0 @1)
-   (mult_op:c (convert@2 @0) (convert @1))
-    (if (types_match (@0, @1) && TYPE_UNSIGNED (TREE_TYPE (@0)))
-     (with
-      {
-       unsigned prec = TYPE_PRECISION (TREE_TYPE (@0));
-       unsigned cvt2_prec = TYPE_PRECISION (TREE_TYPE (@2));
-       bool widen_cvt_p = cvt2_prec > prec;
-      }
-      (if (widen_cvt_p))))))
- (match (usmul_widen_mult @0 @1)
-  (widen_mult:c @0 @1)
-   (if (types_match (@0, @1))))
- (match (unsigned_integer_sat_mul @0 @1)
-  /* SAT_U_MUL (X, Y) = {
-       WT x = (WT)a * (WT)b;
-       T max = -1;
-       if (x > (WT)(max))
-        return max;
-       else
-        return (T)x;
-     }
-     while WT is uint128_t, T is uint8_t, uint16_t, uint32_t or uint64_t.  */
-  (convert (min (usmul_widen_mult@3 @0 @1) INTEGER_CST@2))
-  (if (types_match (type, @0, @1))
-   (with
-    {
-      unsigned prec = TYPE_PRECISION (type);
-      unsigned widen_prec = TYPE_PRECISION (TREE_TYPE (@3));
-      wide_int max = wi::mask (prec, false, widen_prec);
-      bool c2_is_max_p = wi::eq_p (wi::to_wide (@2), max);
-    }
-    (if (c2_is_max_p)))))
-  (match (unsigned_integer_sat_mul @0 @1)
-   /* SAT_U_MUL (X, Y) = {
-       T result;
-       if (__builtin_mul_overflow (X, Y, &result))
-         return -1;
-       else
-         return result;
-      }
-      while T can be uint8_t, uint16_t, uint32_t and uint64_t.  */
-   (cond^ (ne (imagpart (IFN_MUL_OVERFLOW:c@2 @0 @1)) integer_zerop)
-          integer_minus_onep (realpart @2))
-   (if (types_match (type, @0, @1))))
-  (match (unsigned_integer_sat_mul @0 @1)
-   /* SAT_U_MUL (X, Y) = {
-       WT x = (WT)a * (WT)b;
-       if ((x >> sizeof(a) * 8) == 0)
-         return (T)x;
-       else
-         return (T)-1;
-      }
-      while WT is uint128_t, T is uint8_t, uint16_t, uint32_t or uint64_t.  */
-   (convert (cond^ (eq (rshift (mult:c@3 (convert @0) (convert @1))
-                              INTEGER_CST@2)
-                      integer_zerop)
-                  @3 INTEGER_CST@4))
-   (if (types_match (type, @0, @1))
-    (with
-     {
-      unsigned prec = TYPE_PRECISION (type);
-      unsigned widen_prec = TYPE_PRECISION (TREE_TYPE (@3));
-      wide_int c4 = wi::to_wide (@4);
-      wide_int max = wi::mask (prec, false, widen_prec);
-      bool c4_is_max_p = wi::eq_p (c4, max);
-      unsigned c2 = tree_to_uhwi (@2);
-      bool c2_is_type_precision_p = c2 == prec;
-     }
-     (if (widen_prec > prec && c2_is_type_precision_p && c4_is_max_p)))))
-  (match (unsigned_integer_sat_mul @0 @1)
-   /* SAT_U_MUL (X, Y) = {
-       WT x = (WT)a * (WT)b;
-       NT hi = x >> (sizeof(NT) * 8);
-       NT lo = (NT)x;
-       return lo | -!!hi;
-      } while WT is uint128_t, uint64_t, uint32_t, uint16_t,
-       and T is uint64_t, uint32_t, uint16_t, uint8_t.  */
-   (bit_ior:c
-    (convert?
-     (negate
-      (convert (ne (convert2? (rshift @3 INTEGER_CST@2)) integer_zerop))))
-    (convert (usmul_widen_mult@3 @0 @1)))
-   (if (types_match (type, @0, @1))
-    (with
-     {
-      unsigned prec = TYPE_PRECISION (type);
-      bool c2_is_type_precision_p = tree_to_uhwi (@2) == prec;
-     }
-     (if (c2_is_type_precision_p)))))
-  (match (unsigned_integer_sat_mul @0 @1)
-   /* SAT_U_MUL (X, Y) = {
-       WT x = (WT)a * (WT)b;
-       NT max = -1;
-       bool overflow_p = x > (WT)max;
-       return -(NT)(overflow_p) | (NT)x;
-      } while WT is uint128_t, uint64_t, uint32_t, uint16_t,
-       and T is uint64_t, uint32_t, uint16_t, uint8_t.  */
-   (bit_ior:c (negate (convert (gt @3 INTEGER_CST@2)))
-             (convert (usmul_widen_mult@3 @0 @1)))
-   (if (types_match (type, @0, @1))
-    (with
-     {
-      unsigned prec = TYPE_PRECISION (type);
-      unsigned widen_prec = TYPE_PRECISION (TREE_TYPE (@3));
-      wide_int max = wi::mask (prec, false, widen_prec);
-      bool c2_is_max_p = wi::eq_p (wi::to_wide (@2), max);
-     }
-     (if (c2_is_max_p)))))
-)
-#endif
-
-/* The boundary condition for case 10: IMM = 1:
-   SAT_U_SUB = X >= IMM ? (X - IMM) : 0.
-   simplify (X != 0 ? X + ~0 : 0) to X - (X != 0).  */
-(simplify
- (cond (ne@1 @0 integer_zerop)
-       (nop_convert1? (plus (nop_convert2?@2 @0) integer_all_onesp))
-       integer_zerop)
- (if (INTEGRAL_TYPE_P (type))
-   (with { tree itype = TREE_TYPE (@2); }
-    (convert (minus @2 (convert:itype @1))))))
-
 /* x >  y  &&  x != XXX_MIN  -->  x > y
    x >  y  &&  x == XXX_MIN  -->  false . */
 (for eqne (eq ne)
@@ -12410,3 +11855,20 @@ and,
 (simplify
  (BUILT_IN_CONSTANT_P (nop_convert@1 @0))
  (BUILT_IN_CONSTANT_P @0))
+
+#if GIMPLE
+
+#include "match-sat-alu.pd"
+
+#endif
+
+/* The boundary condition for case 10: IMM = 1:
+   SAT_U_SUB = X >= IMM ? (X - IMM) : 0.
+   simplify (X != 0 ? X + ~0 : 0) to X - (X != 0).  */
+(simplify
+ (cond (ne@1 @0 integer_zerop)
+       (nop_convert1? (plus (nop_convert2?@2 @0) integer_all_onesp))
+       integer_zerop)
+ (if (INTEGRAL_TYPE_P (type))
+   (with { tree itype = TREE_TYPE (@2); }
+    (convert (minus @2 (convert:itype @1))))))
-- 
2.43.0

Reply via email to