[MemorySSA] Clobbers for `!invariant.load` instructions

We’ve got this function in MemorySSA.cpp

template <typename AliasAnalysisType>
static bool isUseTriviallyOptimizableToLiveOnEntry(AliasAnalysisType &AA,
                                                   const Instruction *I) {
  // If the memory can't be changed, then loads of the memory can't be
  // clobbered.
  if (auto *LI = dyn_cast<LoadInst>(I))
    return I->hasMetadata(LLVMContext::MD_invariant_load) ||
           AA.pointsToConstantMemory(MemoryLocation::get(LI));
  return false;
}

This does not seem right.

The LangRef says, essentially, when an invariant load is executed, the memory location cannot change anymore. But the function suggests (with code and the comment) a different interpretation, that the mere existence of the invariant load means the memory location holds the same value since the very beginning of the function.

As an example we get:

define i32 @f() {
  %p = alloca i32, align 4
; 1 = MemoryDef(liveOnEntry)
  store i32 211, ptr %p, align 4
; MemoryUse(liveOnEntry)
  %v = load i32, ptr %p, align 4, !invariant.load !0
  ret i32 %v
}

!0 = !{}

i.e. we miss the legit clobber.

Should this function return true iff AA.pointsToConstantMemory(MemoryLocation::get(LI)) is true?

This is what LangRef says:

If a load instruction tagged with the !invariant.load metadata is executed, the memory location referenced by the load has to contain the same value at all points in the program where the memory location is dereferenceable; otherwise, the behavior is undefined.

Note, there is no mention about “afterwards”. The mere fact that the !invariant.load is executed means that the contents of %p in your example must have been constant throughout. So, your example function has undefined behavior.

1 Like