This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

[PATCH] Fix fold-const breakage


Hi!

The testcase below is miscompiled on all platforms I've tried (even at -O0).
The reason is that it is not safe to optimize:
( x * -3 - y * 3 ) / 12 into x / -4 - y / 4 which was extract_muldiv trying
(since extract_muldiv gave non-zero for both operands).
The patch below seems to fix it, although I'm not 100% sure about the
multiple_of_p changes (one of them considers e.g. a << 2 as multiple of 4
(or 2), the other is relevant e.g. to
( x * -24 - y * 24 ) / 12 which should be safe to optimize into x / -2 - y / 2
but multiple_of_p (<int>, -24, 12) would return 0 otherwise).
Bootstrap/regression testing pending, ok to commit if it is successful?

2001-02-22  Jakub Jelinek  <jakub@redhat.com>

	* fold-const.c (extract_muldiv) [case PLUS_EXPR]: If not MULT_EXPR,
	check if both operands are divisible by C.
	(multiple_of_p): Handle LSHIFT_EXPR with small constant shift.
	If type is signed, consider negative numbers as well.

	* gcc.c-torture/execute/20010222-1.c: New test.

--- gcc/fold-const.c.jj	Mon Feb 19 12:30:26 2001
+++ gcc/fold-const.c	Fri Feb 23 00:30:33 2001
@@ -4487,7 +4487,12 @@ extract_muldiv (t, c, code, wide_type)
 	 constant.  */
       t1 = extract_muldiv (op0, c, code, wide_type);
       t2 = extract_muldiv (op1, c, code, wide_type);
-      if (t1 != 0 && t2 != 0)
+      if (t1 != 0 && t2 != 0
+	  && (code == MULT_EXPR
+	      /* If not multiplication, we can only this if both operands
+		 are divisible by c.  */
+	      || (multiple_of_p (ctype, op0, c)
+		  && multiple_of_p (ctype, op1, c))))
 	return fold (build (tcode, ctype, convert (ctype, t1),
 			    convert (ctype, t2)));
 
@@ -7280,6 +7285,25 @@ multiple_of_p (type, top, bottom)
       return (multiple_of_p (type, TREE_OPERAND (top, 0), bottom)
 	      && multiple_of_p (type, TREE_OPERAND (top, 1), bottom));
 
+    case LSHIFT_EXPR:
+      if (TREE_CODE (TREE_OPERAND (top, 1)) == INTEGER_CST)
+	{
+	  tree op1, t1;
+
+	  op1 = TREE_OPERAND (top, 1);
+	  /* const_binop may not detect overflow correctly,
+	     so check for it explicitly here.  */
+	  if (TYPE_PRECISION (TREE_TYPE (size_one_node))
+	      > TREE_INT_CST_LOW (op1)
+	      && TREE_INT_CST_HIGH (op1) == 0
+	      && 0 != (t1 = convert (type,
+				     const_binop (LSHIFT_EXPR, size_one_node,
+						  op1, 0)))
+	      && ! TREE_OVERFLOW (t1))
+	    return multiple_of_p (type, t1, bottom);
+	}
+      return 0;
+
     case NOP_EXPR:
       /* Can't handle conversions from non-integral or wider integral type.  */
       if ((TREE_CODE (TREE_TYPE (TREE_OPERAND (top, 0))) != INTEGER_TYPE)
@@ -7293,9 +7317,10 @@ multiple_of_p (type, top, bottom)
       return multiple_of_p (type, TREE_OPERAND (top, 0), bottom);
 
     case INTEGER_CST:
-      if ((TREE_CODE (bottom) != INTEGER_CST)
-	  || (tree_int_cst_sgn (top) < 0)
-	  || (tree_int_cst_sgn (bottom) < 0))
+      if (TREE_CODE (bottom) != INTEGER_CST
+	  || (TREE_UNSIGNED (type)
+	      && (tree_int_cst_sgn (top) < 0
+		  || tree_int_cst_sgn (bottom) < 0)))
 	return 0;
       return integer_zerop (const_binop (TRUNC_MOD_EXPR,
 					 top, bottom, 0));
--- gcc/testsuite/gcc.c-torture/execute/20010222-1.c.jj	Fri Feb 23 00:45:10 2001
+++ gcc/testsuite/gcc.c-torture/execute/20010222-1.c	Fri Feb 23 00:41:48 2001
@@ -0,0 +1,9 @@
+int a[2] = { 18, 6 };
+
+int main ()
+{
+  int b = (-3 * a[0] -3 * a[1]) / 12;
+  if (b != -6)
+    abort ();
+  exit (0);
+}

	Jakub


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]