On Sat, May 9, 2026 at 2:09 AM Li, Pan2 <[email protected]> wrote: > > > 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.
LGTM > 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 > >
