[gcc r15-1030] Internal-fn: Support new IFN SAT_SUB for unsigned scalar int

Pan Li panli@gcc.gnu.org
Wed Jun 5 08:38:42 GMT 2024


https://gcc.gnu.org/g:abe6d39365476e6be724815d09d072e305018755

commit r15-1030-gabe6d39365476e6be724815d09d072e305018755
Author: Pan Li <pan2.li@intel.com>
Date:   Tue May 28 15:37:44 2024 +0800

    Internal-fn: Support new IFN SAT_SUB for unsigned scalar int
    
    This patch would like to add the middle-end presentation for the
    saturation sub.  Aka set the result of add to the min when downflow.
    It will take the pattern similar as below.
    
    SAT_SUB (x, y) => (x - y) & (-(TYPE)(x >= y));
    
    For example for uint8_t, we have
    
    * SAT_SUB (255, 0)   => 255
    * SAT_SUB (1, 2)     => 0
    * SAT_SUB (254, 255) => 0
    * SAT_SUB (0, 255)   => 0
    
    Given below SAT_SUB for uint64
    
    uint64_t sat_sub_u64 (uint64_t x, uint64_t y)
    {
      return (x - y) & (-(TYPE)(x >= y));
    }
    
    Before this patch:
    uint64_t sat_sub_u_0_uint64_t (uint64_t x, uint64_t y)
    {
      _Bool _1;
      long unsigned int _3;
      uint64_t _6;
    
    ;;   basic block 2, loop depth 0
    ;;    pred:       ENTRY
      _1 = x_4(D) >= y_5(D);
      _3 = x_4(D) - y_5(D);
      _6 = _1 ? _3 : 0;
      return _6;
    ;;    succ:       EXIT
    }
    
    After this patch:
    uint64_t sat_sub_u_0_uint64_t (uint64_t x, uint64_t y)
    {
      uint64_t _6;
    
    ;;   basic block 2, loop depth 0
    ;;    pred:       ENTRY
      _6 = .SAT_SUB (x_4(D), y_5(D)); [tail call]
      return _6;
    ;;    succ:       EXIT
    }
    
    The below tests are running for this patch:
    *. The riscv fully regression tests.
    *. The x86 bootstrap tests.
    *. The x86 fully regression tests.
    
            PR target/51492
            PR target/112600
    
    gcc/ChangeLog:
    
            * internal-fn.def (SAT_SUB): Add new IFN define for SAT_SUB.
            * match.pd: Add new match for SAT_SUB.
            * optabs.def (OPTAB_NL): Remove fixed-point for ussub/ssub.
            * tree-ssa-math-opts.cc (gimple_unsigned_integer_sat_sub): Add
            new decl for generated in match.pd.
            (build_saturation_binary_arith_call): Add new helper function
            to build the gimple call to binary SAT alu.
            (match_saturation_arith): Rename from.
            (match_unsigned_saturation_add): Rename to.
            (match_unsigned_saturation_sub): Add new func to match the
            unsigned sat sub.
            (math_opts_dom_walker::after_dom_children): Add SAT_SUB matching
            try when COND_EXPR.
    
    Signed-off-by: Pan Li <pan2.li@intel.com>

Diff:
---
 gcc/internal-fn.def       |  1 +
 gcc/match.pd              | 14 ++++++++++
 gcc/optabs.def            |  4 +--
 gcc/tree-ssa-math-opts.cc | 67 +++++++++++++++++++++++++++++++++--------------
 4 files changed, 64 insertions(+), 22 deletions(-)

diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def
index 8de1fa882e9..a8c83437ada 100644
--- a/gcc/internal-fn.def
+++ b/gcc/internal-fn.def
@@ -276,6 +276,7 @@ DEF_INTERNAL_SIGNED_OPTAB_FN (MULHRS, ECF_CONST | ECF_NOTHROW, first,
 			      smulhrs, umulhrs, binary)
 
 DEF_INTERNAL_SIGNED_OPTAB_FN (SAT_ADD, ECF_CONST, first, ssadd, usadd, binary)
