]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Widening-Mul: Support unsigned scalar SAT_MUL form 1
authorPan Li <pan2.li@intel.com>
Wed, 2 Jul 2025 01:59:26 +0000 (09:59 +0800)
committerPan Li <pan2.li@intel.com>
Mon, 7 Jul 2025 13:15:25 +0000 (21:15 +0800)
This patch would like to try to match the SAT_MUL during
widening-mul pass, aka below pattern.

  NT __attribute__((noinline))
  sat_u_mul_##NT##_fmt_1 (NT a, NT b)
  {
    uint128_t x = (uint128_t)a * (uint128_t)b;
    NT max = -1;
    if (x > (uint128_t)(max))
      return max;
    else
      return (NT)x;
  }

while the NT can be uint8_t, uint16_t, uint32_t and uint64_t.

gcc/ChangeLog:

* match.pd: Add new match pattern for unsigned SAT_MUL.
* tree-ssa-math-opts.cc (gimple_unsigned_integer_sat_mul):
new decl for pattern match func.
(match_unsigned_saturation_mul): Add new func to match unsigned
SAT_MUL.
(math_opts_dom_walker::after_dom_children): Try to match
unsigned SAT_MUL on NOP.

Signed-off-by: Pan Li <pan2.li@intel.com>
gcc/match.pd
gcc/tree-ssa-math-opts.cc

index 10c2b97f494ecc741aa607ad253ee22e3184cb12..ec2f5603d9c06fea5caf0e584ec5e8310026a7df 100644 (file)
@@ -3583,6 +3583,37 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
         || (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))
+  (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@4 (min (widen_mult:c@3 (convert@5 (convert @0))
+                                  (convert@6 (convert @1)))
+                  INTEGER_CST@2))
+   (if (types_match (type, @0, @1) && types_match (type, @4))
+    (with
+     {
+      unsigned prec = TYPE_PRECISION (type);
+      unsigned widen_prec = TYPE_PRECISION (TREE_TYPE (@3));
+      unsigned cvt5_prec = TYPE_PRECISION (TREE_TYPE (@5));
+      unsigned cvt6_prec = TYPE_PRECISION (TREE_TYPE (@6));
+      unsigned hw_int_prec = sizeof (HOST_WIDE_INT) * 8;
+      wide_int c2 = wi::to_wide (@2);
+      wide_int max = wi::mask (prec, false, widen_prec);
+      bool c2_is_max_p = wi::eq_p (c2, max);
+      bool widen_mult_p = cvt5_prec == cvt6_prec && hw_int_prec == cvt5_prec;
+     }
+     (if (widen_prec > prec && c2_is_max_p && widen_mult_p)))))
+)
+
 /* 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).  */
index 4cfcc420fea5090b8e2719d094b6e1c620ba4cf5..ca98205d58f8685d8589bcc054a87bee7510203a 100644 (file)
@@ -4064,6 +4064,7 @@ 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));
 extern bool gimple_unsigned_integer_sat_trunc (tree, tree*, tree (*)(tree));
+extern bool gimple_unsigned_integer_sat_mul (tree, tree*, tree (*)(tree));
 
 extern bool gimple_signed_integer_sat_add (tree, tree*, tree (*)(tree));
 extern bool gimple_signed_integer_sat_sub (tree, tree*, tree (*)(tree));
@@ -4216,6 +4217,30 @@ match_unsigned_saturation_sub (gimple_stmt_iterator *gsi, gassign *stmt)
                                                    ops[0], ops[1]);
 }
 
+/*
+ * Try to match saturation unsigned mul.
+ *   _1 = (unsigned int) a_6(D);
+ *   _2 = (unsigned int) b_7(D);
+ *   x_8 = _1 * _2;
+ *   overflow_9 = x_8 > 255;
+ *   _3 = (unsigned char) overflow_9;
+ *   _4 = -_3;
+ *   _5 = (unsigned char) x_8;
+ *   _10 = _4 | _5;
+ *   =>
+ *   _10 = .SAT_SUB (a_6, b_7);  */
+
+static void
+match_unsigned_saturation_mul (gimple_stmt_iterator *gsi, gassign *stmt)
+{
+  tree ops[2];
+  tree lhs = gimple_assign_lhs (stmt);
+
+  if (gimple_unsigned_integer_sat_mul (lhs, ops, NULL))
+    build_saturation_binary_arith_call_and_replace (gsi, IFN_SAT_MUL, lhs,
+                                                   ops[0], ops[1]);
+}
+
 /*
  * Try to match saturation unsigned sub.
  *  <bb 2> [local count: 1073741824]:
@@ -6469,6 +6494,7 @@ math_opts_dom_walker::after_dom_children (basic_block bb)
              break;
 
            case NOP_EXPR:
+             match_unsigned_saturation_mul (&gsi, as_a<gassign *> (stmt));
              match_unsigned_saturation_trunc (&gsi, as_a<gassign *> (stmt));
              match_saturation_add_with_assign (&gsi, as_a<gassign *> (stmt));
              break;