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 >
