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]
Other format: [Raw text]

[PATCH] Fix PR54027


This fixes PR54027, VRP treating overflow in signed left-shifts undefined.

Bootstrap and regtest pending on x86_64-unknown-linux-gnu.

Richard.

2012-08-09  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.

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

Index: gcc/tree-vrp.c
===================================================================
*** gcc/tree-vrp.c	(revision 190252)
--- gcc/tree-vrp.c	(working copy)
*************** extract_range_from_binary_expr_1 (value_
*** 2726,2782 ****
        extract_range_from_multiplicative_op_1 (vr, code, &vr0, &vr1);
        return;
      }
!   else if (code == RSHIFT_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)
- 	{
- 	  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;
- 	}
- 
        set_value_range_to_varying (vr);
        return;
      }
--- 2726,2773 ----
        extract_range_from_multiplicative_op_1 (vr, code, &vr0, &vr1);
        return;
      }
!   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 (range_int_cst_p (&vr1)
! 	  && compare_tree_int (vr1.min, 0) >= 0
! 	  && compare_tree_int (vr1.max, TYPE_PRECISION (expr_type)) == -1)
  	{
! 	  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;
      }
Index: gcc/testsuite/gcc.dg/torture/pr54027.c
===================================================================
*** gcc/testsuite/gcc.dg/torture/pr54027.c	(revision 0)
--- gcc/testsuite/gcc.dg/torture/pr54027.c	(working copy)
***************
*** 0 ****
--- 1,9 ----
+ /* { dg-do run } */
+ 
+ int main (void)
+ {
+   int x = 1;
+   while (x)
+     x <<= 1;
+   return x;
+ }


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