[PATCH] D74935: [LangRef][AliasAnalysis] Clarify `noalias` affects only modified objects

Jeroen Dobbelaere via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Thu Mar 5 14:49:32 PST 2020


jeroen.dobbelaere added a comment.

In D74935#1907939 <https://reviews.llvm.org/D74935#1907939>, @jdoerfert wrote:

> In D74935#1907100 <https://reviews.llvm.org/D74935#1907100>, @jeroen.dobbelaere wrote:
>
> > Just to give an example:
> >
> >   int foo(int* restrict *pA, int* restrict *pB) {
> >     int tmp=**pB;
> >     **pA=42;
> >     return tmp - **pB; // **pA and **pB can refer to the same objects
> >   }
> >    
> >
> > [...]
>
>
> `*pA` and `*pB` are both restrict qualified pointers, are they not?
>  If so, why can they point to the same location?


For the original example, *pA and *pB might be the same restrict pointer:

  int* restrict pC = ....;
  foo(&pC, &pC);

> I mean, w/o the side channel stuff the two `int *` values may alias
>  even if you have `noalias` on the arguments (https://godbolt.org/z/J9v_gK).

And that is correct, as *pA might be equal to *pB for that case (even if pA and pB are not equal).

Restrictness adds additional information (ignoring for a moment the 'read only' case (see note *4)):

   // case A
   int * restrict prC;
   int * restrict prD;
   // pC and pD are separate (*1) restrict pointers  => they point to their own separate sets of objects set(prC), set(prD), aka prC != prD (*2)
  
   // case B
   int * restrict * prpE; 
   int * restrict * prpF;
   // prpE and prpF are _not_ restrict pointers, so prpE could be equal to prpF (prpE == prpF) or not (prpE != prpF)
   // *prpE and *prpF are restrict pointers. When prpE == prpF, they represent the same restrict pointer.
   // *prpE could point to prC or prD or a different restrict pointer => set(*prpE) =union(set(prC), set(prD), ...)
   // also *prpF can point to union(set(prC), set(prD), ...)
  
   // case C
   int * restrict * restrict prprG;  
   int * restrict * restrict prprH;
   // prprG and prprH are separate (*3) restrict pointers => they point to their own separate sets of objects set(prprG) and set(prprH)
   // because of that: prprG != prprH
   // and *prprG and *prprH represent also separate (see previous line) restrict points
   // So *prprG and *prprH must point to their own separate sets of objects set(*prprG) and set(*prprH) 
  
   // The difference between between case B and case C is that in B, prpE could be equal to prpF (mayAlias), and because of that, *prpE could be equal to *prpF.
   // By proving that prprG != prprH, it automatically follows that *prprG != *prprH (except for (*4))
  
  // Notes:
  // (*1)  &prC != &prD 
  // (*2) it actually is: for all i,j for which prC[i] and prD[j] are 'valid',  &prC[i] != &prD[j]
  // (*3)  &prprG != &prprH
  // (*4) The restrict definition contains a relaxation when restrict pointers are only used for reading memory: 
  //   In that case, separate restrict pointers are allowed to point to the same set of objects... except for:
  //  But: it also states that (6.7.3.1 paragraph 4 : '.. Every  access  that modifies X shall be considered also to modify P,for the purposes of this subclause. .. '
  //  Which means that if your write to **prprG, it is _as if_ you also write to *prprG and because of that, both prprG and *prprG must point to their own set of objects set(prprG) and set(*prprG)
  //  and those sets must also be different from set(prprH) and set(*prprH)

Now, in the original example, we have 'case B'.  pA could be equal to pB (mayAlias), and because of that, *pA could be equal to *pB.

  int foo(int* restrict *pA, int* restrict *pB);

When we can proof that pA != pB (noalias), then *pA and *pB represent different restrict pointers and *pA != *pB. (different restrict pointers point to their own set of objects)

So, adding the 'noalias' attribute to %pA and %pB will change the behavior of foo().

hmm... this explanation is maybe getting too long ?
The short conclusion should be:

- adding 'noalias' to a pointer argument, because it is only used to read memory, might lead to 'wrong code'
- two 'noalias' pointer arguments should not overlap

or relaxed:

- two 'noalias' pointer arguments can only overlap if they (at any level of indirection) are never used to write to memory.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D74935/new/

https://reviews.llvm.org/D74935





More information about the cfe-commits mailing list