[PATCH] D93376: [LangRef] Clarify the semantics of lifetime intrinsics

Juneyoung Lee via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Fri Dec 18 15:43:45 PST 2020


aqjune added a comment.

Are existing heap optimizations checking whether a malloc is used by lifetime.start/end?
I see that `dereferenceable_or_null(n)` is always attached to `call i8* malloc(<n>)`. If lifetime.start/end can take a heap pointer, its lifetime may start way after this call, so malloc isn't immediately dereferenceable even if it isn't null.
We can change the semantics of `dereferenceable_or_null`, but this can transitively require changes to other attributes or dereferenceability analyses.

In D93376#2463188 <https://reviews.llvm.org/D93376#2463188>, @jdoerfert wrote:

> Sure. You could do the same transformation with heap objects under the same constraints. So you go from 
> ... (snip)

I think there are more cases to consider, such as:

  p = malloc(1)
  lifetime.start(p)
  lifetime.end(p)
  q = malloc(1)
  // Can the addresses of p and q overlap?
  free(q)
  lifetime.start(p)
  lifetime.end(p)
  free(p)

That is why I still prefer memset(undef); it may be a churn to teach that memset(undef) is a canonicalized form to e.g., loop dependence analysis, but teaching lifetime also needs churn.
Most importantly, memset's semantics is crystal clear; it doesn't change the object's address. It also naturally supports a thing that is analogous to 'partial lifetime start'.

>> It's because it can introduce UB. Consider this example:
>>
>>   p = alloca i32
>>   store 0, p // analysis will say this is perfectly fine
>>   f(p) // lifetime.start(p) is hidden in f(p)
>>
>> After inlining:
>>
>>   p = alloca i32
>>   store 0, p
>>   lifetime.start(p) // this makes the above store raise UB 
>
> Given the proposed semantic of lifetime.start, the program had UB semantics prior to inlining, we might not have known it statically but that is not an issue.

But it would be great to say that alloca is simply dereferenceable as far as it isn't used by any lifetime.start/end, isn't it?
We don't want to assume that a function call may affect lifetime of escaped local variables, and IMO this is what LLVM assumes as well.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D93376/new/

https://reviews.llvm.org/D93376



More information about the llvm-commits mailing list