> -----Original Message----- > From: Hal Finkel [mailto:hfinkel at anl.gov] > Sent: 04 November 2014 17:16 > To: Arnaud De Grandmaison > Cc: LLVM Developers Mailing List > Subject: Re: [LLVMdev] lifetime.start/end clarification > > ----- Original Message ----- > > From: "Arnaud A. de Grandmaison" <arnaud.degrandmaison at arm.com> > > To: "LLVM Developers Mailing List" <llvmdev at cs.uiuc.edu> > > Sent: Tuesday, November 4, 2014 5:59:28 AM > > Subject: [LLVMdev] lifetime.start/end clarification > > > > 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 > > > > When you say "unmatched", do you mean not visible in any dominating > block? Assuming we realize that the lifetime begin could also be inside a > function called by any of these dominating blocks (assuming the pointer is an > argument or is captured prior to the call), it seems most logical to say that the > ptr is alive (and invariant) from the function entry.Yes, I meant not visible in any dominating block. I believe assuming the ptr is alive from the function entry is conservatively correct, but not optimal. In my testcase, a lifetime.start could be inserted in the crit_edge bb. Do we really want to handle cross-function stack lifetime analysis ? That's an interesting point. Until now, I supposed this all stayed inside the same function.> > > > > > > I think this ambiguity should be cleared in the LRM, because today’s > > implicit assumption > > What is today's implicit assumption?To be honest: I don't know. I have to dig it out of the stack coloring pass, which I think (but I may be wrong) is the only user of the lifetime markers.> > Thanks again, > Hal > > > may be broken at any time. > > > > > > > > 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. > > > > > > > > Cheers, > > > > -- > > > > Arnaud > > > > > > _______________________________________________ > > LLVM Developers mailing list > > LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu > > http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev > > > > -- > Hal Finkel > Assistant Computational Scientist > Leadership Computing Facility > Argonne National Laboratory
----- Original Message -----> From: "Arnaud A. de Grandmaison" <arnaud.degrandmaison at arm.com> > To: "Hal Finkel" <hfinkel at anl.gov> > Cc: "LLVM Developers Mailing List" <llvmdev at cs.uiuc.edu> > Sent: Tuesday, November 4, 2014 10:39:45 AM > Subject: RE: [LLVMdev] lifetime.start/end clarification > > > > > -----Original Message----- > > From: Hal Finkel [mailto:hfinkel at anl.gov] > > Sent: 04 November 2014 17:16 > > To: Arnaud De Grandmaison > > Cc: LLVM Developers Mailing List > > Subject: Re: [LLVMdev] lifetime.start/end clarification > > > > ----- Original Message ----- > > > From: "Arnaud A. de Grandmaison" <arnaud.degrandmaison at arm.com> > > > To: "LLVM Developers Mailing List" <llvmdev at cs.uiuc.edu> > > > Sent: Tuesday, November 4, 2014 5:59:28 AM > > > Subject: [LLVMdev] lifetime.start/end clarification > > > > > > 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 > > > > > > > When you say "unmatched", do you mean not visible in any dominating > > block? Assuming we realize that the lifetime begin could also be > > inside a > > function called by any of these dominating blocks (assuming the > > pointer is an > > argument or is captured prior to the call), it seems most logical > > to say that the > > ptr is alive (and invariant) from the function entry. > > Yes, I meant not visible in any dominating block. I believe assuming > the ptr is alive from the function entry is conservatively correct, > but not optimal. In my testcase, a lifetime.start could be inserted > in the crit_edge bb.I think that the conservative behavior is what we want for the definition of the intrinsics themselves. Now if we can do better in some cases by deducing subset of the CFG where the allocation is actually used (either in the backend or by using some cleanup pass that adds them), that's fine.> > Do we really want to handle cross-function stack lifetime analysis ? > That's an interesting point. Until now, I supposed this all stayed > inside the same function.As currently defined, that's unavoidable. Philip, as I recall, ran into this recently. If you've not already done so, I recommend you read the recent thread on 'Optimization hints for "constant" loads'. -Hal> > > > > > > > > > > > I think this ambiguity should be cleared in the LRM, because > > > today’s > > > implicit assumption > > > > What is today's implicit assumption? > > To be honest: I don't know. I have to dig it out of the stack > coloring pass, which I think (but I may be wrong) is the only user > of the lifetime markers. > > > > > Thanks again, > > Hal > > > > > may be broken at any time. > > > > > > > > > > > > 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. > > > > > > > > > > > > Cheers, > > > > > > -- > > > > > > Arnaud > > > > > > > > > _______________________________________________ > > > LLVM Developers mailing list > > > LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu > > > http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev > > > > > > > -- > > Hal Finkel > > Assistant Computational Scientist > > Leadership Computing Facility > > Argonne National Laboratory > > > > >-- Hal Finkel Assistant Computational Scientist Leadership Computing Facility Argonne National Laboratory
On 4 November 2014 16:39, Arnaud A. de Grandmaison <arnaud.degrandmaison at arm.com> wrote:> Yes, I meant not visible in any dominating block. I believe assuming the ptr is alive from the function entry is conservatively correct, but not optimal. In my testcase, a lifetime.start could be inserted in the crit_edge bb.Don't you mean "not visible from at least one dominating path"? You may have many paths through (perhaps the same) blocks from the beginning of the function to a lifetime.end call, and if at least one of them doesn't have lifetime.start(), you're doomed. You'd have to scan all paths, not just the blocks, where lifetime.start could be defined. I agree function entry is a safe assumption. cheers, --renato
> -----Original Message----- > From: Renato Golin [mailto:renato.golin at linaro.org] > Sent: 04 November 2014 18:17 > To: Arnaud De Grandmaison > Cc: Hal Finkel; LLVM Developers Mailing List > Subject: Re: [LLVMdev] lifetime.start/end clarification > > On 4 November 2014 16:39, Arnaud A. de Grandmaison > <arnaud.degrandmaison at arm.com> wrote: > > Yes, I meant not visible in any dominating block. I believe assuming the ptr > is alive from the function entry is conservatively correct, but not optimal. In > my testcase, a lifetime.start could be inserted in the crit_edge bb. > > Don't you mean "not visible from at least one dominating path"?Ooops. Yes, I meant if there exists at least one path from function entry to lifetime.end without a the lifetime.start.> > You may have many paths through (perhaps the same) blocks from the > beginning of the function to a lifetime.end call, and if at least one of them > doesn't have lifetime.start(), you're doomed. You'd have to scan all paths, > not just the blocks, where lifetime.start could be defined. > > I agree function entry is a safe assumption. > > cheers, > --renato