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