[wide-int 2/8] Fix ubsan internal-fn.c handling
Richard Biener
richard.guenther@gmail.com
Wed Apr 23 13:54:00 GMT 2014
On Wed, Apr 23, 2014 at 3:29 PM, Richard Sandiford
<rdsandiford@googlemail.com> wrote:
> Richard Sandiford <rdsandiford@googlemail.com> writes:
>> This code was mixing hprec and hprec*2 wide_ints. The simplest fix
>> seemed to be to introduce a function that gives the minimum precision
>> necessary to represent a function, which also means that no temporary
>> wide_ints are needed.
>>
>> Other places might be able to use this too, but I'd like to look at
>> that after the merge.
>>
>> The patch series fixed a regression in c-c++-common/ubsan/overflow-2.c
>> and I assume it's due to this change.
>>
>> Tested on x86_64-linux-gnu. OK to install?
>
> Richard B. expressed doubts about this on IRC, so for a bit more detail:
>
> The comparisons we're doing are on the range of an SSA name.
> There are three ways that these ranges could be stored in the
> range_info_def:
>
> (1) as INTEGER_CSTs. This was felt to be unacceptable because it would
> create too many garbage constants.
>
> (2) as widest_ints. This too was unacceptable because it would bloat
> the range_info_def.
>
> (3) as a form of wide_int in which the HWIs are allocated as a trailing
> part of the containing structure. This means that range_info_defs
> for 64-bit types only have 3 HWIs (smaller than now).
>
> We went for (3).
>
> Having decided to store the ranges like wide_ints, the question then is:
> what about the get/set_range_info interface? Two obvious options are:
>
> (a) present the ranges as wide_ints.
>
> (b) present the ranges as widest_ints, converting in and out as necessary.
>
> (a) is more efficient and seems to fit well with the pre-ubsan callers,
> so that's what was chosen.
>
> In the patch we have two wide_ints that have the same precision as the
> SSA name. The values we were creating via wi::min_value and wi::max_value
> instead had half that precision. This is the same kind of mismatch as
> you'd get comparing HImode and SImode in RTL, say.
>
> We could fix the bug by using something like:
>
> if (wi::les_p (arg0_max, wi::mask (hprec, false, prec))
> && wi::les_p (wi::mask (hprec, true, prec), arg0_min))
>
> etc. Or we could extend the wide_ints to widest_ints so that "precision
> doesn't matter" when doing the comparisons. But both those options
> involve temporaries and seem unnecessarily complicated. All we're
> really asking here is: what is the minimum precision needed to represent
> this constant? That's something that could be generally useful
> (e.g. when checking whether a value fits a type) so the patch adds
> a corresponding wi:: function.
Ah, that makes sense now ;)
Thus the patch is ok.
Thanks,
Richard.
> Thanks,
> Richard
>
>
>>
>> Thanks,
>> Richard
>>
>>
>> Index: gcc/internal-fn.c
>> ===================================================================
>> --- gcc/internal-fn.c 2014-04-22 20:31:10.516895118 +0100
>> +++ gcc/internal-fn.c 2014-04-22 20:31:25.842005530 +0100
>> @@ -478,7 +478,7 @@ ubsan_expand_si_overflow_mul_check (gimp
>> rtx do_overflow = gen_label_rtx ();
>> rtx hipart_different = gen_label_rtx ();
>>
>> - int hprec = GET_MODE_PRECISION (hmode);
>> + unsigned int hprec = GET_MODE_PRECISION (hmode);
>> rtx hipart0 = expand_shift (RSHIFT_EXPR, mode, op0, hprec,
>> NULL_RTX, 0);
>> hipart0 = gen_lowpart (hmode, hipart0);
>> @@ -513,12 +513,11 @@ ubsan_expand_si_overflow_mul_check (gimp
>> wide_int arg0_min, arg0_max;
>> if (get_range_info (arg0, &arg0_min, &arg0_max) == VR_RANGE)
>> {
>> - if (wi::les_p (arg0_max, wi::max_value (hprec, SIGNED))
>> - && wi::les_p (wi::min_value (hprec, SIGNED), arg0_min))
>> + unsigned int mprec0 = wi::min_precision (arg0_min, SIGNED);
>> + unsigned int mprec1 = wi::min_precision (arg0_max, SIGNED);
>> + if (mprec0 <= hprec && mprec1 <= hprec)
>> op0_small_p = true;
>> - else if (wi::les_p (arg0_max, wi::max_value (hprec, UNSIGNED))
>> - && wi::les_p (~wi::max_value (hprec, UNSIGNED),
>> - arg0_min))
>> + else if (mprec0 <= hprec + 1 && mprec1 <= hprec + 1)
>> op0_medium_p = true;
>> if (!wi::neg_p (arg0_min, TYPE_SIGN (TREE_TYPE (arg0))))
>> op0_sign = 0;
>> @@ -531,12 +530,11 @@ ubsan_expand_si_overflow_mul_check (gimp
>> wide_int arg1_min, arg1_max;
>> if (get_range_info (arg1, &arg1_min, &arg1_max) == VR_RANGE)
>> {
>> - if (wi::les_p (arg1_max, wi::max_value (hprec, SIGNED))
>> - && wi::les_p (wi::min_value (hprec, SIGNED), arg1_min))
>> + unsigned int mprec0 = wi::min_precision (arg1_min, SIGNED);
>> + unsigned int mprec1 = wi::min_precision (arg1_max, SIGNED);
>> + if (mprec0 <= hprec && mprec1 <= hprec)
>> op1_small_p = true;
>> - else if (wi::les_p (arg1_max, wi::max_value (hprec, UNSIGNED))
>> - && wi::les_p (~wi::max_value (hprec, UNSIGNED),
>> - arg1_min))
>> + else if (mprec0 <= hprec + 1 && mprec1 <= hprec + 1)
>> op1_medium_p = true;
>> if (!wi::neg_p (arg1_min, TYPE_SIGN (TREE_TYPE (arg1))))
>> op1_sign = 0;
>> Index: gcc/wide-int.h
>> ===================================================================
>> --- gcc/wide-int.h 2014-04-22 20:31:10.516895118 +0100
>> +++ gcc/wide-int.h 2014-04-22 20:31:25.842005530 +0100
>> @@ -562,6 +562,9 @@ #define SHIFT_FUNCTION \
>>
>> template <typename T>
>> unsigned HOST_WIDE_INT extract_uhwi (const T &, unsigned int, unsigned int);
>> +
>> + template <typename T>
>> + unsigned int min_precision (const T &, signop);
>> }
>>
>> namespace wi
>> @@ -2995,6 +2998,17 @@ wi::extract_uhwi (const T &x, unsigned i
>> return zext_hwi (res, width);
>> }
>>
>> +/* Return the minimum precision needed to store X with sign SGN. */
>> +template <typename T>
>> +inline unsigned int
>> +wi::min_precision (const T &x, signop sgn)
>> +{
>> + if (sgn == SIGNED)
>> + return wi::get_precision (x) - clrsb (x);
>> + else
>> + return wi::get_precision (x) - clz (x);
>> +}
>> +
>> template<typename T>
>> void
>> gt_ggc_mx (generic_wide_int <T> *)
More information about the Gcc-patches
mailing list