https://gcc.gnu.org/g:2b82af511b4c77d4b4387e3b01e5fe18847c3a8e
commit r17-444-g2b82af511b4c77d4b4387e3b01e5fe18847c3a8e Author: Pan Li <[email protected]> Date: Fri May 8 09:41:01 2026 +0800 Match: Move saturation alu patterns into match-sat-alu.pd [NFC] Given there are lots of sat alu patterns in match.pd, and there will more in short future. Move all of them into a separated file for better org. The below test suites are passed for this patch: 1. The rv64gcv fully regression tests. 2. The x86 bootstrap tests. 3. The x86 fully regression tests. gcc/ChangeLog: * Makefile.in: Add match-sat-alu.pd as dependency. * match.pd: Remove saturation alu related patterns. * match-sat-alu.pd: Add new file for saturation alu patterns. Signed-off-by: Pan Li <[email protected]> Diff: --- gcc/Makefile.in | 2 +- gcc/match-sat-alu.pd | 566 ++++++++++++++++++++++++++++++++++++++++++++++++++ gcc/match.pd | 573 ++------------------------------------------------- 3 files changed, 585 insertions(+), 556 deletions(-) diff --git a/gcc/Makefile.in b/gcc/Makefile.in index a89c5278a238..3246a1808d20 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -3056,7 +3056,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 000000000000..483c37b6d9f6 --- /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 198e2e7202e8..05095c43cede 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -3329,561 +3329,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) @@ -12472,3 +11917,21 @@ and, (simplify (BUILT_IN_CONSTANT_P (nop_convert@1 @0)) (BUILT_IN_CONSTANT_P @0)) + +#if GIMPLE + +/* Include the saturation alu match patterns. */ +#include "match-sat-alu.pd" + +#endif + +/* The boundary condition for case 10: IMM = 1: + SAT_U_SUB = X >= IMM ? (X - IMM) : 0. + simplify (X != 0 ? X + ~0 : 0) to X - (X != 0). */ +(simplify + (cond (ne@1 @0 integer_zerop) + (nop_convert1? (plus (nop_convert2?@2 @0) integer_all_onesp)) + integer_zerop) + (if (INTEGRAL_TYPE_P (type)) + (with { tree itype = TREE_TYPE (@2); } + (convert (minus @2 (convert:itype @1))))))
