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)
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;
--- /dev/null
+/* 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" } } */