[PATCH] Clarify wording in the LangRef around !invariant.load

Sanjoy Das sanjoy at playingwithpointers.com
Mon Dec 1 21:47:37 PST 2014


> I think this is completely legal for the current optimizer.  Here's my
> argument:
> - !invariant.load describes the constant-ness of the *pointer value*.  Once
> the pointer *value* is known dereferenceable, it is always invariant.
> - The store implies dereferenceability.
> - The store must (by assumption) be not changing the value of the location.
> (Otherwise, the invariant.load marker lied originally.)
> - Given the store can be completely omitted, combining the two loads becomes
> 'obviously' okay.


If I understand this correctly, the above argument allows cases like
this:

  int **p = calloc(sizeof(int*))
  store calloc(sizeof(int)) to p
  int *l = load(p)
  print *l // prints zero

 ==>

  int **p = calloc(sizeof(int*))
  store calloc(sizeof(int)) to p
  if (false) {
    int *s = load (p) !invariant
  }
  int *l = load(p)
  print *l // prints zero

 ==>

  int **p = calloc(sizeof(int*))
  int *s = load (p) !invariant
  store calloc(sizeof(int)) to p
  if (false) {
  }
  int *l = load(p)
  print *l // prints zero

 ==>

  int **p = calloc(sizeof(int*))
  int *s = load (p) !invariant
  store calloc(sizeof(int)) to p
  if (false) {
  }
  int *l = load(s)
  print *l

 ==>

  int **p = calloc(sizeof(int*))
  int *s = load (p) !invariant
  store calloc(sizeof(int)) to p
  if (false) {
  }
  int *l = load(s) // UB, since it now dereferences null
  print *l


We started from a well-defined program, and ended in UB.

-- Sanjoy



More information about the llvm-commits mailing list