This is a proposal for clarifying the semantics of lifetime.start / lifetime.end with @nlopes, @RalfJung.
IIUC, the intrinsics are introduced to represent lifetimes of local variables while keeping allocas at the entry block in IR.
However, their semantics was poorly described in LangRef.
The proposal is consistent with a description about MIR's LIFETIME_START/LIFETIME_END markers
at StackColoring.cpp (https://github.com/llvm/llvm-project/blob/eb44682d671d66e422b02595a636050582a4d84a/llvm/lib/CodeGen/StackColoring.cpp#L163),
with additional syntactic constraints for valid lifetime intrinsic calls.
To summarize, this patch specifies that:
- The alloca is initially *dead* if it is syntactically used by any llvm.lifetime.start.
- Dereferencing a dead alloca is UB, but gep/ptrtoint to a dead alloca returns a valid value (explains LICM: https://gcc.godbolt.org/z/Wo9dbo)
- A program that contains a path executing lifetime.start twice to same alloca is ill-formed. LLVM may raise assertion failure when such program is given.
- lifetime.start may not be paired with lifetime.end in some execution (see https://gcc.godbolt.org/z/e7sdh1 , written by @nlopes)
- Lifetime intrinsics' ptr should be either alloca or bitcast(alloca). I couldn't come up with a reasonable scenario where frontend generates lifetime intrinsics with non-stack objects. For heap allocations we can assume the allocation call/free call is simply its lifetime.
or a zero-index GEP, because we canoncalize bitcasts to that.