So, in hacking on mem2reg I noticed that it doesn’t actually implement optimizations enabled by lifetime markers. I thought I might take a stab at teaching it about them, but I’m left with some questions about the semantics. Much of this may have been hash out when they were added, and if so I’ll appreciate your help educating me, and maybe we can come up with improved documentation to cover this.
First, is there any realistic intent that these be used for heap pointers? If so, what is the expected use case?
Second, if the answer to the first is ‘no’, then could we remove the ‘start’ intrinsic? It seems redundant as the value of an alloca prior to a store to that alloca is already ‘undef’.
Third, what is the semantic model intended for the size argument? The documentation says:
The first argument is a constant integer representing the size of the object, or -1 if it is variable sized.
Part of this seems a bit confusingly specified – what does it mean by “the object”? I assume what it really means is the object read from memory by a corresponding load, but that in and of itself is confusing because the pointer passed to this routine is typically not the pointer loaded. There might be many different loads of different type objects all corresponding to the same lifetime intrinsic.
The best way I have of interpreting it is in terms of the ‘end’ intrinsic: the results of it is equivalent to that of a notional store of ‘[i8 x N] undef’ to the provided pointer where N is the size. However, this becomes truly muddy in the presence of ‘-1’ size which just means a “variable” size. But how much is variable? Where does the undef stop?
I think the whole thing would be somewhat clearer as an intrinsic with an arbitrary pointer type and a boolean flag for ‘is_variable_length’. If the flag is false (common), the pointee type’s store size is the size of the region whose lifetime is marked. If the flag is true, the pointer must be an alloca instruction itself with a runtime size, and the entire alloca’s lifetime is marked. Among other benefits, this would make mem2reg and other analyzes easier and faster by decreasing the bitcast or gep instructions that result from common frontend lowering patterns. It also matches more closely the behavior of load and store.