diff mbox

VRP: range info of new variables

Message ID alpine.DEB.2.02.1605132019140.21219@laptop-mg.saclay.inria.fr
State New
Headers show

Commit Message

Marc Glisse May 13, 2016, 6:50 p.m. UTC
Hello,

when VRP does some transforms, it may create new SSA_NAMEs, but doesn't 
give them range information. This can prevent cascading transformations in 
a single VRP pass. With this patch, I assign range information to the 
variable introduced by one transformation, and in another transformation, 
I get range information through get_range_info instead of get_value_range 
in order to have access to the new information.

Some notes:
- get_range_info only applies to integers, not pointers. I hope we are not 
losing much by restricting this transformation. I could also call 
get_value_range and only fall back to get_range_info if that failed (and 
we don't have a pointer), but it doesn't seem worth it.
- Now that I think of it, maybe I should check that the variable is not a 
pointer before calling set_range_info? Having range [0, 1] makes it 
unlikely, but who knows...
- wide_int is much more complicated to use than I expected :-(
- the foldings that disappear in pr69270.c are for dead variables that are 
now eliminated earlier.

Bootstrap+regtest on powerpc64le-unknown-linux-gnu, I also checked 
manually that an earlier version of the patch fixes vrp47.c on 
x86_64-pc-linux-gnu.

2016-05-16  Marc Glisse  <marc.glisse@inria.fr>

gcc/
 	* tree-vrp.c (simplify_truth_ops_using_ranges): Set range
 	information for new SSA_NAME.
 	(simplify_switch_using_ranges): Get range through get_range_info
 	instead of get_value_range.

gcc/testsuite/
 	* gcc.dg/tree-ssa/pr69270.c: Adjust.
 	* gcc.dg/tree-ssa/vrp99.c: New testcase.

Comments

Jeff Law May 16, 2016, 6:30 p.m. UTC | #1
On 05/13/2016 12:50 PM, Marc Glisse wrote:
> Hello,
>
> when VRP does some transforms, it may create new SSA_NAMEs, but doesn't
> give them range information. This can prevent cascading transformations
> in a single VRP pass. With this patch, I assign range information to the
> variable introduced by one transformation, and in another
> transformation, I get range information through get_range_info instead
> of get_value_range in order to have access to the new information.
>
> Some notes:
> - get_range_info only applies to integers, not pointers. I hope we are
> not losing much by restricting this transformation. I could also call
> get_value_range and only fall back to get_range_info if that failed (and
> we don't have a pointer), but it doesn't seem worth it.
It probably isn't worth it.

> - Now that I think of it, maybe I should check that the variable is not
> a pointer before calling set_range_info? Having range [0, 1] makes it
> unlikely, but who knows...
Maybe using an assert would be better.


> Index: gcc/tree-vrp.c
> ===================================================================
> --- gcc/tree-vrp.c	(revision 236194)
> +++ gcc/tree-vrp.c	(working copy)
> @@ -8933,20 +8933,24 @@ simplify_truth_ops_using_ranges (gimple_
>      gimple_assign_set_rhs_with_ops (gsi,
>  				    need_conversion
>  				    ? NOP_EXPR : TREE_CODE (op0), op0);
>    /* For A != B we substitute A ^ B.  Either with conversion.  */
>    else if (need_conversion)
>      {
>        tree tem = make_ssa_name (TREE_TYPE (op0));
>        gassign *newop
>  	= gimple_build_assign (tem, BIT_XOR_EXPR, op0, op1);
>        gsi_insert_before (gsi, newop, GSI_SAME_STMT);
> +      if (TYPE_PRECISION (TREE_TYPE (tem)) > 1)
> +	set_range_info (tem, VR_RANGE,
> +			wi::zero (TYPE_PRECISION (TREE_TYPE (tem))),
> +			wi::one (TYPE_PRECISION (TREE_TYPE (tem))));
Is there actually a case where TYPE_PRECISION (TREE_TYPE (tem)) > 1 is 
ever false?  Would an assert make more sense here?


>
>  /* Simplify an integral conversion from an SSA name in STMT.  */
>
>  static bool
>  simplify_conversion_using_ranges (gimple *stmt)
Your ChangeLog mentions simplify_switch_using_ranges, not 
simplify_conversion_using_ranges.

This is OK for the trunk -- your call on asserting the variable is not a 
pointer before calling set_range_info.  Similarly on the check that the 
TYPE_PRECISION (TREE_TYPE (tem)) > 1.

Jeff
Marc Glisse May 17, 2016, 12:01 p.m. UTC | #2
On Mon, 16 May 2016, Jeff Law wrote:

>> - Now that I think of it, maybe I should check that the variable is not
>> a pointer before calling set_range_info? Having range [0, 1] makes it
>> unlikely, but who knows...
> Maybe using an assert would be better.

I don't think having a pointer there would be completely wrong, just 
unlikely, so I'd rather add a check but not assert.

>> Index: gcc/tree-vrp.c
>> ===================================================================
>> --- gcc/tree-vrp.c	(revision 236194)
>> +++ gcc/tree-vrp.c	(working copy)
>> @@ -8933,20 +8933,24 @@ simplify_truth_ops_using_ranges (gimple_
>>      gimple_assign_set_rhs_with_ops (gsi,
>>  				    need_conversion
>>  				    ? NOP_EXPR : TREE_CODE (op0), op0);
>>    /* For A != B we substitute A ^ B.  Either with conversion.  */
>>    else if (need_conversion)
>>      {
>>        tree tem = make_ssa_name (TREE_TYPE (op0));
>>        gassign *newop
>>  	= gimple_build_assign (tem, BIT_XOR_EXPR, op0, op1);
>>        gsi_insert_before (gsi, newop, GSI_SAME_STMT);
>> +      if (TYPE_PRECISION (TREE_TYPE (tem)) > 1)
>> +	set_range_info (tem, VR_RANGE,
>> +			wi::zero (TYPE_PRECISION (TREE_TYPE (tem))),
>> +			wi::one (TYPE_PRECISION (TREE_TYPE (tem))));
> Is there actually a case where TYPE_PRECISION (TREE_TYPE (tem)) > 1 is ever 
> false?  Would an assert make more sense here?

op0 can have precision 1, so tem can as well. In most cases I would expect 
need_conversion to be false in that case though. However, it doesn't seem 
impossible to have several types with 1-bit precision that are not 
equivalent (different TYPE_SIGN for instance). So again, I don't feel 
comfortable adding an assert. But I am open to proofs that those events 
cannot happen.

>>  static bool
>>  simplify_conversion_using_ranges (gimple *stmt)
> Your ChangeLog mentions simplify_switch_using_ranges, not 
> simplify_conversion_using_ranges.

Oups, bad copy-paste (I keep too much context in the diff for diff -p to 
give useful results), thanks.

> This is OK for the trunk -- your call on asserting the variable is not a 
> pointer before calling set_range_info.  Similarly on the check that the 
> TYPE_PRECISION (TREE_TYPE (tem)) > 1.
diff mbox

Patch

Index: gcc/testsuite/gcc.dg/tree-ssa/pr69270.c
===================================================================
--- gcc/testsuite/gcc.dg/tree-ssa/pr69270.c	(revision 236194)
+++ gcc/testsuite/gcc.dg/tree-ssa/pr69270.c	(working copy)
@@ -1,21 +1,19 @@ 
 /* { dg-do compile } */
 /* { dg-options "-O2 -fsplit-paths -fdump-tree-dom3-details" } */
 
 /* There should be two references to bufferstep that turn into
    constants.  */
 /* { dg-final { scan-tree-dump-times "Replaced .bufferstep_\[0-9\]+. with constant .0." 1 "dom3"} } */
 /* { dg-final { scan-tree-dump-times "Replaced .bufferstep_\[0-9\]+. with constant .1." 1 "dom3"} } */
 
 /* And some assignments ought to fold down to constants.  */
-/* { dg-final { scan-tree-dump-times "Folded to: _\[0-9\]+ = -1;" 1 "dom3"} } */
-/* { dg-final { scan-tree-dump-times "Folded to: _\[0-9\]+ = -2;" 1 "dom3"} } */
 /* { dg-final { scan-tree-dump-times "Folded to: _\[0-9\]+ = 1;" 1 "dom3"} } */
 /* { dg-final { scan-tree-dump-times "Folded to: _\[0-9\]+ = 0;" 1 "dom3"} } */
 
 /* The XOR operations should have been optimized to constants.  */
 /* { dg-final { scan-tree-dump-not "bit_xor" "dom3"} } */
 
 
 extern int *stepsizeTable;
 
 void
Index: gcc/testsuite/gcc.dg/tree-ssa/vrp99.c
===================================================================
--- gcc/testsuite/gcc.dg/tree-ssa/vrp99.c	(revision 0)
+++ gcc/testsuite/gcc.dg/tree-ssa/vrp99.c	(working copy)
@@ -0,0 +1,9 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-vrp1" } */
+
+unsigned f(unsigned i){
+  i >>= __SIZEOF_INT__ * __CHAR_BIT__ - 1;
+  return i == 0;
+}
+
+/* { dg-final { scan-tree-dump-not "\\(unsigned int\\)" "vrp1" } } */
Index: gcc/tree-vrp.c
===================================================================
--- gcc/tree-vrp.c	(revision 236194)
+++ gcc/tree-vrp.c	(working copy)
@@ -8933,20 +8933,24 @@  simplify_truth_ops_using_ranges (gimple_
     gimple_assign_set_rhs_with_ops (gsi,
 				    need_conversion
 				    ? NOP_EXPR : TREE_CODE (op0), op0);
   /* For A != B we substitute A ^ B.  Either with conversion.  */
   else if (need_conversion)
     {
       tree tem = make_ssa_name (TREE_TYPE (op0));
       gassign *newop
 	= gimple_build_assign (tem, BIT_XOR_EXPR, op0, op1);
       gsi_insert_before (gsi, newop, GSI_SAME_STMT);
+      if (TYPE_PRECISION (TREE_TYPE (tem)) > 1)
+	set_range_info (tem, VR_RANGE,
+			wi::zero (TYPE_PRECISION (TREE_TYPE (tem))),
+			wi::one (TYPE_PRECISION (TREE_TYPE (tem))));
       gimple_assign_set_rhs_with_ops (gsi, NOP_EXPR, tem);
     }
   /* Or without.  */
   else
     gimple_assign_set_rhs_with_ops (gsi, BIT_XOR_EXPR, op0, op1);
   update_stmt (gsi_stmt (*gsi));
 
   return true;
 }
 
@@ -9641,50 +9645,48 @@  simplify_switch_using_ranges (gswitch *s
   return false;
 }
 
 /* Simplify an integral conversion from an SSA name in STMT.  */
 
 static bool
 simplify_conversion_using_ranges (gimple *stmt)
 {
   tree innerop, middleop, finaltype;
   gimple *def_stmt;
-  value_range *innervr;
   signop inner_sgn, middle_sgn, final_sgn;
   unsigned inner_prec, middle_prec, final_prec;
   widest_int innermin, innermed, innermax, middlemin, middlemed, middlemax;
 
   finaltype = TREE_TYPE (gimple_assign_lhs (stmt));
   if (!INTEGRAL_TYPE_P (finaltype))
     return false;
   middleop = gimple_assign_rhs1 (stmt);
   def_stmt = SSA_NAME_DEF_STMT (middleop);
   if (!is_gimple_assign (def_stmt)
       || !CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def_stmt)))
     return false;
   innerop = gimple_assign_rhs1 (def_stmt);
   if (TREE_CODE (innerop) != SSA_NAME
       || SSA_NAME_OCCURS_IN_ABNORMAL_PHI (innerop))
     return false;
 
-  /* Get the value-range of the inner operand.  */
-  innervr = get_value_range (innerop);
-  if (innervr->type != VR_RANGE
-      || TREE_CODE (innervr->min) != INTEGER_CST
-      || TREE_CODE (innervr->max) != INTEGER_CST)
+  /* Get the value-range of the inner operand.  Use get_range_info in
+     case innerop was created during substitute-and-fold.  */
+  wide_int imin, imax;
+  if (!INTEGRAL_TYPE_P (TREE_TYPE (innerop))
+      || get_range_info (innerop, &imin, &imax) != VR_RANGE)
     return false;
+  innermin = widest_int::from (imin, TYPE_SIGN (TREE_TYPE (innerop)));
+  innermax = widest_int::from (imax, TYPE_SIGN (TREE_TYPE (innerop)));
 
   /* Simulate the conversion chain to check if the result is equal if
      the middle conversion is removed.  */
-  innermin = wi::to_widest (innervr->min);
-  innermax = wi::to_widest (innervr->max);
-
   inner_prec = TYPE_PRECISION (TREE_TYPE (innerop));
   middle_prec = TYPE_PRECISION (TREE_TYPE (middleop));
   final_prec = TYPE_PRECISION (finaltype);
 
   /* If the first conversion is not injective, the second must not
      be widening.  */
   if (wi::gtu_p (innermax - innermin,
 		 wi::mask <widest_int> (middle_prec, false))
       && middle_prec < final_prec)
     return false;