On 12/16/25 07:45, Siddhesh Poyarekar wrote:
On 2025-12-15 15:50, Andrew MacLeod wrote:
I am experimenting with integrating VRP's Points-to analysis into
prange. Its currently managed on the side via the class in
value_pointer_equiv.{cc,h} which maintains a global side table and a
push/pop for conditions during the dominator walk.
I have managed to get it mostly working, but Im running into an issue
with runtime and the Object Size Checking Built-in Functions such as
__builtin___memcpy_chk
I see we often generate code like
_1 = __builtin_memcpy (&buf1, "ABCDEFGHI", 9);
if (_1 != &buf1)
goto abort ();
but the builtin function fnspec string is "1cO313" which says that _1
will always return the first argument,, which is &buf1. It therefore
seems like we can fold away the condition in this case... Which
ranger and the enhanced prange does. This seems to cause no problem.
Where i do run into a problem is in gcc.c-torture/execute/builtins/
memcpy-chk.c , everything passes fine up until this point in
test2_sub () :
/* buf3 points to an unknown object, so __memcpy_chk should not be
done. */
if (memcpy ((char *) buf3 + 4, buf5, n + 6) != (char *) buf1 + 4
|| memcmp (buf1, "aBcdRSTUVWklmnopq\0", 19))
abort ();
With my changes, this sequence goes from
<bb 31> :
__builtin___memcpy_chk (buf3_60(D), "aBcdEFghijklmnopq\x00", 19, _5);
_47 = n_73(D) + 6;
_48 = (long unsigned int) _47;
_50 = __builtin___memcpy_chk (_19, &buf5, _48, _20);
if (_50 != &MEM <long int[64]> [(void *)&buf1 + 4B])
goto <bb 33>; [INV]
else
goto <bb 32>; [INV]
<bb 32> :
_52 = memcmp (&buf1, "aBcdRSTUVWklmnopq\x00", 19);
if (_52 != 0)
goto <bb 33>; [INV]
else
goto <bb 34>; [INV]
<bb 33> :
abort ();
to
<bb 23> :
__builtin___memcpy_chk (&buf1, "aBcdEFghijklmnopq\x00", 19, _5);
_47 = n_73(D) + 6;
_48 = (long unsigned int) _47;
_50 = __builtin___memcpy_chk (&MEM <long int[64]> [(void *)&buf1 +
4B], &buf5, _48, 508);
_52 = memcmp (&buf1, "aBcdRSTUVWklmnopq\x00", 19);
if (_52 != 0)
goto <bb 24>; [INV]
else
goto <bb 25>; [INV]
<bb 24> :
abort ();
The new integrated PTA figures out a couple of things.. first, it knows
* from earlier that buf3 and buf1 points to the same thing,
* and can also figure out that buf3 + 4 == buf1 + 4, so it can
fold away the condition afterwards since arg1 is the result
How does it know of this equivalence? Is PTA somehow ignoring
__noinline__?
No, it earlier in the function we have a few statements like :
if (memcpy (buf3, buf5, 8) != (char *) buf1
abort ();
which translates into
_9 = __builtin___memcpy_chk (buf3_60(D), "a", 1, _5);
if (_9 != &buf1)
goto <bb 13>; [INV]
else
goto <bb 12>; [INV]
where it can establish that buf3_60 == &buf1 since _9 == buf3_60 and _9
== &buf1 from bb12 onward
Andrew