<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40"><head><meta http-equiv=Content-Type content="text/html; charset=us-ascii"><meta name=Generator content="Microsoft Word 14 (filtered medium)"><style><!--
/* Font Definitions */
@font-face
        {font-family:Calibri;
        panose-1:2 15 5 2 2 2 4 3 2 4;}
@font-face
        {font-family:Tahoma;
        panose-1:2 11 6 4 3 5 4 4 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
        {margin:0cm;
        margin-bottom:.0001pt;
        font-size:11.0pt;
        font-family:"Calibri","sans-serif";
        color:black;
        mso-fareast-language:EN-US;}
a:link, span.MsoHyperlink
        {mso-style-priority:99;
        color:blue;
        text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
        {mso-style-priority:99;
        color:purple;
        text-decoration:underline;}
span.EmailStyle17
        {mso-style-type:personal;
        font-family:"Calibri","sans-serif";
        color:windowtext;}
span.EmailStyle18
        {mso-style-type:personal-reply;
        font-family:"Calibri","sans-serif";
        color:#1F497D;}
.MsoChpDefault
        {mso-style-type:export-only;
        font-size:10.0pt;}
@page WordSection1
        {size:612.0pt 792.0pt;
        margin:72.0pt 72.0pt 72.0pt 72.0pt;}
div.WordSection1
        {page:WordSection1;}
--></style><!--[if gte mso 9]><xml>
<o:shapedefaults v:ext="edit" spidmax="1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1" />
</o:shapelayout></xml><![endif]--></head><body bgcolor=white lang=EN-GB link=blue vlink=purple><div class=WordSection1><p class=MsoNormal><span style='color:#1F497D'><o:p> </o:p></span></p><p class=MsoNormal><span style='color:#1F497D'><o:p> </o:p></span></p><div><div style='border:none;border-top:solid #B5C4DF 1.0pt;padding:3.0pt 0cm 0cm 0cm'><p class=MsoNormal style='margin-left:36.0pt'><b><span lang=EN-US style='font-size:10.0pt;font-family:"Tahoma","sans-serif";color:windowtext;mso-fareast-language:EN-GB'>From:</span></b><span lang=EN-US style='font-size:10.0pt;font-family:"Tahoma","sans-serif";color:windowtext;mso-fareast-language:EN-GB'> Philip Reames [mailto:listmail@philipreames.com] <br><b>Sent:</b> 05 November 2014 19:21<br><b>To:</b> Arnaud De Grandmaison; LLVM Developers Mailing List<br><b>Subject:</b> Re: [LLVMdev] lifetime.start/end clarification<o:p></o:p></span></p></div></div><p class=MsoNormal style='margin-left:36.0pt'><o:p> </o:p></p><p class=MsoNormal style='margin-left:36.0pt'><o:p> </o:p></p><div><p class=MsoNormal style='margin-left:36.0pt'>On 11/04/2014 03:59 AM, Arnaud A. de Grandmaison wrote:<o:p></o:p></p></div><blockquote style='margin-top:5.0pt;margin-bottom:5.0pt'><p class=MsoNormal style='margin-left:36.0pt'>The LRM (<a href="http://llvm.org/docs/LangRef.html#llvm-lifetime-start-intrinsic">http://llvm.org/docs/LangRef.html#llvm-lifetime-start-intrinsic</a>) essentially  states that:<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>- ptr is dead before a call to “lifetime.start size, ptr”<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>- ptr is dead after a call to “lifetime.end size, ptr”<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'> <o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>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.<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'> <o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>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:<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>- the memory area pointed to by ptr is assumed to be alive since function entry<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>- the memory area pointed to by ptr is assumed to be dead since function entry, as it has not been marked alive<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>- this is an unexpected situation<o:p></o:p></p></blockquote><p class=MsoNormal style='margin-left:36.0pt'><span style='font-size:12.0pt;font-family:"Times New Roman","serif";mso-fareast-language:EN-GB'>My reading of the current spec is that your first option is the only valid interpretation.<br><br>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.)<br><br></span><span style='font-size:12.0pt;font-family:"Times New Roman","serif";color:#1F497D;mso-fareast-language:EN-GB'><o:p></o:p></span></p><p class=MsoNormal><span style='color:#1F497D;mso-fareast-language:EN-GB'>You worded the above as your interpretation of the spec. I agree your interpretation is the sanest one. <o:p></o:p></span></p><p class=MsoNormal style='margin-left:36.0pt'><span style='font-size:12.0pt;font-family:"Times New Roman","serif";mso-fareast-language:EN-GB'><br>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.<br><br><br><o:p></o:p></span></p><p class=MsoNormal style='margin-left:36.0pt'> <o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>I think this ambiguity should be cleared in the LRM, because today’s implicit assumption may be broken at any time.<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'><span style='font-size:12.0pt;font-family:"Times New Roman","serif";mso-fareast-language:EN-GB'>I believe the existing implementation matches the semantics I specified above.  If you find a case where it doesn't, that's a bug.  <br><br><o:p></o:p></span></p><p class=MsoNormal><span style='color:#1F497D;mso-fareast-language:EN-GB'>I checked the stack coloring (the only real user of the lifetime markers), and it seems to match this semantics.<o:p></o:p></span></p><p class=MsoNormal style='margin-left:36.0pt'> <o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>This is not a theoretical question: clang can generate such cases. For example, the following testcase:<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>struct X {<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>  void doSomething();<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>  char b[33];<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>};<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'> <o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>void bar(X &);<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>void baz();<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'> <o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>void test(int i) {<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>  if (i==9) {<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>    X x;<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>    x.doSomething();<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>label:<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>    bar(x);<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>  } else {<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>    baz();<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>    if (i==0)<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>      goto label;<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>  }<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>}<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'> <o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>Produces:<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'> <o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>%struct.X = type { [33 x i8] }<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'> <o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>define void @_Z4testi(i32 %i) {<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>entry:<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>  %x = alloca %struct.X, align 1<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>  %cmp = icmp eq i32 %i, 9<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>  br i1 %cmp, label %if.then, label %if.else<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'> <o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>if.then:                                          ; preds = %entry<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>  %0 = getelementptr inbounds %struct.X* %x, i64 0, i32 0, i64 0<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>  call void @llvm.lifetime.start(i64 33, i8* %0)<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>  call void @_ZN1X11doSomethingEv(%struct.X* %x)<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>  br label %label<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'> <o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>label:                                            ; preds = %if.else.label_crit_edge, %if.then<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>  %.pre-phi = phi i8* [ %.pre, %if.else.label_crit_edge ], [ %0, %if.then ]<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>  call void @_Z3barR1X(%struct.X* dereferenceable(33) %x)<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>  call void @llvm.lifetime.end(i64 33, i8* %.pre-phi)<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>  br label %if.end3<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'> <o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>if.else:                                          ; preds = %entry<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>  tail call void @_Z3bazv()<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>  %cmp1 = icmp eq i32 %i, 0<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>  br i1 %cmp1, label %if.else.label_crit_edge, label %if.end3<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'> <o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>if.else.label_crit_edge:                          ; preds = %if.else<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>  %.pre = getelementptr inbounds %struct.X* %x, i64 0, i32 0, i64 0<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>  br label %label<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'> <o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>if.end3:                                          ; preds = %if.else, %label<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>  ret void<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>}<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'> <o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>Note that the path thru if.else.label_crit_edge has no lifetime start.<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'><span style='font-size:12.0pt;font-family:"Times New Roman","serif";mso-fareast-language:EN-GB'>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?<br><br></span><span style='font-size:12.0pt;font-family:"Times New Roman","serif";color:#1F497D;mso-fareast-language:EN-GB'><o:p></o:p></span></p><p class=MsoNormal><span style='color:#1F497D;mso-fareast-language:EN-GB'>With the clarification you made on the semantics, the above IR is correct, but could be improved when clang generates it: the label_crit_edge block should contain a lifetime.start for the alloca.<o:p></o:p></span></p><p class=MsoNormal style='margin-left:36.0pt'><span style='font-size:12.0pt;font-family:"Times New Roman","serif";mso-fareast-language:EN-GB'><br>Philip<o:p></o:p></span></p></div></body></html>