[gcc r15-1009] builtins: Force SAVE_EXPR for __builtin_{add, sub, mul}_overflow and __builtin{add, sub}c [PR108789]
Jakub Jelinek
jakub@gcc.gnu.org
Tue Jun 4 10:28:50 GMT 2024
https://gcc.gnu.org/g:b8e28381cb5c0cddfe5201faf799d8b27f5d7d6c
commit r15-1009-gb8e28381cb5c0cddfe5201faf799d8b27f5d7d6c
Author: Jakub Jelinek <jakub@redhat.com>
Date: Tue Jun 4 12:28:01 2024 +0200
builtins: Force SAVE_EXPR for __builtin_{add,sub,mul}_overflow and __builtin{add,sub}c [PR108789]
The following testcase is miscompiled, because we use save_expr
on the .{ADD,SUB,MUL}_OVERFLOW call we are creating, but if the first
two operands are not INTEGER_CSTs (in that case we just fold it right away)
but are TREE_READONLY/!TREE_SIDE_EFFECTS, save_expr doesn't actually
create a SAVE_EXPR at all and so we lower it to
*arg2 = REALPART_EXPR (.ADD_OVERFLOW (arg0, arg1)), \
IMAGPART_EXPR (.ADD_OVERFLOW (arg0, arg1))
which evaluates the ifn twice and just hope it will be CSEd back.
As *arg2 aliases *arg0, that is not the case.
The builtins are really never const/pure as they store into what
the third arguments points to, so after handling the INTEGER_CST+INTEGER_CST
case, I think we should just always use SAVE_EXPR. Just building SAVE_EXPR
by hand and setting TREE_SIDE_EFFECTS on it doesn't work, because
c_fully_fold optimizes it away again, so the following patch marks the
ifn calls as TREE_SIDE_EFFECTS (but doesn't do it for the
__builtin_{add,sub,mul}_overflow_p case which were designed for use
especially in constant expressions and don't really evaluate the
realpart side, so we don't really need a SAVE_EXPR in that case).
2024-06-04 Jakub Jelinek <jakub@redhat.com>
PR middle-end/108789
* builtins.cc (fold_builtin_arith_overflow): For ovf_only,
don't call save_expr and don't build REALPART_EXPR, otherwise
set TREE_SIDE_EFFECTS on call before calling save_expr.
(fold_builtin_addc_subc): Set TREE_SIDE_EFFECTS on call before
calling save_expr.
* gcc.c-torture/execute/pr108789.c: New test.
Diff:
---
gcc/builtins.cc | 22 ++++++++++++++-
gcc/testsuite/gcc.c-torture/execute/pr108789.c | 39 ++++++++++++++++++++++++++
2 files changed, 60 insertions(+), 1 deletion(-)
diff --git a/gcc/builtins.cc b/gcc/builtins.cc
index 00ee9eb2925..5b5307c67b8 100644
--- a/gcc/builtins.cc
+++ b/gcc/builtins.cc
@@ -10042,7 +10042,21 @@ fold_builtin_arith_overflow (location_t loc, enum built_in_function fcode,
tree ctype = build_complex_type (type);
tree call = build_call_expr_internal_loc (loc, ifn, ctype, 2,
arg0, arg1);
- tree tgt = save_expr (call);
+ tree tgt;
+ if (ovf_only)
+ {
+ tgt = call;
+ intres = NULL_TREE;
+ }
+ else
+ {
+ /* Force SAVE_EXPR even for calls which satisfy tree_invariant_p_1,
+ as while the call itself is const, the REALPART_EXPR store is
+ certainly not. And in any case, we want just one call,
+ not multiple and trying to CSE them later. */
+ TREE_SIDE_EFFECTS (call) = 1;
+ tgt = save_expr (call);
+ }
intres = build1_loc (loc, REALPART_EXPR, type, tgt);
ovfres = build1_loc (loc, IMAGPART_EXPR, type, tgt);
ovfres = fold_convert_loc (loc, boolean_type_node, ovfres);
@@ -10354,11 +10368,17 @@ fold_builtin_addc_subc (location_t loc, enum built_in_function fcode,
tree ctype = build_complex_type (type);
tree call = build_call_expr_internal_loc (loc, ifn, ctype, 2,
args[0], args[1]);
+ /* Force SAVE_EXPR even for calls which satisfy tree_invariant_p_1,
+ as while the call itself is const, the REALPART_EXPR store is
+ certainly not. And in any case, we want just one call,
+ not multiple and trying to CSE them later. */
+ TREE_SIDE_EFFECTS (call) = 1;
tree tgt = save_expr (call);
tree intres = build1_loc (loc, REALPART_EXPR, type, tgt);
tree ovfres = build1_loc (loc, IMAGPART_EXPR, type, tgt);
call = build_call_expr_internal_loc (loc, ifn, ctype, 2,
intres, args[2]);
+ TREE_SIDE_EFFECTS (call) = 1;
tgt = save_expr (call);
intres = build1_loc (loc, REALPART_EXPR, type, tgt);
tree ovfres2 = build1_loc (loc, IMAGPART_EXPR, type, tgt);
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr108789.c b/gcc/testsuite/gcc.c-torture/execute/pr108789.c
new file mode 100644
index 00000000000..32ee19be1c4
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/pr108789.c
@@ -0,0 +1,39 @@
+/* PR middle-end/108789 */
+
+int
+add (unsigned *r, const unsigned *a, const unsigned *b)
+{
+ return __builtin_add_overflow (*a, *b, r);
+}
+
+int
+mul (unsigned *r, const unsigned *a, const unsigned *b)
+{
+ return __builtin_mul_overflow (*a, *b, r);
+}
+
+int
+main ()
+{
+ unsigned x;
+
+ /* 1073741824U + 1073741824U should not overflow. */
+ x = (__INT_MAX__ + 1U) / 2;
+ if (add (&x, &x, &x))
+ __builtin_abort ();
+
+ /* 256U * 256U should not overflow */
+ x = 1U << (sizeof (int) * __CHAR_BIT__ / 4);
+ if (mul (&x, &x, &x))
+ __builtin_abort ();
+
+ /* 2147483648U + 2147483648U should overflow */
+ x = __INT_MAX__ + 1U;
+ if (!add (&x, &x, &x))
+ __builtin_abort ();
+
+ /* 65536U * 65536U should overflow */
+ x = 1U << (sizeof (int) * __CHAR_BIT__ / 2);
+ if (!mul (&x, &x, &x))
+ __builtin_abort ();
+}
More information about the Gcc-cvs
mailing list