public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] builtins: Force SAVE_EXPR for __builtin_{add,sub,mul}_overflow and __builtin{add,sub}c [PR108789]
@ 2024-06-04  6:24 Jakub Jelinek
  2024-06-04  7:05 ` Richard Biener
  0 siblings, 1 reply; 2+ messages in thread
From: Jakub Jelinek @ 2024-06-04  6:24 UTC (permalink / raw)
  To: Richard Biener; +Cc: gcc-patches

Hi!

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).

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

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.

--- gcc/builtins.cc.jj	2024-04-05 09:19:47.899050410 +0200
+++ gcc/builtins.cc	2024-06-03 17:27:11.071693074 +0200
@@ -10042,7 +10042,21 @@ fold_builtin_arith_overflow (location_t
       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,
   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);
--- gcc/testsuite/gcc.c-torture/execute/pr108789.c.jj	2024-06-03 17:15:01.143366766 +0200
+++ gcc/testsuite/gcc.c-torture/execute/pr108789.c	2024-06-03 17:12:55.189036744 +0200
@@ -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 ();
+}

	Jakub


^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [PATCH] builtins: Force SAVE_EXPR for __builtin_{add,sub,mul}_overflow and __builtin{add,sub}c [PR108789]
  2024-06-04  6:24 [PATCH] builtins: Force SAVE_EXPR for __builtin_{add,sub,mul}_overflow and __builtin{add,sub}c [PR108789] Jakub Jelinek
@ 2024-06-04  7:05 ` Richard Biener
  0 siblings, 0 replies; 2+ messages in thread
From: Richard Biener @ 2024-06-04  7:05 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches

On Tue, 4 Jun 2024, Jakub Jelinek wrote:

> Hi!
> 
> 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).
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

OK.

Thanks,
Richard.

> 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.
> 
> --- gcc/builtins.cc.jj	2024-04-05 09:19:47.899050410 +0200
> +++ gcc/builtins.cc	2024-06-03 17:27:11.071693074 +0200
> @@ -10042,7 +10042,21 @@ fold_builtin_arith_overflow (location_t
>        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,
>    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);
> --- gcc/testsuite/gcc.c-torture/execute/pr108789.c.jj	2024-06-03 17:15:01.143366766 +0200
> +++ gcc/testsuite/gcc.c-torture/execute/pr108789.c	2024-06-03 17:12:55.189036744 +0200
> @@ -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 ();
> +}
> 
> 	Jakub
> 
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE Software Solutions Germany GmbH,
Frankenstrasse 146, 90461 Nuernberg, Germany;
GF: Ivo Totev, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2024-06-04  7:05 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-06-04  6:24 [PATCH] builtins: Force SAVE_EXPR for __builtin_{add,sub,mul}_overflow and __builtin{add,sub}c [PR108789] Jakub Jelinek
2024-06-04  7:05 ` Richard Biener

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).