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

Johannes Doerfert via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Fri Dec 18 00:01:30 PST 2020


jdoerfert added a comment.

In D93376#2462175 <https://reviews.llvm.org/D93376#2462175>, @aqjune wrote:

> If a heap allocation is allowed, it really brings another level of complexity.
> No one knows what lifetime.start of malloc really means; there is no optimization that works on it, it's nontrivial to decide how it interacts with free(), etc.

Why wouldn't/shouldn't it mean exactly what it means for stack allocations?
"The memory region specified in the lifetime start is dead until a lifetime start makes that memory accessible, ..."
Could you explain what is nontrivial about the interaction with free?

> We're leaving a construct something that is really hard to be used. In perspective of the frontend, simply placing malloc()/free() or memset(undef) or their own marker at the place where lifetime.start/lifetime.end are supposed to be would have been a better choice.

I'm not so sure about that. memset(undef) is, for example, not recognized commonly while `hasOnlyLifetimeUsers` (or similar) is a common check. Moving malloc/free may come with a cost.  Placing the malloc/free in a loop is a totally different story than placing lifetime markers in there. Imagine you have a heap allocation in a loop and the FE (or something else) places the malloc earlier instead and uses lifetime markers to assure the middle end that there are no loop carried dependences via this memory region. (Also, we should implement this transformation, it could not only save time wrt. allocations but also allow vectorization, especially given the lifetime markers.)

> Perhaps the best thing to do is to ask how lifetime intrinsic is used in other frontends/projects. I'll send a mail to llvm-dev.

That can't hurt but the absence of users shouldn't be the only factor (IMHO). Above I already sketched an optimization to use them (by accident).

In D93376#2462187 <https://reviews.llvm.org/D93376#2462187>, @aqjune wrote:

> [...] Optimizations can transform lifetime's argument, such as bitcast -> gep (as @nikic said) or merging two lifetime calls in if-else branches and introducing phi. I'll change the syntactic constraint to be more generous. Syntactic constraint is needed anyway, otherwise we really don't know which object is passed to `lifetime.start`. Assume that a pointer p is passed to `call f(p)`, which is doing `lifetime.start(p)`.

I disagree that syntactic constraints are needed, in a generic sense, and I find they often make the IR harder to work with. I'm not sure I understand your example but I guess if you inline the call the lifetime argument could be syntactically something else, right? So it might become syntactically useful even if it wasn't before. The PHI case is the opposite. It started to be syntactically useful, i.a., alloca arguments, but after sinking there might not be a single alloca but a phi picking one. Arguably, the information is no different. A user could easily determine all the underlying objects and filter the allocas.


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