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