Patchwork Fix extract_muldiv (PR tree-optimization/56899)

login
register
mail settings
Submitter Jakub Jelinek
Date April 10, 2013, 3:31 p.m.
Message ID <20130410153114.GE16463@tucnak.redhat.com>
Download mbox | patch
Permalink /patch/235408/
State New
Headers show

Comments

Jakub Jelinek - April 10, 2013, 3:31 p.m.
Hi!

As f1 in the testcase shows, applying distributive law in extract_muldiv_1
isn't safe if overflow behavior isn't defined, if we have
(op0 + c1) * c2
and the type is signed, we can't just try to fold that to
op0 * c2 + (c1 * c2)
even when we know that c1*c2 doesn't overflow, because op0 * c2
might overflow even when (op0 + c1) * c2 doesn't.

Fixed thusly, after all that hunk of code is often soon undone by
fold_build2 again or later during GIMPLE optimizations,
bootstrapped/regtested on x86_64-linux and i686-linux, ok
for trunk/4.8?

2013-04-10  Jakub Jelinek  <jakub@redhat.com>

	PR tree-optimization/56899
	* fold-const.c (extract_muldiv_1): Apply distributive law
	only if TYPE_OVERFLOW_WRAPS (ctype).

	* gcc.c-torture/execute/pr56899.c: New test.


	Jakub
Jeff Law - April 10, 2013, 6:38 p.m.
On 04/10/2013 09:31 AM, Jakub Jelinek wrote:
> Hi!
>
> As f1 in the testcase shows, applying distributive law in extract_muldiv_1
> isn't safe if overflow behavior isn't defined, if we have
> (op0 + c1) * c2
> and the type is signed, we can't just try to fold that to
> op0 * c2 + (c1 * c2)
> even when we know that c1*c2 doesn't overflow, because op0 * c2
> might overflow even when (op0 + c1) * c2 doesn't.
>
> Fixed thusly, after all that hunk of code is often soon undone by
> fold_build2 again or later during GIMPLE optimizations,
> bootstrapped/regtested on x86_64-linux and i686-linux, ok
> for trunk/4.8?
>
> 2013-04-10  Jakub Jelinek  <jakub@redhat.com>
>
> 	PR tree-optimization/56899
> 	* fold-const.c (extract_muldiv_1): Apply distributive law
> 	only if TYPE_OVERFLOW_WRAPS (ctype).
>
> 	* gcc.c-torture/execute/pr56899.c: New test.
OK, but I think you should update the comment before the test.  Right 
now it just references the overflow of the constant multiplication.

jeff

Patch

--- gcc/fold-const.c.jj	2013-04-03 15:46:45.000000000 +0200
+++ gcc/fold-const.c	2013-04-10 14:45:20.590321561 +0200
@@ -5851,7 +5851,7 @@  extract_muldiv_1 (tree t, tree c, enum t
       /* The last case is if we are a multiply.  In that case, we can
 	 apply the distributive law to commute the multiply and addition
 	 if the multiplication of the constants doesn't overflow.  */
-      if (code == MULT_EXPR)
+      if (code == MULT_EXPR && TYPE_OVERFLOW_WRAPS (ctype))
 	return fold_build2 (tcode, ctype,
 			    fold_build2 (code, ctype,
 					 fold_convert (ctype, op0),
--- gcc/testsuite/gcc.c-torture/execute/pr56899.c.jj	2013-04-10 14:58:37.015788243 +0200
+++ gcc/testsuite/gcc.c-torture/execute/pr56899.c	2013-04-10 14:58:08.000000000 +0200
@@ -0,0 +1,47 @@ 
+/* PR tree-optimization/56899 */
+
+#if __SIZEOF_INT__ == 4 && __CHAR_BIT__ == 8
+__attribute__((noinline, noclone)) void
+f1 (int v)
+{
+  int x = -214748365 * (v - 1);
+  if (x != -1932735285)
+    __builtin_abort ();
+}
+
+__attribute__((noinline, noclone)) void
+f2 (int v)
+{
+  int x = 214748365 * (v + 1);
+  if (x != -1932735285)
+    __builtin_abort ();
+}
+
+__attribute__((noinline, noclone)) void
+f3 (unsigned int v)
+{
+  unsigned int x = -214748365U * (v - 1);
+  if (x != -1932735285U)
+    __builtin_abort ();
+}
+
+__attribute__((noinline, noclone)) void
+f4 (unsigned int v)
+{
+  unsigned int x = 214748365U * (v + 1);
+  if (x != -1932735285U)
+    __builtin_abort ();
+}
+#endif
+
+int
+main ()
+{
+#if __SIZEOF_INT__ == 4 && __CHAR_BIT__ == 8
+  f1 (10);
+  f2 (-10);
+  f3 (10);
+  f4 (-10U);
+#endif
+  return 0;
+}