Index: include/llvm/Transforms/Utils/MemorySSA.h =================================================================== --- include/llvm/Transforms/Utils/MemorySSA.h +++ include/llvm/Transforms/Utils/MemorySSA.h @@ -235,7 +235,7 @@ void *operator new(size_t s) { return User::operator new(s, 1); } MemoryUse(LLVMContext &C, MemoryAccess *DMA, Instruction *MI, BasicBlock *BB) - : MemoryUseOrDef(C, DMA, MemoryUseVal, MI, BB) {} + : MemoryUseOrDef(C, DMA, MemoryUseVal, MI, BB), OptimizedID(0) {} static inline bool classof(const MemoryUse *) { return true; } static inline bool classof(const Value *MA) { @@ -243,6 +243,14 @@ } void print(raw_ostream &OS) const override; + void setDefiningAccess(MemoryAccess *DMA, bool Optimized = false) { + if (Optimized) + OptimizedID = DMA->getID(); + MemoryUseOrDef::setDefiningAccess(DMA); + } + bool isOptimized() const { + return getDefiningAccess() && OptimizedID == getDefiningAccess()->getID(); + } protected: friend class MemorySSA; @@ -250,6 +258,9 @@ unsigned getID() const override { llvm_unreachable("MemoryUses do not have IDs"); } + +private: + unsigned int OptimizedID; }; template <> Index: lib/Transforms/Utils/MemorySSA.cpp =================================================================== --- lib/Transforms/Utils/MemorySSA.cpp +++ lib/Transforms/Utils/MemorySSA.cpp @@ -1332,7 +1332,7 @@ } if (isUseTriviallyOptimizableToLiveOnEntry(*AA, MU->getMemoryInst())) { - MU->setDefiningAccess(MSSA->getLiveOnEntryDef()); + MU->setDefiningAccess(MSSA->getLiveOnEntryDef(), true); continue; } @@ -1428,13 +1428,13 @@ // At the end of this loop, UpperBound is either a clobber, or lower bound // PHI walking may cause it to be < LowerBound, and in fact, < LastKill. if (FoundClobberResult || UpperBound < LocInfo.LastKill) { - MU->setDefiningAccess(VersionStack[UpperBound]); + MU->setDefiningAccess(VersionStack[UpperBound], true); // We were last killed now by where we got to LocInfo.LastKill = UpperBound; } else { // Otherwise, we checked all the new ones, and now we know we can get to // LastKill. - MU->setDefiningAccess(VersionStack[LocInfo.LastKill]); + MU->setDefiningAccess(VersionStack[LocInfo.LastKill], true); } LocInfo.LowerBound = VersionStack.size() - 1; LocInfo.LowerBoundBlock = BB; @@ -2188,6 +2188,13 @@ if (!StartingAccess) return MA; + // If this is an already optimized use or def, return the optimized result. + // Note: Currently, we do not store the optimized def result because we'd need + // a separate field, since we can't use it as the defining access. + if (MemoryUse *MU = dyn_cast(StartingAccess)) + if (MU->isOptimized()) + return MU->getDefiningAccess(); + const Instruction *I = StartingAccess->getMemoryInst(); UpwardsMemoryQuery Q(I, StartingAccess); // We can't sanely do anything with a fences, they conservatively @@ -2202,6 +2209,8 @@ if (isUseTriviallyOptimizableToLiveOnEntry(*MSSA->AA, I)) { MemoryAccess *LiveOnEntry = MSSA->getLiveOnEntryDef(); Cache.insert(StartingAccess, LiveOnEntry, Q.StartingLoc, Q.IsCall); + if (MemoryUse *MU = dyn_cast(StartingAccess)) + MU->setDefiningAccess(LiveOnEntry, true); return LiveOnEntry; } @@ -2218,6 +2227,8 @@ DEBUG(dbgs() << *DefiningAccess << "\n"); DEBUG(dbgs() << "Final Memory SSA clobber for " << *I << " is "); DEBUG(dbgs() << *Result << "\n"); + if (MemoryUse *MU = dyn_cast(StartingAccess)) + MU->setDefiningAccess(Result, true); return Result; } Index: unittests/Transforms/Utils/MemorySSA.cpp =================================================================== --- unittests/Transforms/Utils/MemorySSA.cpp +++ unittests/Transforms/Utils/MemorySSA.cpp @@ -450,24 +450,32 @@ EXPECT_EQ(LoadClobber, MSSA.getLiveOnEntryDef()); } -// At one point, we were building MSSA with 0 AA passes. This ensures that we -// actually use BasicAA. -TEST_F(MemorySSATest, AAIsPresentAtBuildTime) { +// Test loads get reoptimized properly by the walker. +TEST_F(MemorySSATest, WalkerReopt) { F = Function::Create(FunctionType::get(B.getVoidTy(), {}, false), GlobalValue::ExternalLinkage, "F", &M); B.SetInsertPoint(BasicBlock::Create(C, "", F)); - Type *Int8 = Type::getInt8Ty(C); - Constant *One = ConstantInt::get(Int8, 1); - Value *AllocaA = B.CreateAlloca(Int8); - Instruction *StoreA = B.CreateStore(One, AllocaA); - - Value *AllocaB = B.CreateAlloca(Int8); - B.CreateStore(One, AllocaB); - Instruction *LoadA = B.CreateLoad(AllocaA); + Value *AllocaA = B.CreateAlloca(Int8, ConstantInt::get(Int8, 1), "A"); + Instruction *SIA = B.CreateStore(ConstantInt::get(Int8, 0), AllocaA); + Value *AllocaB = B.CreateAlloca(Int8, ConstantInt::get(Int8, 1), "B"); + Instruction *SIB = B.CreateStore(ConstantInt::get(Int8, 0), AllocaB); + Instruction *LIA = B.CreateLoad(AllocaA); setupAnalyses(); MemorySSA &MSSA = *Analyses->MSSA; - auto *MU = cast(MSSA.getMemoryAccess(LoadA)); - EXPECT_EQ(MU->getDefiningAccess(), MSSA.getMemoryAccess(StoreA)); + MemorySSAWalker *Walker = Analyses->Walker; + + MemoryAccess *LoadClobber = Walker->getClobberingMemoryAccess(LIA); + MemoryUse *LoadAccess = cast(MSSA.getMemoryAccess(LIA)); + EXPECT_EQ(LoadClobber, MSSA.getMemoryAccess(SIA)); + EXPECT_TRUE(MSSA.isLiveOnEntryDef(Walker->getClobberingMemoryAccess(SIA))); + MSSA.removeMemoryAccess(LoadAccess); + + // Create the load memory access pointing to an unoptimized place. + MemoryUse *NewLoadAccess = cast(MSSA.createMemoryAccessInBB( + LIA, MSSA.getMemoryAccess(SIB), LIA->getParent(), MemorySSA::End)); + // This should it cause it to be optimized + EXPECT_EQ(Walker->getClobberingMemoryAccess(NewLoadAccess), LoadClobber); + EXPECT_EQ(NewLoadAccess->getDefiningAccess(), LoadClobber); }