> Add a small comment on what is being included here.
> Like:
> /* Include the saturation alu match patterns.  */

Thanks Pinski, will commit with the comment if OK from Richard.

Pan

-----Original Message-----
From: Andrew Pinski <[email protected]> 
Sent: Saturday, May 9, 2026 7:55 AM
To: Li, Pan2 <[email protected]>
Cc: [email protected]; [email protected]; [email protected]; 
[email protected]; [email protected]; Chen, Ken <[email protected]>; 
Liu, Hongtao <[email protected]>; [email protected]
Subject: Re: [PATCH v2] Match: Move saturation alu patterns into 
match-sat-alu.pd [NFC]

On Fri, May 8, 2026 at 4:26 PM <[email protected]> wrote:
>
> 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.

LGTM. Give Richard B. until Tuesday to review it.
Just a small change I request ...

>
> 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

Add a small comment on what is being included here.
Like:
/* Include the saturation alu match patterns.  */

Thanks,
Andrea

> +
> +/* 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