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 another VRP bug


Hi,

We have on SPARC 32-bit
   FAIL: gcc.c-torture/execute/950612-1.c execution,  -O3 -g 
but only on 32-bit hosts, not on 64-bit hosts.

Reduced testcase:
unsigned long long
f4 (unsigned long long diff)
{
  return ((unsigned long long) ((signed long long) diff < 0 ? -diff : diff));
}

int main (void)
{
  int i;
  for (i = 0; i <= 10; i++)
    if (f4 ((long long) -i) != i)
      abort ();
  return 0;
}

t27.copyprop1:
  long long unsigned int diff;
  long long int D.1332;
  long long int diff.0;
  long long unsigned int D.1333;
  int i;
  int D.1282;
  long long unsigned int D.1281;
  long long unsigned int D.1280;
  long long unsigned int D.1279;
  int D.1278;

<bb 0>:
  goto <bb 4> (<L3>);

<L0>:;
  D.1278_5 = -i_1;
  diff_6 = (long long unsigned int) D.1278_5;
  diff_7 = diff_6;
  diff.0_8 = (long long int) diff_6;
  D.1332_9 = ABS_EXPR <diff.0_8>;
  D.1280_10 = (long long unsigned int) D.1332_9;
  D.1280_11 = D.1280_10;
  D.1281_12 = (long long unsigned int) i_1;
  if (D.1280_10 != D.1281_12) goto <L1>; else goto <L2>;

t28.vrp (HOST_BITS_PER_WIDE_INT == 32):
i_1: VARYING
i_3: [0, 10]  EQUIVALENCES: { i_1 } (1 elements)
<retval>_4: VARYING
D.1278_5: [-10, 0]  EQUIVALENCES: { } (0 elements)
diff_6: [0, +INF]  EQUIVALENCES: { } (0 elements)
diff_7: [0, +INF]  EQUIVALENCES: { diff_6 } (1 elements)
diff.0_8: [0, -000000001]  EQUIVALENCES: { } (0 elements)  <--- boo!

t28.vrp (HOST_BITS_PER_WIDE_INT == 64):
i_1: VARYING
i_3: [0, 10]  EQUIVALENCES: { i_1 } (1 elements)
<retval>_4: VARYING
D.1278_5: [-10, 0]  EQUIVALENCES: { } (0 elements)
diff_6: [0, +INF]  EQUIVALENCES: { } (0 elements)
diff_7: [0, +INF]  EQUIVALENCES: { diff_6 } (1 elements)
diff.0_8: VARYING

so the ABS_EXPR gets eliminated in the former case and all hell breaks loose.


