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

Sanjoy Das sanjoy at playingwithpointers.com
Mon Dec 1 21:45:40 PST 2014


> The "invariant" metadata property should be treated as alias
> analysis information. So storing to an location and invariant-loading
> from the same location would not be undefined behavior. The subsequent
> load could legally return either the stored value or the prior value
> (or poison if you like). As long as the value is never used, it
> doesn't affect semantics.

Okay; that makes things a lot clearer to me!  So (taking some liberty
with phrasing):

'If the value stored at a location changes after it is dereferenceable
to a thread, !invariant loads from that location by the said thread
return undef'.

It thus is okay to hoist an invariant load to anywhere where the
pointer it loads from is dereferenceable -- if the value it loads
would have been different in the place it was hoisted from, then its
result is undef; and hence can legally be whatever the result of the
load is in the location where it is hoisted to.

I'm not sure how to deal with referenceable pointers becoming
unreferenceable though -- starting with this

  t = calloc()
  m = load(t) !invariant
  free(t)
  use(m)

we clearly want to avoid

  t = calloc()
  free(t)
  m = load(t) !invariant
  use(m)

but not

  t = calloc()
  m = load(t) !invariant
  not_free(t)
  use(m)

 ==>

  t = calloc()
  not_free(t)
  m = load(t) !invariant
  use(m)


The !invariant load in the initial program is not UB even though m is
undef (assuming we are modelling free as a "write" changing the value
of t), so we cannot end up with a program that has UB.  We could say
that if there an invariant load from P, then it cannot go from
dereferenceable to not dereferenceable; but then we're back to square
one w.r.t. defining "cannot go" -- if it is UB, then

  // well defined
  p = malloc()
  free(p)

 ==>

  p = malloc()
  if (false) { load !invariant p; }
  free(p)

 ==>

  p = malloc()
  load !invariant p;
  if (false) { }
  free(p)

 ==>
  UB


Alternatively, we could say 'If the value stored at a location changes
*while* is dereferenceable to a thread, !invariant loads from that
location by the said thread return undef'.  This would mean we won't
be able to move invariant loads from P across calls that could write
to P; and I'm not sure I'm happy with that.

-- Sanjoy



More information about the llvm-commits mailing list