Hi,

On Thu, Nov 07 2024, Aldy Hernandez wrote:
> Aldy Hernandez <a...@quesejoda.com> writes:
>
>> Martin Jambor <mjam...@suse.cz> writes:
>>
>>> Hi,
>>>
>>> Because the simplified way of extracting value ranges from functions
>>> does not look at scalar constants (as one of the versions had been
>>> doing before) but instead rely on the value range within the jump
>>> function already capturing the constant, I have added a verifier that
>>> it is indeed so.  After the fixes in the previous patches, the
>>> verifier passes bootstrap and testsuite.
>>>
>>> The verifier is however a bit lenient when it comes to pranges.  When
>>> a prange for an ADDR_EXPR of a DECL results in a non-NULL prange
>>> adjusted with known alignment, but this is then converted to an
>>> integer because that is what the compiled source does as is the case
>>> for example in testcase gcc.c-torture/compile/pr71109.c.  While as
>>> long as we track the address in a prange we do capture the
>>> non-nullness:
>>>
>>>   [prange] void (*<Txxxx>) (void) [1, +INF] MASK 0xfffffffffffffffe VALUE 
>>> 0x0
>>>
>>> when it the range is folded into an integer we get
>>>
>>>   Value range: [irange] int [-INF, +INF] MASK 0xfffffffe VALUE 0x0
>>>
>>> which can contain zero.  I have not looked into detail whether there
>>> is anything we can do about this case or what it would be.
>>
>> Let's ignore the mask for a moment.  This range:
>>
>> [prange] void (*<Txxxx>) (void) [1, +INF] MASK 0xfffffffffffffffe VALUE 0x0
>>
>> ...casted to an int *does* include 0.  For example, 0x100000000UL casted
>> to a signed 32-bit int is 0.
>>
>> However, when we take into account the mask, 0 is clearly not possible
>> as the lowest bit is known to be 0.  This is an inherent problem we have
>> with sub-ranges and value/mask pairs not always being kept in sync.  The
>> reason we don't is because at one time there was a 5% slowdown in VRP
>> for doing so.  See this comment:
>
> Wait, wait... I'm clearly suffering from lack of sleep.
>
> MASK 0xfffffffffffffffe VALUE 0x0 means the lowest bit is known to be 0,
> so the range *can* contain a zero.  It's the range end points that say
> we can't have a zero: [1, +INF].  So the range and mask contradict each
> other which is actually a possibility as per my previous quote:
>
> [snip]
>   // This also means that the mask may have a finer granularity than
>   // the range and thus contradict it.  Think of the mask as an
>   // enhancement to the range.  For example:
>   //
>   // [3, 1000] MASK 0xfffffffe VALUE 0x0
>   //
>   // 3 is in the range endpoints, but is excluded per the known 0 bits
>   // in the mask.
>
> I think the presence of 0 in the casted range is correct.  For example:
>
> int main(){
>   long unsigned int p = 0x100000000;
>   int i;
>
>   printf("p = 0x%lx\n", p);
>   i = (int) p;
>   printf("i = %d\n", i);
> }
>
> aldy@abulafia:/tmp$ gcc a.c
> aldy@abulafia:/tmp$ ./a.out
> p = 0x100000000
> i = 0
>
> That is, we can have an unsigned 64-bit number with a clear least
> significant bit that when casted to a signed 32-bit integer yields a 0.
>
> Someone correct my math, but I believe the casted range can contain a
> zero, thus the new range looks right.

Right, as the width of the type shrinks, the non-null bits can be lost.
Thanks for looking into this.

Martin

Reply via email to