https://gcc.gnu.org/g:b20f5c7760e4c5032e8f9d84145d3be7d0238029
commit r17-459-gb20f5c7760e4c5032e8f9d84145d3be7d0238029 Author: Naveen <[email protected]> Date: Mon May 11 21:08:11 2026 -0700 tree-optimization: Fold SAT_ADD at gimple level 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 <[email protected]> Diff: --- gcc/fold-const-call.cc | 35 +++++++++++++++++++++++++++++++++++ gcc/genmatch.cc | 1 + gcc/match.pd | 5 +++++ gcc/testsuite/gcc.dg/pr123286.c | 33 +++++++++++++++++++++++++++++++++ 4 files changed, 74 insertions(+) diff --git a/gcc/fold-const-call.cc b/gcc/fold-const-call.cc index 7dd1b21c34f3..cc2defcd5bc9 100644 --- a/gcc/fold-const-call.cc +++ b/gcc/fold-const-call.cc @@ -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; diff --git a/gcc/genmatch.cc b/gcc/genmatch.cc index 633ff9e1db21..6c267ca8dc2a 100644 --- a/gcc/genmatch.cc +++ b/gcc/genmatch.cc @@ -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: diff --git a/gcc/match.pd b/gcc/match.pd index 05095c43cede..e27d7b75466d 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -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 index 000000000000..d6689aa91d4a --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr123286.c @@ -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" } } */