The problem is located in extract_range_from_unary_expr:

  /* Handle unary expressions on integer ranges.  */
  if (code == NOP_EXPR || code == CONVERT_EXPR)
    {
      tree inner_type = TREE_TYPE (op0);
      tree outer_type = TREE_TYPE (expr);

      /* If VR0 represents a simple range, then try to convert
	 the min and max values for the range to the same type
	 as OUTER_TYPE.  If the results compare equal to VR0's
	 min and max values and the new min is still less than
	 or equal to the new max, then we can safely use the newly
	 computed range for EXPR.  This allows us to compute
	 accurate ranges through many casts.  */
      if (vr0.type == VR_RANGE)
	{
	  tree new_min, new_max;

	  /* Convert VR0's min/max to OUTER_TYPE.  */
	  new_min = fold_convert (outer_type, vr0.min);
	  new_max = fold_convert (outer_type, vr0.max);

	  /* Verify the new min/max values are gimple values and
	     that they compare equal to VR0's min/max values.  */
	  if (is_gimple_val (new_min)
	      && is_gimple_val (new_max)
	      && tree_int_cst_equal (new_min, vr0.min)
	      && tree_int_cst_equal (new_max, vr0.max)
	      && compare_values (new_min, new_max) <= 0
	      && compare_values (new_min, new_max) >= -2)
	    {
	      set_value_range (vr, VR_RANGE, new_min, new_max, vr->equiv);
	      return;
	    }
	}

for the statement "diff.0_8 = (long long int) diff_6".

HOST_BITS_PER_WIDE_INT == 32:
(gdb) p debug_tree(vr0.min)
 <integer_cst 0x556d6510 type <integer_type 0x556e5450 long long unsigned int> 
constant invariant 0>
$8 = void
(gdb) p debug_tree(vr0.max)
 <integer_cst 0x556d64f8 type <integer_type 0x556e5450 long long unsigned int> 
constant invariant -1>
$9 = void
(gdb) p debug_tree(new_min)
 <integer_cst 0x55754c78 type <integer_type 0x556e53f4 long long int> constant 
invariant 0>
$10 = void
(gdb) p debug_tree(new_max)
 <integer_cst 0x557578e8 type <integer_type 0x556e53f4 long long int> constant 
invariant public static overflow -1>

HOST_BITS_PER_WIDE_INT == 64:
(gdb) p debug_tree(vr0.min)
 <integer_cst 0x2a95890bd0 type <integer_type 0x2a958a1840 long long unsigned 
int> constant invariant 0>
$7 = void
(gdb) p debug_tree(vr0.max)
 <integer_cst 0x2a95890ba0 type <integer_type 0x2a958a1840 long long unsigned 
int> constant invariant 18446744073709551615>
$8 = void
(gdb) p debug_tree(new_min)
 <integer_cst 0x2a9597fcf0 type <integer_type 0x2a958a1790 long long int> 
constant invariant 0>
$9 = void
(gdb) p debug_tree(new_max)
 <integer_cst 0x2a959c1690 type <integer_type 0x2a958a1790 long long int> 
constant invariant public static overflow -1>

I think everything is fine up to now.  Then, in the latter case the test 
tree_int_cst_equal (new_max, vr0.max) fails and we end up with

     {
      /* Otherwise, operate on each end of the range.  */
      min = fold_unary_to_constant (code, TREE_TYPE (expr), vr0.min);
      max = fold_unary_to_constant (code, TREE_TYPE (expr), vr0.max);
    }

  cmp = compare_values (min, max);
  if (cmp == -2 || cmp == 1)
    {
      /* If the new range has its limits swapped around (MIN > MAX),
	 then the operation caused one of them to wrap around, mark
	 the new range VARYING.  */
      set_value_range_to_varying (vr);
    }

which sets the range to VARYING because cmp == -2 because of TREE_OVERFLOW on 
max.

But in the former case, tree_int_cst_equal (new_max, vr0.max) happens to 
succeed so we end up instead with

	      && compare_values (new_min, new_max) <= 0
	      && compare_values (new_min, new_max) >= -2)
	    {
	      set_value_range (vr, VR_RANGE, new_min, new_max, vr->equiv);
	      return;
	    }

Again compare_values returns -2 because of TREE_OVERFLOW on new_max and we 
nevertheless set the range!


Any specific reason for the discrepancy in the treatment of -2?  If no, I'm 
proposing the following fix.  Bootstrapped/regtested on x86_64-linux-gnu.


2005-09-03  Eric Botcazou  <ebotcazou@libertysurf.fr>

	* tree-vrp.c (extract_range_from_unary_expr): Do not set the range for the
	result of a conversion if the new min and max cannot be compared.


-- 
Eric Botcazou
Index: tree-vrp.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-vrp.c,v
retrieving revision 2.53
diff -u -p -r2.53 tree-vrp.c
--- tree-vrp.c	28 Aug 2005 21:08:28 -0000	2.53
+++ tree-vrp.c	3 Sep 2005 10:48:47 -0000
@@ -1341,7 +1341,7 @@ extract_range_from_unary_expr (value_ran
 	      && tree_int_cst_equal (new_min, vr0.min)
 	      && tree_int_cst_equal (new_max, vr0.max)
 	      && compare_values (new_min, new_max) <= 0
-	      && compare_values (new_min, new_max) >= -2)
+	      && compare_values (new_min, new_max) >= -1)
 	    {
 	      set_value_range (vr, VR_RANGE, new_min, new_max, vr->equiv);
 	      return;

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