]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
tree-optimization: Fold SAT_ADD at gimple level
authorNaveen <naveen.siddegowda@oss.qualcomm.com>
Tue, 12 May 2026 04:08:11 +0000 (21:08 -0700)
committerNaveen <naveen.siddegowda@oss.qualcomm.com>
Tue, 12 May 2026 04:10:31 +0000 (21:10 -0700)
Extend scalar SAT_ADD constant folding to recognize cases where one operand is
zero. It allows SAT_ADD expressions with constant operands to fold away early.
The change improves optimization opportunities and avoids emitting unnecessary
SAT_ADD operations.
Bootstrapped and tested on aarch64-linux-gnu.

PR middle-end/123286

gcc/ChangeLog:
* fold-const-call.cc (fold_internal_fn_sat_add): New function.
(fold_const_call): Handle CFN_SAT_ADD.
* match.pd: Add simplifications for x SAT_ADD 0 == x.
* genmatch.cc (commutative_op): Add CFN_SAT_ADD.

gcc/testsuite/ChangeLog:
* gcc.dg/pr123286.c: New test.

Signed-off-by: Naveen <naveen.siddegowda@oss.qualcomm.com>
gcc/fold-const-call.cc
gcc/genmatch.cc
gcc/match.pd
gcc/testsuite/gcc.dg/pr123286.c [new file with mode: 0644]

index 7dd1b21c34f35a0c571c948f3381d1aa30660fc1..cc2defcd5bc9385cd536f294ab2d76ce8b7b7326 100644 (file)
@@ -1477,6 +1477,38 @@ fold_const_vec_extract (tree, tree arg0, tree)
   return NULL_TREE;
 }
 
+/* Try to fold scalar integer IFN_SAT_ADD with operands OP0 and OP1.  */
+
+static tree
+fold_internal_fn_sat_add (tree type, tree op0, tree op1)
+{
+  if (!INTEGRAL_NB_TYPE_P (type))
+    return NULL_TREE;
+
+  if (TREE_CODE (op0) != INTEGER_CST
+      || TREE_CODE (op1) != INTEGER_CST)
+    return NULL_TREE;
+
+  wi::overflow_type overflow;
+  unsigned int prec = TYPE_PRECISION (type);
+  wide_int result = wi::add (wi::to_wide (op0), wi::to_wide (op1),
+                            TYPE_SIGN (type), &overflow);
+
+  if (overflow != wi::OVF_NONE)
+    {
+      if (TYPE_UNSIGNED (type))
+       result = wi::max_value (prec, UNSIGNED);
+      else if (overflow == wi::OVF_OVERFLOW)
+       result = wi::max_value (prec, SIGNED);
+      else if (overflow == wi::OVF_UNDERFLOW)
+       result = wi::min_value (prec, SIGNED);
+      else
+       return NULL_TREE;
+    }
+
+  return wide_int_to_tree (type, result);
+}
+
 /* Try to evaluate:
 
       *RESULT = FN (*ARG0, *ARG1)
@@ -1886,6 +1918,9 @@ fold_const_call (combined_fn fn, tree type, tree arg0, tree arg1)
     case CFN_VEC_EXTRACT:
       return fold_const_vec_extract (type, arg0, arg1);
 
+    case CFN_SAT_ADD:
+      return fold_internal_fn_sat_add (type, arg0, arg1);
+
     case CFN_UBSAN_CHECK_ADD:
     case CFN_ADD_OVERFLOW:
       subcode = PLUS_EXPR;
index 633ff9e1db2192b7bc0fda1879767b12cb43ab82..6c267ca8dc2a4f25d4eb7bba034fcce02f760cd7 100644 (file)
@@ -1268,6 +1268,7 @@ commutative_op (id_base *id, bool compares_are_commutative = false)
       case CFN_FNMS:
       case CFN_ADD_OVERFLOW:
       case CFN_MUL_OVERFLOW:
+      case CFN_SAT_ADD:
        return 0;
 
       case CFN_COND_ADD:
index 05095c43cede86e2a341d1f69be4e93c0748971d..e27d7b75466da43a0cf3e79d86634599a7b6c01a 100644 (file)
@@ -8383,6 +8383,11 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
        && TYPE_UNSIGNED (TREE_TYPE (@0)))
    (cmp @1 @0))))
 
+/* x SAT_ADD 0 == x.  */
+(simplify
+ (IFN_SAT_ADD:c @0 integer_zerop)
+  @0)
+
 /* Optimize A - B + -1 >= A into B >= A for unsigned comparisons.  */
 (for cmp (ge lt)
  (simplify
diff --git a/gcc/testsuite/gcc.dg/pr123286.c b/gcc/testsuite/gcc.dg/pr123286.c
new file mode 100644 (file)
index 0000000..d6689aa
--- /dev/null
@@ -0,0 +1,33 @@
+/* PR middle-end/123286 */
+/* { dg-do compile } */
+/* { dg-additional-options "-O2 -fdump-tree-optimized" } */
+
+#include <arm_neon.h>
+#include <stdint.h>
+
+uint64_t
+f1 (uint64_t a)
+{
+  uint64x1_t va;
+  uint64x1_t vz;
+
+  va = vdup_n_u64 (a);
+  vz = vdup_n_u64 (0);
+
+  return vqadd_u64 (va, vz)[0];
+}
+
+uint64_t
+f2 (uint64_t a)
+{
+  uint64x1_t va;
+  uint64x1_t vz;
+
+  va = vdup_n_u64 (0);
+  vz = vdup_n_u64 (a);
+
+  return vqadd_u64 (va, vz)[0];
+}
+
+/* Both SAT_ADD calls should fold away.  */
+/* { dg-final { scan-tree-dump-not "\\.SAT_ADD" "optimized" } } */