This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Fix another VRP bug
- From: Eric Botcazou <ebotcazou at libertysurf dot fr>
- To: gcc-patches at gcc dot gnu dot org
- Date: Sat, 3 Sep 2005 16:41:25 +0200
- Subject: [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;