<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 15 (filtered medium)">
<style><!--
/* Font Definitions */
@font-face
        {font-family:"Cambria Math";
        panose-1:2 4 5 3 5 4 6 3 2 4;}
@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;
        font-size:11.0pt;
        font-family:"Calibri",sans-serif;}
a:link, span.MsoHyperlink
        {mso-style-priority:99;
        color:#0563C1;
        text-decoration:underline;}
span.EmailStyle20
        {mso-style-type:personal-compose;
        font-family:"Calibri",sans-serif;
        color:windowtext;}
.MsoChpDefault
        {mso-style-type:export-only;
        font-size:10.0pt;}
@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="#0563C1" vlink="#954F72" style="word-wrap:break-word">
<div class="WordSection1">
<p class="MsoNormal">Stepping through this in the debugger, I see this code in BasicAliasAnalysis doing a check similar to the sort that I would have expected to see proving NoAlias for this case, but it’s not because (ISTM) it’s being pretty conservative:<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">    // If one pointer is the result of a call/invoke or load and the other is a<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">    // non-escaping local object within the same function, then we know the<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">    // object couldn't escape to a point where the call could return it.<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">    //<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">    // Note that if the pointers are in different functions, there are a<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">    // variety of complications. A call with a nocapture argument may still<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">    // temporary store the nocapture argument's value in a temporary memory<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">    // location if that memory location doesn't escape. Or it may pass a<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">    // nocapture value to other functions as long as they don't capture it.<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">    if (isEscapeSource(O1) &&<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">        isNonEscapingLocalObject(O2, &AAQI.IsCapturedCache))<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">      return NoAlias;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">    if (isEscapeSource(O2) &&<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">        isNonEscapingLocalObject(O1, &AAQI.IsCapturedCache))<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">      return NoAlias;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">  }</span><o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">and<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">/// Returns true if the pointer is one which would have been considered an<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">/// escape by isNonEscapingLocalObject.<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">static bool isEscapeSource(const Value *V) {<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">  if (isa<CallBase>(V))<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">    return true;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New""><o:p> </o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">  if (isa<Argument>(V))<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">    return true;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New""><o:p> </o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">  // The load case works because isNonEscapingLocalObject considers all<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">  // stores to be escapes (it passes true for the StoreCaptures argument<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">  // to PointerMayBeCaptured).<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">  if (isa<LoadInst>(V))<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">    return true;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New""><o:p> </o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">  return false;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">}</span><o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">Since we have to look through all the uses of O1/O2 (including certain transitive ones) to prove isNonEscapingLocalObject, an expensive-but-more-precise analysis could just check if O2/O1 is in that set, IIUC.  I get why BasicAliasAnalysis
 isn’t the right place to do that.  Is there some more expensive alias analysis that I could opt into and get that sort of check?<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">Alternatively, following the logic that we can assume isEscapeSource for loads because we treat stores as escapes, is there room to assume isEscapeSource for inttoptrs because we treat ptrtoints, and things that let you subtly intify pointers
 such as certain compares, as escapes?<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">-Joseph<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<div>
<div style="border:none;border-top:solid #E1E1E1 1.0pt;padding:3.0pt 0in 0in 0in">
<p class="MsoNormal"><b>From:</b> llvm-dev <llvm-dev-bounces@lists.llvm.org> <b>On Behalf Of
</b>Joseph Tremoulet via llvm-dev<br>
<b>Sent:</b> Wednesday, March 31, 2021 2:09 PM<br>
<b>To:</b> llvm-dev <llvm-dev@lists.llvm.org><br>
<b>Subject:</b> [EXTERNAL] [llvm-dev] inttoptr and noalias returns<o:p></o:p></p>
</div>
</div>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">Hi,<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">I’m a bit confused about the interaction between inttoptr and noalias, and would like to better understand our model.<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">I realize there’s a bunch of in-flight work around restrict modeling and that ptrtoint was on the agenda for last week’s AA call.  I’m interested in understanding both the current state and the thinking/plans for the future.  And I’m happy
 for pointers to anywhere this is already written down, I didn’t find it from skimming the AA call minutes or the mailing list archive, but I could easily have overlooked it, and haven’t really dug into the set of restrict patches (nor do I know where to get
 a list of those).<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">I also realize that with aliasing questions there can always be a gap between what the model says we can infer and how aggressive analyses and optimizations are about actually making use of those inferences.  Again I’m interested in both
 answers (and happy for either).<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">In the LangRef section on pointer aliasing rules [1], I see<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal" style="margin-left:.5in">An integer constant other than zero or a pointer value returned from a function not defined within LLVM may be associated with address ranges allocated through mechanisms other than those provided by LLVM. Such
 ranges shall not overlap with any ranges of addresses allocated by mechanisms provided by LLVM.<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">And I’m curious what “mechanisms provided by LLVM” for allocation means.  Alloca, presumably.  Global variables?  Certain intrinsics?  Any function with a noalias return value?<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">In the LangRef description of the noalias attribute [2], I see<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal" style="margin-left:.5in">This indicates that memory locations accessed via pointer values based on the argument or return value are not also accessed, during the execution of the function, via pointer values not based on the argument or
 return value …  On function return values, the noalias attribute indicates that the function acts like a system memory allocation function, returning a pointer to allocated storage disjoint from the storage for any other object accessible to the caller.<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">The phrase “the storage for any other object accessible to the caller” in the noalias description sounds like a broader category than the phrase “mechanisms provided by LLVM” from the pointer aliasing section, so I would expect that if
 the pointer returned from a call to a function with return attribute noalias does not escape, then loads/stores through it would not alias loads/stores through a pointer produced by inttoptr.  Am I interpreting that correctly?<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">I wrote some snippets [3] to see what the optimizer would do.  Each case has a store of value 86 via pointer %p that I’d expect dead store elimination to remove if we think it does not alias the subsequent load via pointer %q (because immediately
 after that is another store to %p).<o:p></o:p></p>
