[LLVMdev] lifetime.start/end clarification
Philip Reames
listmail at philipreames.com
Wed Nov 5 10:21:04 PST 2014
On 11/04/2014 03:59 AM, Arnaud A. de Grandmaison wrote:
>
> The LRM
> (http://llvm.org/docs/LangRef.html#llvm-lifetime-start-intrinsic)
> essentially states that:
>
> - ptr is dead before a call to “lifetime.start size, ptr”
>
> - ptr is dead after a call to “lifetime.end size, ptr”
>
> This is all good and fine, and the expected use case is that all
> “lifetime.end size, ptr” markers are matched with a preceding
> “lifetime.start size, ptr” in the CFG.
>
> What is supposed to happen when a “lifetime.end size, ptr” is not
> matched with a “lifetime.start size, ptr” ? I think there are a few
> possible answers:
>
> - the memory area pointed to by ptr is assumed to be alive since
> function entry
>
> - the memory area pointed to by ptr is assumed to be dead since
> function entry, as it has not been marked alive
>
> - this is an unexpected situation
>
My reading of the current spec is that your first option is the only
valid interpretation.
My interpretation of the spec wording would be that each path in the
program may contain either a lifetime.start, a lifetime.end, or both.
If the path contains no marker, the location is assumed live (unless
proven otherwise). The lifetime markers segment the path into live, and
dead regions, but only on that specific path. To reason about global
properties, the optimizer must form "for-all-paths" facts. (Dominance
being the easiest form of this generally.)
Just to note, this is rather different than the "invariant.*" family.
In particular, the invariant family requires the "start" as an argument
to the "end" intrinsic.
> I think this ambiguity should be cleared in the LRM, because today’s
> implicit assumption may be broken at any time.
>
I believe the existing implementation matches the semantics I specified
above. If you find a case where it doesn't, that's a bug.
>
> This is not a theoretical question: clang can generate such cases. For
> example, the following testcase:
>
> struct X {
>
> void doSomething();
>
> char b[33];
>
> };
>
> void bar(X &);
>
> void baz();
>
> void test(int i) {
>
> if (i==9) {
>
> X x;
>
> x.doSomething();
>
> label:
>
> bar(x);
>
> } else {
>
> baz();
>
> if (i==0)
>
> goto label;
>
> }
>
> }
>
> Produces:
>
> %struct.X = type { [33 x i8] }
>
> define void @_Z4testi(i32 %i) {
>
> entry:
>
> %x = alloca %struct.X, align 1
>
> %cmp = icmp eq i32 %i, 9
>
> br i1 %cmp, label %if.then, label %if.else
>
> if.then: ; preds = %entry
>
> %0 = getelementptr inbounds %struct.X* %x, i64 0, i32 0, i64 0
>
> call void @llvm.lifetime.start(i64 33, i8* %0)
>
> call void @_ZN1X11doSomethingEv(%struct.X* %x)
>
> br label %label
>
> label: ; preds = %if.else.label_crit_edge, %if.then
>
> %.pre-phi = phi i8* [ %.pre, %if.else.label_crit_edge ], [ %0,
> %if.then ]
>
> call void @_Z3barR1X(%struct.X* dereferenceable(33) %x)
>
> call void @llvm.lifetime.end(i64 33, i8* %.pre-phi)
>
> br label %if.end3
>
> if.else: ; preds = %entry
>
> tail call void @_Z3bazv()
>
> %cmp1 = icmp eq i32 %i, 0
>
> br i1 %cmp1, label %if.else.label_crit_edge, label %if.end3
>
> if.else.label_crit_edge: ; preds = %if.else
>
> %.pre = getelementptr inbounds %struct.X* %x, i64 0, i32 0, i64 0
>
> br label %label
>
> if.end3: ; preds = %if.else, %label
>
> ret void
>
> }
>
> Note that the path thru if.else.label_crit_edge has no lifetime start.
>
This seems fine to me. The optimizer can (soundly) conclude that %p is
dead after the "lifetime.end" (for the two instructions), and dead
before the "lifetime.start" (for the *single* instruction in that basic
block, *not* for the previous BB). This seems like the proper result
for this example, am I missing something?
Philip
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20141105/7cf63cb2/attachment.html>
More information about the llvm-dev
mailing list