+DEF_INTERNAL_SIGNED_OPTAB_FN (SAT_SUB, ECF_CONST, first, sssub, ussub, binary)
 
 DEF_INTERNAL_COND_FN (ADD, ECF_CONST, add, binary)
 DEF_INTERNAL_COND_FN (SUB, ECF_CONST, sub, binary)
diff --git a/gcc/match.pd b/gcc/match.pd
index f19ef702747..7c1ad428a3c 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -3096,6 +3096,20 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 (match (unsigned_integer_sat_add @0 @1)
  (bit_ior:c (usadd_left_part_2 @0 @1) (usadd_right_part_2 @0 @1)))
 
+/* Unsigned saturation sub, case 1 (branch with gt):
+   SAT_U_SUB = X > Y ? X - Y : 0  */
+(match (unsigned_integer_sat_sub @0 @1)
+ (cond (gt @0 @1) (minus @0 @1) integer_zerop)
+ (if (INTEGRAL_TYPE_P (type) && TYPE_UNSIGNED (type)
+      && types_match (type, @0, @1))))
+
+/* Unsigned saturation sub, case 2 (branch with ge):
+   SAT_U_SUB = X >= Y ? X - Y : 0.  */
+(match (unsigned_integer_sat_sub @0 @1)
+ (cond (ge @0 @1) (minus @0 @1) integer_zerop)
+ (if (INTEGRAL_TYPE_P (type) && TYPE_UNSIGNED (type)
+      && types_match (type, @0, @1))))
+
 /* x >  y  &&  x != XXX_MIN  -->  x > y
    x >  y  &&  x == XXX_MIN  -->  false . */
 (for eqne (eq ne)
diff --git a/gcc/optabs.def b/gcc/optabs.def
index 3f2cb46aff8..bc2611abdc2 100644
--- a/gcc/optabs.def
+++ b/gcc/optabs.def
@@ -118,8 +118,8 @@ OPTAB_NX(sub_optab, "sub$F$a3")
 OPTAB_NX(sub_optab, "sub$Q$a3")
 OPTAB_VL(subv_optab, "subv$I$a3", MINUS, "sub", '3', gen_intv_fp_libfunc)
 OPTAB_VX(subv_optab, "sub$F$a3")
-OPTAB_NL(sssub_optab, "sssub$Q$a3", SS_MINUS, "sssub", '3', gen_signed_fixed_libfunc)
-OPTAB_NL(ussub_optab, "ussub$Q$a3", US_MINUS, "ussub", '3', gen_unsigned_fixed_libfunc)
+OPTAB_NL(sssub_optab, "sssub$a3", SS_MINUS, "sssub", '3', gen_signed_fixed_libfunc)
+OPTAB_NL(ussub_optab, "ussub$a3", US_MINUS, "ussub", '3', gen_unsigned_fixed_libfunc)
 OPTAB_NL(smul_optab, "mul$Q$a3", MULT, "mul", '3', gen_int_fp_fixed_libfunc)
 OPTAB_NX(smul_optab, "mul$P$a3")
 OPTAB_NX(smul_optab, "mul$F$a3")
diff --git a/gcc/tree-ssa-math-opts.cc b/gcc/tree-ssa-math-opts.cc
index 57d51fd01ee..469e34d828d 100644
--- a/gcc/tree-ssa-math-opts.cc
+++ b/gcc/tree-ssa-math-opts.cc
@@ -4087,33 +4087,56 @@ arith_overflow_check_p (gimple *stmt, gimple *cast_stmt, gimple *&use_stmt,
 }
 
 extern bool gimple_unsigned_integer_sat_add (tree, tree*, tree (*)(tree));
+extern bool gimple_unsigned_integer_sat_sub (tree, tree*, tree (*)(tree));
+
+static void
+build_saturation_binary_arith_call (gimple_stmt_iterator *gsi, internal_fn fn,
+				    tree lhs, tree op_0, tree op_1)
+{
+  if (direct_internal_fn_supported_p (fn, TREE_TYPE (lhs), OPTIMIZE_FOR_BOTH))
+    {
+      gcall *call = gimple_build_call_internal (fn, 2, op_0, op_1);
+      gimple_call_set_lhs (call, lhs);
+      gsi_replace (gsi, call, /* update_eh_info */ true);
+    }
+}
 
 /*
- * Try to match saturation arith pattern(s).
- *   1. SAT_ADD (unsigned)
- *      _7 = _4 + _6;
- *      _8 = _4 > _7;
- *      _9 = (long unsigned int) _8;
- *      _10 = -_9;
- *      _12 = _7 | _10;
- *      =>
- *      _12 = .SAT_ADD (_4, _6);  */
+ * Try to match saturation unsigned add.
+ *   _7 = _4 + _6;
+ *   _8 = _4 > _7;
+ *   _9 = (long unsigned int) _8;
+ *   _10 = -_9;
+ *   _12 = _7 | _10;
+ *   =>
+ *   _12 = .SAT_ADD (_4, _6);  */
+
 static void
-match_saturation_arith (gimple_stmt_iterator *gsi, gassign *stmt)
+match_unsigned_saturation_add (gimple_stmt_iterator *gsi, gassign *stmt)
 {
-  gcall *call = NULL;
+  tree ops[2];
+  tree lhs = gimple_assign_lhs (stmt);
 
+  if (gimple_unsigned_integer_sat_add (lhs, ops, NULL))
+    build_saturation_binary_arith_call (gsi, IFN_SAT_ADD, lhs, ops[0], ops[1]);
+}
+
+/*
+ * Try to match saturation unsigned sub.
+ *   _1 = _4 >= _5;
+ *   _3 = _4 - _5;
+ *   _6 = _1 ? _3 : 0;
+ *   =>
+ *   _6 = .SAT_SUB (_4, _5);  */
+
+static void
+match_unsigned_saturation_sub (gimple_stmt_iterator *gsi, gassign *stmt)
+{
   tree ops[2];
   tree lhs = gimple_assign_lhs (stmt);
 
-  if (gimple_unsigned_integer_sat_add (lhs, ops, NULL)
-      && direct_internal_fn_supported_p (IFN_SAT_ADD, TREE_TYPE (lhs),
-					 OPTIMIZE_FOR_BOTH))
-    {
-      call = gimple_build_call_internal (IFN_SAT_ADD, 2, ops[0], ops[1]);
-      gimple_call_set_lhs (call, lhs);
-      gsi_replace (gsi, call, true);
-    }
+  if (gimple_unsigned_integer_sat_sub (lhs, ops, NULL))
+    build_saturation_binary_arith_call (gsi, IFN_SAT_SUB, lhs, ops[0], ops[1]);
 }
 
 /* Recognize for unsigned x
@@ -6078,7 +6101,7 @@ math_opts_dom_walker::after_dom_children (basic_block bb)
 	      break;
 
 	    case BIT_IOR_EXPR:
-	      match_saturation_arith (&gsi, as_a<gassign *> (stmt));
+	      match_unsigned_saturation_add (&gsi, as_a<gassign *> (stmt));
 	      /* fall-through  */
 	    case BIT_XOR_EXPR:
 	      match_uaddc_usubc (&gsi, stmt, code);
@@ -6089,6 +6112,10 @@ math_opts_dom_walker::after_dom_children (basic_block bb)
 	      match_single_bit_test (&gsi, stmt);
 	      break;
 
+	    case COND_EXPR:
+	      match_unsigned_saturation_sub (&gsi, as_a<gassign *> (stmt));
+	      break;
+
 	    default:;
 	    }
 	}


More information about the Gcc-cvs mailing list