<p class="MsoNormal">In each case, %q is the result of a call to a function whose return value is annotated noalias.<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">When %p is a pointer parameter, I indeed see the optimizer removing the dead store:<o:p></o:p></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">define i8 @test1(i8* %p) {<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New""><o:p> </o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">    %q = call i8* @allocate()<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">    store i8 86, i8* %p ; <-- this gets removed<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">    %result = load i8, i8* %q<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">    store i8 0, i8* %p<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">    ret i8 %result<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">}<o:p></o:p></span></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">When %p is the result of inttoptr, I do not see the store being removed, and I’m wondering if this is because of a subtle aliasing rule or an intentional conservativism in the optimizer or just a blind spot in the analysis:<o:p></o:p></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">define i8 @test2(i64 %p_as_int) {<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">    %p = inttoptr i64 %p_as_int to i8*<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New""><o:p> </o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">    %q = call i8* @allocate()<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">    store i8 86, i8* %p ; <-- this does not get removed<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">    %result = load i8, i8* %q<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">    store i8 0, i8* %p<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">    ret i8 %result<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">}<o:p></o:p></span></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">When I outline the inttoptr into a separate function, I again see the optimizer remove the dead store, which again I’m wondering if the difference between this and the previous case is an intentional subtle point or what.<o:p></o:p></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">define i8* @launder(i64 %int) noinline {<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">  %ptr = inttoptr i64 %int to i8*<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">  ret i8* %ptr<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">}<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New""><o:p> </o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">define i8 @test3(i64 %p_as_int) {<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">    %p = call i8* @launder(i64 %p_as_int)<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New""><o:p> </o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">    %q = call i8* @allocate()<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">    store i8 86, i8* %p ; <-- this gets removed<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">    %result = load i8, i8* %q<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">    store i8 0, i8* %p<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">    ret i8 %result<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:.5in"><span style="font-family:"Courier New"">}</span><o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">Happy for any insights you can share.<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">-Joseph<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">1 - <a href="https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fllvm.org%2Fdocs%2FLangRef.html%23pointeraliasing&data=04%7C01%7Cjotrem%40microsoft.com%7Ce772dc1fd7ee4665003b08d8f47007eb%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637528109307055170%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&sdata=iQ4uHRskXvviDCAzX1otuyuii9FhnmkYO8z5YkHI0y0%3D&reserved=0">
https://llvm.org/docs/LangRef.html#pointeraliasing</a><o:p></o:p></p>
<p class="MsoNormal">2 - <a href="https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fllvm.org%2Fdocs%2FLangRef.html%23parameter-attributes&data=04%7C01%7Cjotrem%40microsoft.com%7Ce772dc1fd7ee4665003b08d8f47007eb%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637528109307055170%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&sdata=uDsHa3L12nNt7y5fK1GU36D%2BflL7RmQIW8X2gkhbM%2Fo%3D&reserved=0">
https://llvm.org/docs/LangRef.html#parameter-attributes</a><o:p></o:p></p>
<p class="MsoNormal">3 - <a href="https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgodbolt.org%2Fz%2Fx8e41G33Y&data=04%7C01%7Cjotrem%40microsoft.com%7Ce772dc1fd7ee4665003b08d8f47007eb%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637528109307065126%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&sdata=j8cZ0Stb%2F%2BRZMe%2FNotzuvJTz%2FjDUJBqLixbXp0WRBH0%3D&reserved=0">
https://godbolt.org/z/x8e41G33Y</a><o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
</body>
</html>