<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">Hi,<div class=""><br class=""></div><div class=""><div><blockquote type="cite" class=""><div class="">On Dec 3, 2015, at 10:33 PM, Vaivaswatha Nagaraj via llvm-dev <<a href="mailto:llvm-dev@lists.llvm.org" class="">llvm-dev@lists.llvm.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class=""><div class=""><div class="">Hi,<br class=""><br class=""></div>This email is in continuation to the mail thread <a href="http://lists.llvm.org/pipermail/llvm-dev/2015-December/092996.html" class="">http://lists.llvm.org/pipermail/llvm-dev/2015-December/092996.html</a>, to propose a new function attribute that can convey that a function maintains state, but this state is inaccessible to the rest of the program under compilation.<br class=""><br class=""></div>Such a flag could be added to most libc/system calls such as printf/malloc/free. (libc and system calls do access/modify internal variables such as errno).<br class=""><div class=""><div class=""><br class=""></div><div class="">Example attributes (in addition to what are already set):<br class=""></div><div class="">malloc/free: HasInaccessibleState, ReadNone<br class=""></div><div class="">printf: HasInaccessibleState, ArgMemOnly<br class=""></div><div class="">realloc: HasInaccessibleState, ReadOnly (not sure).<br class=""><br class=""></div><div class="">The intention behind introducing this attribute is to relax the conditions in GlobalsAA as below:<br class=""></div><div class="">(this code is in GlobalsAAResult::AnalyzeCallGraph)<br class=""></div><div class=""><pre class="">       if (F->isDeclaration()) {
         // Try to get mod/ref behaviour from function attributes.
-        if (F->doesNotAccessMemory()) {
+        if (F->doesNotAccessMemory() || F->onlyAccessesArgMemory()) {
           // Can't do better than that!
         } else if (F->onlyReadsMemory()) {
           FunctionEffect |= Ref;
           if (!F->isIntrinsic())
             // This function might call back into the module and read a global -
             // consider every global as possibly being read by this function.
             FR.MayReadAnyGlobal = true;
         } else {
           FunctionEffect |= ModRef;
           // Can't say anything useful unless it's an intrinsic - they don't
           // read or write global variables of the kind considered here.
           KnowNothing = !F->isIntrinsic();
         }
         continue;
       }</pre>This relaxation allows functions that (transitively) call library functions (such as printf/malloc) to still maintain and propagate GlobalsAA info. In general, this adds more precision to the description of these functions. <br class=""><br class=""></div><div class="">Concerns regarding impact on other optimizations (I'm repeating a few examples that Hal mentioned earlier).<br class=""><br class="">1. <br class="">><span class="im">A readnone 
function is one whose output is a function only of its inputs, and if 
you have this:<br class="">
><br class="">
>  int *x = malloc(4);<br class="">
>  *x = 2;<br class="">
>  int *y = malloc(4);<br class="">
>  *y = 4;<br class="">
</span><span class="im">> you certainly don't want EarlyCSE to replace the 
second call to malloc with the result of the first (which it will 
happily do if you mark malloc as readnone).<br class=""><br class=""></span></div><div class=""><span style="" class=""><span class="im"><span style="" class="">For malloc, even though ReadNone is set now (as proposed above), EarlyCSE should be taught to respect the HasInaccessibleState and not combine functions that maintain internal states.</span> <span style="" class="">Similarly other optimizations (such as DCE) must be taught to respect the flag.</span><br class=""><br class="">2.<br class=""></span></span><span style="" class=""><span class="im">>void foo(char * restrict s1, char * restrict s2) {<br class="">
>  printf(s1);<br class="">
>  printf(s2);<br class="">>}<br class="">
<br class="">>If printf is argmemonly, then we could interchange the two printf calls.<br class=""><br class=""></span></span></div><div class=""><span class="im"><span style="" class="">In this example too, printf maintains an internal state, preventing the calls from being internchanged</span>. <span style="" class="">Also, it is now correct to add ArgMemOnly to printf as it does not access any other program memory.</span> <br class=""><br class="">3.<br class=""></span>>For malloc this is still a problem, in the following sense, if we have:<br class="">
><br class="">>  p1 = malloc(really_big);<br class="">>  ...<br class="">>  free(p1);<br class="">
><br class="">> p2 = malloc(really_big);<br class="">>  ...<br class="">> free(p2);<br class="">
>allowing a transformation into:<br class="">
>   p1 = malloc(really_big);<br class="">>   p2 = malloc(really_big);<br class="">
>    ...<br class="">
>   free(p1); free(p2);<br class="">
>could be problematic.</div><div class=""><span class="im"><br class=""></span></div><div class=""><span class="im"><span style="" class="">Both free and malloc would be marked with having an internal state. This should prevent this kind of an optimization</span>. <span style="" class="">Note that having the ReadNone attribute should not cause problems anymore.</span><br class=""></span></div></div></div></div></blockquote><div><br class=""></div><div><div class="">Something is not clear to me: is this "internal state” supposed to be private to the function?</div><div class="">How does it deal with malloc/free which can be seen as sharing a state? Especially it is not clear to me how this flag would prevent the last “optimization” you’re illustrating.</div><div class=""><br class=""></div><div class="">— </div><div class="">Mehdi</div><div class=""><br class=""></div><div class=""><br class=""><div><blockquote type="cite" class=""></blockquote></div></div></div></div><br class=""></div></body></html>