VRP: undefined shifting calculation should not need sign bit
Richard Sandiford
richard.sandiford@arm.com
Wed Oct 17 12:31:00 GMT 2018
Aldy Hernandez <aldyh@redhat.com> writes:
> On 9/13/18 3:33 AM, Richard Sandiford wrote:
>> Aldy Hernandez <aldyh@redhat.com> writes:
>>> On 09/12/2018 12:57 PM, Richard Sandiford wrote:
>>>> Aldy Hernandez <aldyh@redhat.com> writes:
>>>>> diff --git a/gcc/wide-int-range.h b/gcc/wide-int-range.h
>>>>> index 589fdea4df6..e9ee418e5b2 100644
>>>>> --- a/gcc/wide-int-range.h
>>>>> +++ b/gcc/wide-int-range.h
>>>>> @@ -131,7 +131,7 @@ extern bool wide_int_range_div (wide_int &wmin, wide_int &wmax,
>>>>> /* Return TRUE if shifting by range [MIN, MAX] is undefined behavior. */
>>>>>
>>>>> inline bool
>>>>> -wide_int_range_shift_undefined_p (signop sign, unsigned prec,
>>>>> +wide_int_range_shift_undefined_p (unsigned prec,
>>>>> const wide_int &min, const wide_int &max)
>>>>> {
>>>>> /* ?? Note: The original comment said this only applied to
>>>>> @@ -142,7 +142,7 @@ wide_int_range_shift_undefined_p (signop sign, unsigned prec,
>>>>> 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. */
>>>>> - return wi::lt_p (min, 0, sign) || wi::ge_p (max, prec, sign);
>>>>> + return wi::sign_mask (min) || wi::ge_p (max, prec, UNSIGNED);
>>>>
>>>> I don't think this is a good idea. Logically the comparison should
>>>> be done relative to the TYPE_SIGN of the type, so I think the original
>>>> code was correct.
>>>
>>> The operation to calculate undefinedness must be done with the type of
>>> the RHS, as opposed to the type of the entire operation. This can be
>>> confusing, as most operations use the same type for all operands as well
>>> as for the type of the entire operation. For example, AFAICT, the
>>> following is valid gimple:
>>>
>>> UINT64 = UINT64 << INT32
>>>
>>> The original code was doing this (correctly), but since it was confusing
>>> to remember which type to pass, I rewrote the above function to not need
>>> the sign of the RHS. This came about because in my ranger work, I
>>> passed the wrong type which took forever to find ;-). My patch avoids
>>> further confusion.
>>>
>>> Am I missing a subtle incorrectness in my approach?
>>
>> The problem is with things like UINT256 << UINT8 vs. UINT256 << INT8.
>> A range of [128, 131] on the UINT8 would be represented using the same
>> wide_ints as a range of [-128, -125] on the INT8, but the former is
>> well-defined while the latter isn't. Only the TYPE_SIGN tells you
>> which applies.
>>
>> The original code got this right, but the new code effectively assumes
>> all shift amounts are signed, and so would treat UINT8 like INT8.
>>
>> OK, so no current target actually supports UINT256 AFAIK, so it might
>> be academic. But the original point of wide-int.h was to support such
>> wide types, so they could become a thing in future.
>>
>> Thanks,
>> Richard
>>
>
> As promised. Here is the reversal of the bits you suggested.
Thanks!
> I think this is an obvious patch, but would appreciate a sanity peek.
>
> Aldy
>
> commit 38a335af9aa5d72778fbacba247ab2219672da7b
> Author: Aldy Hernandez <aldyh@redhat.com>
> Date: Wed Oct 17 11:25:21 2018 +0200
>
> * wide-int-range.h (wide_int_range_shift_undefined_p): Adjust to
> use sign as argument.
> * tree-vrp.c (extract_range_from_binary_expr_1): Pass sign to
> wide_int_range_shift_undefined_p.
>
> diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
> index cbc2ea2f26b..c519613bb28 100644
> --- a/gcc/tree-vrp.c
> +++ b/gcc/tree-vrp.c
> @@ -1521,7 +1521,8 @@ extract_range_from_binary_expr_1 (value_range *vr,
> || code == LSHIFT_EXPR)
> {
> if (range_int_cst_p (&vr1)
> - && !wide_int_range_shift_undefined_p (prec,
> + && !wide_int_range_shift_undefined_p (TYPE_SIGN (TREE_TYPE (vr1.min)),
> + prec,
> wi::to_wide (vr1.min),
> wi::to_wide (vr1.max)))
> {
> diff --git a/gcc/wide-int-range.h b/gcc/wide-int-range.h
> index e9ee418e5b2..589fdea4df6 100644
> --- a/gcc/wide-int-range.h
> +++ b/gcc/wide-int-range.h
> @@ -131,7 +131,7 @@ extern bool wide_int_range_div (wide_int &wmin, wide_int &wmax,
> /* Return TRUE if shifting by range [MIN, MAX] is undefined behavior. */
>
> inline bool
> -wide_int_range_shift_undefined_p (unsigned prec,
> +wide_int_range_shift_undefined_p (signop sign, unsigned prec,
> const wide_int &min, const wide_int &max)
Need to add SIGN back to the comment, maybe something like:
/* Return TRUE if shifting by range [MIN, MAX] is undefined behavior,
interpreting MIN and MAX according to SIGN. */
(or whatever you think's best).
OK otherwise, thanks.
Richard
More information about the Gcc-patches
mailing list