]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
2012-08-10 Richard Guenther <rguenther@suse.de>
authorrguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 10 Aug 2012 08:33:57 +0000 (08:33 +0000)
committerrguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 10 Aug 2012 08:33:57 +0000 (08:33 +0000)
PR tree-optimization/54027
* tree-vrp.c (extract_range_from_binary_expr_1): Merge RSHIFT_EXPR
and LSHIFT_EXPR handling, force -fwrapv for the multiplication used
to handle LSHIFT_EXPR with a constant.

* gcc.dg/torture/pr54027.c: New testcase.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@190286 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/torture/pr54027.c [new file with mode: 0644]
gcc/tree-vrp.c

index 9a9a9ce184e8c8730ef997e81ca4f8ef67cfa735..f047b141fc710eb0a7932ae06d36a434be496fa5 100644 (file)
@@ -1,3 +1,10 @@
+2012-08-10  Richard Guenther  <rguenther@suse.de>
+
+       PR tree-optimization/54027
+       * tree-vrp.c (extract_range_from_binary_expr_1): Merge RSHIFT_EXPR
+       and LSHIFT_EXPR handling, force -fwrapv for the multiplication used
+       to handle LSHIFT_EXPR with a constant.
+
 2012-08-10  Richard Guenther  <rguenther@suse.de>
 
        * tree.h (SSA_NAME_VAR): Return NULL_TREE if an IDENTIFIER_NODE
index be6b56a721b2205c565f96dd9b85b784adaaf346..55bc89298f53cc1d72cad1f16b6e10db6006b7ff 100644 (file)
@@ -1,3 +1,8 @@
+2012-08-10  Richard Guenther  <rguenther@suse.de>
+
+       PR tree-optimization/54027
+       * gcc.dg/torture/pr54027.c: New testcase.
+
 2012-08-10  Richard Guenther  <rguenther@suse.de>
 
        * g++.dg/plugin/selfassign.c: Adjust.
diff --git a/gcc/testsuite/gcc.dg/torture/pr54027.c b/gcc/testsuite/gcc.dg/torture/pr54027.c
new file mode 100644 (file)
index 0000000..b5568f4
--- /dev/null
@@ -0,0 +1,9 @@
+/* { dg-do run } */
+
+int main (void)
+{
+  int x = 1;
+  while (x)
+    x <<= 1;
+  return x;
+}
index 5f7734f9ac8ae186709954d76b63692beac8754b..a5b583b66d56b578579f7806556e933fe4877a35 100644 (file)
@@ -2726,57 +2726,48 @@ extract_range_from_binary_expr_1 (value_range_t *vr,
       extract_range_from_multiplicative_op_1 (vr, code, &vr0, &vr1);
       return;
     }
-  else if (code == RSHIFT_EXPR)
+  else if (code == RSHIFT_EXPR
+          || code == LSHIFT_EXPR)
     {
       /* If we have a RSHIFT_EXPR with any shift values outside [0..prec-1],
         then drop to VR_VARYING.  Outside of this range we get undefined
         behavior from the shift operation.  We cannot even trust
         SHIFT_COUNT_TRUNCATED at this stage, because that applies to rtl
         shifts, and the operation at the tree level may be widened.  */
-      if (vr1.type != VR_RANGE
-         || !value_range_nonnegative_p (&vr1)
-         || TREE_CODE (vr1.max) != INTEGER_CST
-         || compare_tree_int (vr1.max, TYPE_PRECISION (expr_type) - 1) == 1)
-       {
-         set_value_range_to_varying (vr);
-         return;
-       }
-
-      extract_range_from_multiplicative_op_1 (vr, code, &vr0, &vr1);
-      return;
-    }
-  else if (code == LSHIFT_EXPR)
-    {
-      /* If we have a LSHIFT_EXPR with any shift values outside [0..prec-1],
-        then drop to VR_VARYING.  Outside of this range we get undefined
-        behavior from the shift operation.  We cannot even trust
-        SHIFT_COUNT_TRUNCATED at this stage, because that applies to rtl
-        shifts, and the operation at the tree level may be widened.  */
-      if (vr1.type != VR_RANGE
-         || !value_range_nonnegative_p (&vr1)
-         || TREE_CODE (vr1.max) != INTEGER_CST
-         || compare_tree_int (vr1.max, TYPE_PRECISION (expr_type) - 1) == 1)
+      if (range_int_cst_p (&vr1)
+         && compare_tree_int (vr1.min, 0) >= 0
+         && compare_tree_int (vr1.max, TYPE_PRECISION (expr_type)) == -1)
        {
-         set_value_range_to_varying (vr);
-         return;
-       }
-
-      /* We can map shifts by constants to MULT_EXPR handling.  */
-      if (range_int_cst_singleton_p (&vr1))
-       {
-         value_range_t vr1p = VR_INITIALIZER;
-         vr1p.type = VR_RANGE;
-         vr1p.min
-           = double_int_to_tree (expr_type,
-                                 double_int_lshift (double_int_one,
-                                                    TREE_INT_CST_LOW (vr1.min),
-                                                    TYPE_PRECISION (expr_type),
-                                                    false));
-         vr1p.max = vr1p.min;
-         extract_range_from_multiplicative_op_1 (vr, MULT_EXPR, &vr0, &vr1p);
-         return;
+         if (code == RSHIFT_EXPR)
+           {
+             extract_range_from_multiplicative_op_1 (vr, code, &vr0, &vr1);
+             return;
+           }
+         /* We can map lshifts by constants to MULT_EXPR handling.  */
+         else if (code == LSHIFT_EXPR
+                  && range_int_cst_singleton_p (&vr1))
+           {
+             bool saved_flag_wrapv;
+             value_range_t vr1p = VR_INITIALIZER;
+             vr1p.type = VR_RANGE;
+             vr1p.min
+               = double_int_to_tree (expr_type,
+                                     double_int_lshift
+                                       (double_int_one,
+                                        TREE_INT_CST_LOW (vr1.min),
+                                        TYPE_PRECISION (expr_type),
+                                        false));
+             vr1p.max = vr1p.min;
+             /* We have to use a wrapping multiply though as signed overflow
+                on lshifts is implementation defined in C89.  */
+             saved_flag_wrapv = flag_wrapv;
+             flag_wrapv = 1;
+             extract_range_from_binary_expr_1 (vr, MULT_EXPR, expr_type,
+                                               &vr0, &vr1p);
+             flag_wrapv = saved_flag_wrapv;
+             return;
+           }
        }
-
       set_value_range_to_varying (vr);
       return;
     }