[llvm-dev] lifetime.start/end

Johannes Doerfert via llvm-dev llvm-dev at lists.llvm.org
Tue Jan 19 15:24:59 PST 2021


On 1/19/21 11:37 AM, James Y Knight wrote:
> I haven't followed the whole discussion here, so I'm not sure if I've
> understood the proposal correctly, but I'm a bit concerned.
>
> In the IR generated by Clang, lifetime markers are inserted to denote the
> scope of the variable's storage. As such, it ought to be entirely valid to
> coalesce the variables x and y to a single address in the following
> example, *even though* the addresses both escape and are compared:
>
> int *p_x, *p_y;
> int test() {
>    {
>      int x = 5;
>      p_x = &x;
>    }
>    {
>      int y = 5;
>      p_y = &y;
>    }
>    return p_x == p_y;
> }
>
> Although we don't currently appear to do such coalescing, it would seem
> unfortunate to define the IR so as to prohibit it.

I am still doubtful that my proposed "restrictions" are really impacting
our ability to do coalescing in practice. I'm also surprised it didn't
happen here. FWIW, my proposed restrictions would forbid it to happen
only as long as we did not fold the comparison. The comparison could be
folded since the pointers are not otherwise observed, thus this example
would/should be in the realm of possibility (now and then).


>
> Furthermore, it's not clear to me that the comparison at the end is
> actually required to return a consistent answer. The deallocation of x and
> y magically transforms all pointers to them into "invalid pointer values",
> the use of which is implementation defined [https://wg21.link/basic.stc]. I
> think it'd be OK for the implementation to say that deallocation turns all
> such pointers into indeterminate values -- and, thus, to end up with (p_x
> == p_y) being false, and yet, for a subsequent `printf("%p %p\n", p_x,
> p_y);` to print the same value twice.

That argument is interesting but has the problem that it makes our LICM and
inliner wrong, doesn't it? (Side note, what happens if we do `intptr_t 
xp = &x;`?
Even if x goes out of scope this should be fine, right?)

For LICM and inliner, if lifetime markers make pointers "invalid" we 
cannot hoist
uses across them, which we do. I feat not doing that has a higher 
practical impact
than what I was proposing, though I have not run any experiments.

(When I talk about my proposed restrictions I mean what was described 
here: https://lists.llvm.org/pipermail/llvm-dev/2021-January/147594.html )

~ Johannes


>
> On Mon, Jan 18, 2021, 5:05 PM Johannes Doerfert via llvm-dev <
> llvm-dev at lists.llvm.org> wrote:
>
>> On 1/12/21 4:11 PM, Michael Kruse wrote:
>>> Am Di., 12. Jan. 2021 um 12:33 Uhr schrieb Ralf Jung via llvm-dev
>>> <llvm-dev at lists.llvm.org>:
>>>> I hope this question has not been answered yet, but I don't see how
>> that fold
>>>> could be legal. I asked the same question on Phabricator but it seems
>> you prefer
>>>> to have the discussion here. Taking your example from there and
>> adjusting it:
>>>> p = malloc(1)
>>>> q = malloc(1)
>>>> %c = icmp eq %p, %q
>>>> free(q)
>>>> free(p)
>>>>
>>>> I think there is a guarantee that c will always be "false". Every
>> operational
>>>> model of allocation that I have ever seen will guarantee this, and the
>> same for
>>>> every program logic that I can imagine. So if the compiler may fold
>> this to
>>>> "false", then as far as I can see, pointer comparison becomes entirely
>>>> unpredictable. The only consistent model I can think of is "icmp on
>> pointers may
>>>> spuriously return 'true' at any time", which I doubt anyone wants. ;)
>>> In my understanding of
>>> https://timsong-cpp.github.io/cppwp/n3337/expr.rel#2.2 or
>>> http://eel.is/c++draft/expr.rel#4.3 the result of this is unspecified.
>>> While this does not necessarily extend to LLVM-IR, LLVM-IR usually
>>> assumes C/C++ semantics unless defined otherwise.
>> I also thought the above is fine.
>>
>>
>>> Optimizations such as https://reviews.llvm.org/D53362 and
>>> https://reviews.llvm.org/D65408 assume the equivalence of alloca and
>>> malloc+free. I assume that such optimizations are the reason for this
>>> unspecifiedness, i.e. I think someone might want this. Johannes's
>>> proposal A1 however, seems to forbid StackColoring to exploit lifetime
>>> markers, which it currently does and I am not sure we can afford to do
>>> that.
>> It's not that A1 "forbid[s] StackColoring to exploit lifetime markers", but
>> A1 says that you cannot use lifetime markers to argue about the address. So
>> you can still use them for reasoning but only as far as they tell you the
>> content is undef. If you want to do coalescing, you need to verify more
>> things,
>> especially that the addresses are not (both) observed. If they are,
>> which they
>> can be with lifetime markers in place as well, you end up with
>> inconsistent views.
>>
>> That said, if we want to preserve the property that you cannot access
>> outside of
>> lifetime ranges, you could "fix" StackColoring by simply verifying one
>> of the two
>> allocas is not escaping. You'd still need to fix InstCombine but the fix
>> is the same.
>> I'm not sure we want to declare accesses outside of lifetime ranges UB
>> or not. I imagine
>> in practice this makes little difference anyway, given that escaping
>> uses are a problem
>> on their own.
>>
>> ~ Johannes
>>
>>
>>> Michael
>> _______________________________________________
>> LLVM Developers mailing list
>> llvm-dev at lists.llvm.org
>> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
>>


More information about the llvm-dev mailing list