On 27/08/14 23:02, Kugan wrote:
> On 27/08/14 20:01, Uros Bizjak wrote:
>> Hello!
>>
>>> 2014-08-07 Kugan Vivekanandarajah <[email protected]>
>>>
>>> * calls.c (precompute_arguments): Check
>>> promoted_for_signed_and_unsigned_p and set the promoted mode.
>>> (promoted_for_signed_and_unsigned_p): New function.
>>> (expand_expr_real_1): Check promoted_for_signed_and_unsigned_p
>>> and set the promoted mode.
>>> * expr.h (promoted_for_signed_and_unsigned_p): New function definition.
>>> * cfgexpand.c (expand_gimple_stmt_1): Call emit_move_insn if
>>> SUBREG is promoted with SRP_SIGNED_AND_UNSIGNED.
>>
>> This patch regresses:
>>
>> Running target unix
>> FAIL: libgomp.fortran/simd7.f90 -O2 execution test
>> FAIL: libgomp.fortran/simd7.f90 -Os execution test
>>
>
> [snip]
>
>> When compiling this code, we have:
>>
>> lhs = _63
>> target = (subreg/s/v/u:SI (reg:DI 145 [ D.1694 ]) 0)
>> temp = (subreg:SI (reg:DI 540) 0)
>>
>> So, the code assumes that it is possible to copy (reg:DI 540) directly
>> to (reg:DI 154). However, this is not the case, since we still have
>> garbage in the top 32bits.
>>
>> Reverting the part above fixes the runtime failure, since (insn 599) is now:
>>
>> (insn 599 598 0 (set (reg:DI 145 [ D.1694 ])
>> (zero_extend:DI (subreg:SI (reg:DI 540) 0))) -1
>> (nil))
>>
>> It looks to me that we have also to check the temp with SUBREG_PROMOTED_*.
>
> Sorry for the breakage. I am looking into this now and I can reproduce
> it on qemu-alpha.
>
> I have noticed the following VRP data which is used in deciding this
> erroneous removal. It seems suspicious to me.
>
> _343: [2147483652, 2147483715]
> _344: [8, 134]
> _345: [8, 134]
>
> _343 = ivtmp.179_52 + 2147483645;
> _344 = _343 * 2;
> _345 = (integer(kind=4)) _344;
>
> Error comes from the third statement.
In tree-vrp.c, in extract_range_from_binary_expr_1, there is a loss of
precision and the value_range is truncated. For the test-case provided
by Uros, it is
_344 = _343 * 2;
[...,0x100000008], precision = 384
[...,0x100000086], precision = 384
and it is converted to following when it goes from wide_int to tree.
[8, 134]
How about doing something like this to fix it.
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index d16fd8a..c0fb902 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -2625,6 +2625,8 @@ extract_range_from_binary_expr_1 (value_range_t *vr,
<wi::extended_tree <WIDE_INT_MAX_PRECISION * 2> > vrp_int_cst;
vrp_int sizem1 = wi::mask <vrp_int> (prec, false);
vrp_int size = sizem1 + 1;
+ vrp_int type_min = vrp_int_cst (TYPE_MIN_VALUE (expr_type));
+ vrp_int type_max = vrp_int_cst (TYPE_MAX_VALUE (expr_type));
/* Extend the values using the sign of the result to PREC2.
From here on out, everthing is just signed math no matter
@@ -2688,7 +2690,9 @@ extract_range_from_binary_expr_1 (value_range_t *vr,
/* diff = max - min. */
prod2 = prod3 - prod0;
- if (wi::geu_p (prod2, sizem1))
+ if (wi::geu_p (prod2, sizem1)
+ || wi::lts_p (prod0, type_min)
+ || wi::gts_p (prod3, type_max))
{
/* the range covers all values. */
set_value_range_to_varying (vr);
If this looks reasonable I will do proper testing and post the results
with the Changelog.
Thanks,
Kugan