[llvm-dev] RFC: New function attribute HasInaccessibleState

Vaivaswatha Nagaraj via llvm-dev llvm-dev at lists.llvm.org
Thu Dec 3 22:33:28 PST 2015


This email is in continuation to the mail thread
http://lists.llvm.org/pipermail/llvm-dev/2015-December/092996.html, 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

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).

Example attributes (in addition to what are already set):
malloc/free: HasInaccessibleState, ReadNone
printf: HasInaccessibleState, ArgMemOnly
realloc: HasInaccessibleState, ReadOnly (not sure).

The intention behind introducing this attribute is to relax the conditions
in GlobalsAA as below:
(this code is in GlobalsAAResult::AnalyzeCallGraph)

       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();

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.

Concerns regarding impact on other optimizations (I'm repeating a few
examples that Hal mentioned earlier).

>A readnone function is one whose output is a function only of its inputs,
and if you have this:
>  int *x = malloc(4);
>  *x = 2;
>  int *y = malloc(4);
>  *y = 4;
> 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).

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. Similarly other optimizations
(such as DCE) must be taught to respect the flag.

>void foo(char * restrict s1, char * restrict s2) {
>  printf(s1);
>  printf(s2);

>If printf is argmemonly, then we could interchange the two printf calls.

In this example too, printf maintains an internal state, preventing the
calls from being internchanged. Also, it is now correct to add ArgMemOnly
to printf as it does not access any other program memory.

>For malloc this is still a problem, in the following sense, if we have:
>  p1 = malloc(really_big);
>  ...
>  free(p1);
> p2 = malloc(really_big);
>  ...
> free(p2);
>allowing a transformation into:
>   p1 = malloc(really_big);
>   p2 = malloc(really_big);
>    ...
>   free(p1); free(p2);
>could be problematic.

Both free and malloc would be marked with having an internal state. This
should prevent this kind of an optimization. Note that having the ReadNone
attribute should not cause problems anymore.

  - Vaivaswatha
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20151204/02b42d0c/attachment-0001.html>

More information about the llvm-dev mailing list