<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;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
        {margin:0in;
        margin-bottom:.0001pt;
        font-size:11.0pt;
        font-family:"Calibri","sans-serif";}
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-compose;
        font-family:"Calibri","sans-serif";
        color:windowtext;}
.MsoChpDefault
        {mso-style-type:export-only;
        font-family:"Calibri","sans-serif";}
@page WordSection1
        {size:8.5in 11.0in;
        margin:1.0in 1.0in 1.0in 1.0in;}
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 lang="EN-US" link="blue" vlink="purple">
<div class="WordSection1">
<p class="MsoNormal">Hi all,<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">Is it allowed to use the @llvm.lifetime.end intrinsic to optimize away stores to global variables that are used as temporaries?<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">eg I want use the Jit engine to generate code for the following function 'f':<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">struct State {<o:p></o:p></p>
<p class="MsoNormal">  int a;<o:p></o:p></p>
<p class="MsoNormal">  int tmp;<o:p></o:p></p>
<p class="MsoNormal">  int b;<o:p></o:p></p>
<p class="MsoNormal">};<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">void f0(State* s) {  s->tmp = s->a; }<o:p></o:p></p>
<p class="MsoNormal">void f1(State* s) { s->b = s->tmp; }<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">void f(State* s)<o:p></o:p></p>
<p class="MsoNormal">{<o:p></o:p></p>
<p class="MsoNormal">  f0(s);<o:p></o:p></p>
<p class="MsoNormal">  f1(s);<o:p></o:p></p>
<p class="MsoNormal">}<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">The Jit engine generates the following code:<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">define void @_Z1fP5State(%struct.State* %s) #1 {<o:p></o:p></p>
<p class="MsoNormal">  %1 = getelementptr inbounds %struct.State, %struct.State* %s, i64 0, i32 0<o:p></o:p></p>
<p class="MsoNormal">  %2 = load i32, i32* %1, align 4, !tbaa !1<o:p></o:p></p>
<p class="MsoNormal">  %3 = getelementptr inbounds %struct.State, %struct.State* %s, i64 0, i32 1<o:p></o:p></p>
<p class="MsoNormal">  store i32 %2, i32* %3, align 4, !tbaa !6<o:p></o:p></p>
<p class="MsoNormal">  %4 = getelementptr inbounds %struct.State, %struct.State* %s, i64 0, i32 2<o:p></o:p></p>
<p class="MsoNormal">  store i32 %2, i32* %4, align 4, !tbaa !7<o:p></o:p></p>
<p class="MsoNormal">  ret void<o:p></o:p></p>
<p class="MsoNormal">}<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">Which gives (on x86_64):<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">_Z1fP5State:<o:p></o:p></p>
<p class="MsoNormal">        movl              (%rdi), %eax<o:p></o:p></p>
<p class="MsoNormal">        movl              %eax, 4(%rdi)<o:p></o:p></p>
<p class="MsoNormal">        movl              %eax, 8(%rdi)<o:p></o:p></p>
<p class="MsoNormal">        retq<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">The 'tmp' state variable is only needed during execution of the function 'f'.<o:p></o:p></p>
<p class="MsoNormal">After the function has finished to value can be discarded.<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">How can I tell the optimizer to optimize away to stores to the 'tmp' variable?<o:p></o:p></p>
<p class="MsoNormal">Can I use the @llvm.lifetime.end intrinsic to do this?<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">Eg If I change the function 'f' as follows:<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">extern "C" void llvm_lifetime_end(unsigned long long, void*);<o:p></o:p></p>
<p class="MsoNormal">void cleanup(State* s)<o:p></o:p></p>
<p class="MsoNormal">{<o:p></o:p></p>
<p class="MsoNormal">  // llvm_lifetime_end will be replaced with @llvm.lifetime.end<o:p></o:p></p>
<p class="MsoNormal">  llvm_lifetime_end(sizeof(s->tmp), (void*)&s->tmp);<o:p></o:p></p>
<p class="MsoNormal">}<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">void f(State* s)<o:p></o:p></p>
<p class="MsoNormal">{<o:p></o:p></p>
<p class="MsoNormal">  f0(s);<o:p></o:p></p>
<p class="MsoNormal">  f1(s);<o:p></o:p></p>
<p class="MsoNormal">  cleanup(s);<o:p></o:p></p>
<p class="MsoNormal">}<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">And then use a pass to replace the function llvm_lifetime_end with the intrinsic @llvm.lifetime.end.<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">I get the following code:<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">define void @_Z1fP5State(%struct.State* nocapture %s) #0 {<o:p></o:p></p>
<p class="MsoNormal">  %1 = getelementptr inbounds %struct.State, %struct.State* %s, i64 0, i32 0<o:p></o:p></p>
<p class="MsoNormal">  %2 = load i32, i32* %1, align 4, !tbaa !1<o:p></o:p></p>
<p class="MsoNormal">  %3 = getelementptr inbounds %struct.State, %struct.State* %s, i64 0, i32 1<o:p></o:p></p>
<p class="MsoNormal">  %4 = getelementptr inbounds %struct.State, %struct.State* %s, i64 0, i32 2<o:p></o:p></p>
<p class="MsoNormal">  store i32 %2, i32* %4, align 4, !tbaa !7<o:p></o:p></p>
<p class="MsoNormal">  %5 = bitcast i32* %3 to i8*<o:p></o:p></p>
<p class="MsoNormal">  tail call void @llvm.lifetime.end(i64 4, i8* %5)<o:p></o:p></p>
<p class="MsoNormal">  ret void<o:p></o:p></p>
<p class="MsoNormal">}<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">_Z1fP5State:<o:p></o:p></p>
<p class="MsoNormal">                movl      (%rdi), %eax<o:p></o:p></p>
<p class="MsoNormal">                movl      %eax, 8(%rdi)<o:p></o:p></p>
<p class="MsoNormal">                retq<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">Is this a supported usecase of the @llvm.lifetime.end intrinsic? ie is it allowed to use the intrinsic on a global variable instead of a local variable?<o:p></o:p></p>
<p class="MsoNormal">Or is there a better way to get the same result?<o:p></o:p></p>
<p class="MsoNormal">Is it ok to only have an @llvm.lifetime.end intrinsic, without a matching @llvm.lifetime.start intrinisic?<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">If not is there another way to tell the optimizer to optimize away the stores to the 'tmp' state variable?<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">Thanks,<o:p></o:p></p>
<p class="MsoNormal">Tom<o:p></o:p></p>
</div>
</body>
</html>