diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2019-01-19 10:01:25 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2019-01-19 10:01:25 +0000 |
commit | d8e91e46262bc44006913e6796843909f1ac7bcd (patch) | |
tree | 7d0c143d9b38190e0fa0180805389da22cd834c5 /lib/Analysis/MemorySSA.cpp | |
parent | b7eb8e35e481a74962664b63dfb09483b200209a (diff) |
Notes
Diffstat (limited to 'lib/Analysis/MemorySSA.cpp')
-rw-r--r-- | lib/Analysis/MemorySSA.cpp | 437 |
1 files changed, 312 insertions, 125 deletions
diff --git a/lib/Analysis/MemorySSA.cpp b/lib/Analysis/MemorySSA.cpp index f57d490ce96e..6a5567ed765b 100644 --- a/lib/Analysis/MemorySSA.cpp +++ b/lib/Analysis/MemorySSA.cpp @@ -30,7 +30,6 @@ #include "llvm/Config/llvm-config.h" #include "llvm/IR/AssemblyAnnotationWriter.h" #include "llvm/IR/BasicBlock.h" -#include "llvm/IR/CallSite.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/Function.h" #include "llvm/IR/Instruction.h" @@ -77,9 +76,15 @@ static cl::opt<unsigned> MaxCheckLimit( cl::desc("The maximum number of stores/phis MemorySSA" "will consider trying to walk past (default = 100)")); -static cl::opt<bool> - VerifyMemorySSA("verify-memoryssa", cl::init(false), cl::Hidden, - cl::desc("Verify MemorySSA in legacy printer pass.")); +// Always verify MemorySSA if expensive checking is enabled. +#ifdef EXPENSIVE_CHECKS +bool llvm::VerifyMemorySSA = true; +#else +bool llvm::VerifyMemorySSA = false; +#endif +static cl::opt<bool, true> + VerifyMemorySSAX("verify-memoryssa", cl::location(VerifyMemorySSA), + cl::Hidden, cl::desc("Enable verification of MemorySSA.")); namespace llvm { @@ -119,16 +124,15 @@ class MemoryLocOrCall { public: bool IsCall = false; - MemoryLocOrCall() = default; MemoryLocOrCall(MemoryUseOrDef *MUD) : MemoryLocOrCall(MUD->getMemoryInst()) {} MemoryLocOrCall(const MemoryUseOrDef *MUD) : MemoryLocOrCall(MUD->getMemoryInst()) {} MemoryLocOrCall(Instruction *Inst) { - if (ImmutableCallSite(Inst)) { + if (auto *C = dyn_cast<CallBase>(Inst)) { IsCall = true; - CS = ImmutableCallSite(Inst); + Call = C; } else { IsCall = false; // There is no such thing as a memorylocation for a fence inst, and it is @@ -140,9 +144,9 @@ public: explicit MemoryLocOrCall(const MemoryLocation &Loc) : Loc(Loc) {} - ImmutableCallSite getCS() const { + const CallBase *getCall() const { assert(IsCall); - return CS; + return Call; } MemoryLocation getLoc() const { @@ -157,16 +161,17 @@ public: if (!IsCall) return Loc == Other.Loc; - if (CS.getCalledValue() != Other.CS.getCalledValue()) + if (Call->getCalledValue() != Other.Call->getCalledValue()) return false; - return CS.arg_size() == Other.CS.arg_size() && - std::equal(CS.arg_begin(), CS.arg_end(), Other.CS.arg_begin()); + return Call->arg_size() == Other.Call->arg_size() && + std::equal(Call->arg_begin(), Call->arg_end(), + Other.Call->arg_begin()); } private: union { - ImmutableCallSite CS; + const CallBase *Call; MemoryLocation Loc; }; }; @@ -192,9 +197,9 @@ template <> struct DenseMapInfo<MemoryLocOrCall> { hash_code hash = hash_combine(MLOC.IsCall, DenseMapInfo<const Value *>::getHashValue( - MLOC.getCS().getCalledValue())); + MLOC.getCall()->getCalledValue())); - for (const Value *Arg : MLOC.getCS().args()) + for (const Value *Arg : MLOC.getCall()->args()) hash = hash_combine(hash, DenseMapInfo<const Value *>::getHashValue(Arg)); return hash; } @@ -247,24 +252,29 @@ struct ClobberAlias { // Return a pair of {IsClobber (bool), AR (AliasResult)}. It relies on AR being // ignored if IsClobber = false. -static ClobberAlias instructionClobbersQuery(MemoryDef *MD, +static ClobberAlias instructionClobbersQuery(const MemoryDef *MD, const MemoryLocation &UseLoc, const Instruction *UseInst, AliasAnalysis &AA) { Instruction *DefInst = MD->getMemoryInst(); assert(DefInst && "Defining instruction not actually an instruction"); - ImmutableCallSite UseCS(UseInst); + const auto *UseCall = dyn_cast<CallBase>(UseInst); Optional<AliasResult> AR; if (const IntrinsicInst *II = dyn_cast<IntrinsicInst>(DefInst)) { // These intrinsics will show up as affecting memory, but they are just - // markers. + // markers, mostly. + // + // FIXME: We probably don't actually want MemorySSA to model these at all + // (including creating MemoryAccesses for them): we just end up inventing + // clobbers where they don't really exist at all. Please see D43269 for + // context. switch (II->getIntrinsicID()) { case Intrinsic::lifetime_start: - if (UseCS) + if (UseCall) return {false, NoAlias}; AR = AA.alias(MemoryLocation(II->getArgOperand(1)), UseLoc); - return {AR == MustAlias, AR}; + return {AR != NoAlias, AR}; case Intrinsic::lifetime_end: case Intrinsic::invariant_start: case Intrinsic::invariant_end: @@ -275,8 +285,8 @@ static ClobberAlias instructionClobbersQuery(MemoryDef *MD, } } - if (UseCS) { - ModRefInfo I = AA.getModRefInfo(DefInst, UseCS); + if (UseCall) { + ModRefInfo I = AA.getModRefInfo(DefInst, UseCall); AR = isMustSet(I) ? MustAlias : MayAlias; return {isModOrRefSet(I), AR}; } @@ -322,11 +332,12 @@ struct UpwardsMemoryQuery { // The MemoryAccess we actually got called with, used to test local domination const MemoryAccess *OriginalAccess = nullptr; Optional<AliasResult> AR = MayAlias; + bool SkipSelfAccess = false; UpwardsMemoryQuery() = default; UpwardsMemoryQuery(const Instruction *Inst, const MemoryAccess *Access) - : IsCall(ImmutableCallSite(Inst)), Inst(Inst), OriginalAccess(Access) { + : IsCall(isa<CallBase>(Inst)), Inst(Inst), OriginalAccess(Access) { if (!IsCall) StartingLoc = MemoryLocation::get(Inst); } @@ -366,13 +377,15 @@ static bool isUseTriviallyOptimizableToLiveOnEntry(AliasAnalysis &AA, /// \param Start The MemoryAccess that we want to walk from. /// \param ClobberAt A clobber for Start. /// \param StartLoc The MemoryLocation for Start. -/// \param MSSA The MemorySSA isntance that Start and ClobberAt belong to. +/// \param MSSA The MemorySSA instance that Start and ClobberAt belong to. /// \param Query The UpwardsMemoryQuery we used for our search. /// \param AA The AliasAnalysis we used for our search. -static void LLVM_ATTRIBUTE_UNUSED -checkClobberSanity(MemoryAccess *Start, MemoryAccess *ClobberAt, +/// \param AllowImpreciseClobber Always false, unless we do relaxed verify. +static void +checkClobberSanity(const MemoryAccess *Start, MemoryAccess *ClobberAt, const MemoryLocation &StartLoc, const MemorySSA &MSSA, - const UpwardsMemoryQuery &Query, AliasAnalysis &AA) { + const UpwardsMemoryQuery &Query, AliasAnalysis &AA, + bool AllowImpreciseClobber = false) { assert(MSSA.dominates(ClobberAt, Start) && "Clobber doesn't dominate start?"); if (MSSA.isLiveOnEntryDef(Start)) { @@ -382,21 +395,21 @@ checkClobberSanity(MemoryAccess *Start, MemoryAccess *ClobberAt, } bool FoundClobber = false; - DenseSet<MemoryAccessPair> VisitedPhis; - SmallVector<MemoryAccessPair, 8> Worklist; + DenseSet<ConstMemoryAccessPair> VisitedPhis; + SmallVector<ConstMemoryAccessPair, 8> Worklist; Worklist.emplace_back(Start, StartLoc); // Walk all paths from Start to ClobberAt, while looking for clobbers. If one // is found, complain. while (!Worklist.empty()) { - MemoryAccessPair MAP = Worklist.pop_back_val(); + auto MAP = Worklist.pop_back_val(); // All we care about is that nothing from Start to ClobberAt clobbers Start. // We learn nothing from revisiting nodes. if (!VisitedPhis.insert(MAP).second) continue; - for (MemoryAccess *MA : def_chain(MAP.first)) { + for (const auto *MA : def_chain(MAP.first)) { if (MA == ClobberAt) { - if (auto *MD = dyn_cast<MemoryDef>(MA)) { + if (const auto *MD = dyn_cast<MemoryDef>(MA)) { // instructionClobbersQuery isn't essentially free, so don't use `|=`, // since it won't let us short-circuit. // @@ -418,19 +431,39 @@ checkClobberSanity(MemoryAccess *Start, MemoryAccess *ClobberAt, // We should never hit liveOnEntry, unless it's the clobber. assert(!MSSA.isLiveOnEntryDef(MA) && "Hit liveOnEntry before clobber?"); - if (auto *MD = dyn_cast<MemoryDef>(MA)) { - (void)MD; + if (const auto *MD = dyn_cast<MemoryDef>(MA)) { + // If Start is a Def, skip self. + if (MD == Start) + continue; + assert(!instructionClobbersQuery(MD, MAP.second, Query.Inst, AA) .IsClobber && "Found clobber before reaching ClobberAt!"); continue; } + if (const auto *MU = dyn_cast<MemoryUse>(MA)) { + (void)MU; + assert (MU == Start && + "Can only find use in def chain if Start is a use"); + continue; + } + assert(isa<MemoryPhi>(MA)); - Worklist.append(upward_defs_begin({MA, MAP.second}), upward_defs_end()); + Worklist.append( + upward_defs_begin({const_cast<MemoryAccess *>(MA), MAP.second}), + upward_defs_end()); } } + // If the verify is done following an optimization, it's possible that + // ClobberAt was a conservative clobbering, that we can now infer is not a + // true clobbering access. Don't fail the verify if that's the case. + // We do have accesses that claim they're optimized, but could be optimized + // further. Updating all these can be expensive, so allow it for now (FIXME). + if (AllowImpreciseClobber) + return; + // If ClobberAt is a MemoryPhi, we can assume something above it acted as a // clobber. Otherwise, `ClobberAt` should've acted as a clobber at some point. assert((isa<MemoryPhi>(ClobberAt) || FoundClobber) && @@ -503,13 +536,13 @@ class ClobberWalker { /// /// This does not test for whether StopAt is a clobber UpwardsWalkResult - walkToPhiOrClobber(DefPath &Desc, - const MemoryAccess *StopAt = nullptr) const { + walkToPhiOrClobber(DefPath &Desc, const MemoryAccess *StopAt = nullptr, + const MemoryAccess *SkipStopAt = nullptr) const { assert(!isa<MemoryUse>(Desc.Last) && "Uses don't exist in my world"); for (MemoryAccess *Current : def_chain(Desc.Last)) { Desc.Last = Current; - if (Current == StopAt) + if (Current == StopAt || Current == SkipStopAt) return {Current, false, MayAlias}; if (auto *MD = dyn_cast<MemoryDef>(Current)) { @@ -587,9 +620,16 @@ class ClobberWalker { if (!VisitedPhis.insert({Node.Last, Node.Loc}).second) continue; - UpwardsWalkResult Res = walkToPhiOrClobber(Node, /*StopAt=*/StopWhere); + const MemoryAccess *SkipStopWhere = nullptr; + if (Query->SkipSelfAccess && Node.Loc == Query->StartingLoc) { + assert(isa<MemoryDef>(Query->OriginalAccess)); + SkipStopWhere = Query->OriginalAccess; + } + + UpwardsWalkResult Res = walkToPhiOrClobber(Node, /*StopAt=*/StopWhere, + /*SkipStopAt=*/SkipStopWhere); if (Res.IsKnownClobber) { - assert(Res.Result != StopWhere); + assert(Res.Result != StopWhere && Res.Result != SkipStopWhere); // If this wasn't a cache hit, we hit a clobber when walking. That's a // failure. TerminatedPath Term{Res.Result, PathIndex}; @@ -601,10 +641,13 @@ class ClobberWalker { continue; } - if (Res.Result == StopWhere) { + if (Res.Result == StopWhere || Res.Result == SkipStopWhere) { // We've hit our target. Save this path off for if we want to continue - // walking. - NewPaused.push_back(PathIndex); + // walking. If we are in the mode of skipping the OriginalAccess, and + // we've reached back to the OriginalAccess, do not save path, we've + // just looped back to self. + if (Res.Result != SkipStopWhere) + NewPaused.push_back(PathIndex); continue; } @@ -875,7 +918,8 @@ public: } #ifdef EXPENSIVE_CHECKS - checkClobberSanity(Current, Result, Q.StartingLoc, MSSA, Q, AA); + if (!Q.SkipSelfAccess) + checkClobberSanity(Current, Result, Q.StartingLoc, MSSA, Q, AA); #endif return Result; } @@ -903,28 +947,76 @@ struct RenamePassData { namespace llvm { +class MemorySSA::ClobberWalkerBase { + ClobberWalker Walker; + MemorySSA *MSSA; + +public: + ClobberWalkerBase(MemorySSA *M, AliasAnalysis *A, DominatorTree *D) + : Walker(*M, *A, *D), MSSA(M) {} + + MemoryAccess *getClobberingMemoryAccessBase(MemoryAccess *, + const MemoryLocation &); + // Second argument (bool), defines whether the clobber search should skip the + // original queried access. If true, there will be a follow-up query searching + // for a clobber access past "self". Note that the Optimized access is not + // updated if a new clobber is found by this SkipSelf search. If this + // additional query becomes heavily used we may decide to cache the result. + // Walker instantiations will decide how to set the SkipSelf bool. + MemoryAccess *getClobberingMemoryAccessBase(MemoryAccess *, bool); + void verify(const MemorySSA *MSSA) { Walker.verify(MSSA); } +}; + /// A MemorySSAWalker that does AA walks to disambiguate accesses. It no /// longer does caching on its own, but the name has been retained for the /// moment. class MemorySSA::CachingWalker final : public MemorySSAWalker { - ClobberWalker Walker; - - MemoryAccess *getClobberingMemoryAccess(MemoryAccess *, UpwardsMemoryQuery &); + ClobberWalkerBase *Walker; public: - CachingWalker(MemorySSA *, AliasAnalysis *, DominatorTree *); + CachingWalker(MemorySSA *M, ClobberWalkerBase *W) + : MemorySSAWalker(M), Walker(W) {} ~CachingWalker() override = default; using MemorySSAWalker::getClobberingMemoryAccess; - MemoryAccess *getClobberingMemoryAccess(MemoryAccess *) override; - MemoryAccess *getClobberingMemoryAccess(MemoryAccess *, - const MemoryLocation &) override; - void invalidateInfo(MemoryAccess *) override; + MemoryAccess *getClobberingMemoryAccess(MemoryAccess *MA) override; + MemoryAccess *getClobberingMemoryAccess(MemoryAccess *MA, + const MemoryLocation &Loc) override; + + void invalidateInfo(MemoryAccess *MA) override { + if (auto *MUD = dyn_cast<MemoryUseOrDef>(MA)) + MUD->resetOptimized(); + } void verify(const MemorySSA *MSSA) override { MemorySSAWalker::verify(MSSA); - Walker.verify(MSSA); + Walker->verify(MSSA); + } +}; + +class MemorySSA::SkipSelfWalker final : public MemorySSAWalker { + ClobberWalkerBase *Walker; + +public: + SkipSelfWalker(MemorySSA *M, ClobberWalkerBase *W) + : MemorySSAWalker(M), Walker(W) {} + ~SkipSelfWalker() override = default; + + using MemorySSAWalker::getClobberingMemoryAccess; + + MemoryAccess *getClobberingMemoryAccess(MemoryAccess *MA) override; + MemoryAccess *getClobberingMemoryAccess(MemoryAccess *MA, + const MemoryLocation &Loc) override; + + void invalidateInfo(MemoryAccess *MA) override { + if (auto *MUD = dyn_cast<MemoryUseOrDef>(MA)) + MUD->resetOptimized(); + } + + void verify(const MemorySSA *MSSA) override { + MemorySSAWalker::verify(MSSA); + Walker->verify(MSSA); } }; @@ -1063,7 +1155,7 @@ void MemorySSA::markUnreachableAsLiveOnEntry(BasicBlock *BB) { MemorySSA::MemorySSA(Function &Func, AliasAnalysis *AA, DominatorTree *DT) : AA(AA), DT(DT), F(Func), LiveOnEntryDef(nullptr), Walker(nullptr), - NextID(0) { + SkipWalker(nullptr), NextID(0) { buildMemorySSA(); } @@ -1394,10 +1486,25 @@ MemorySSA::CachingWalker *MemorySSA::getWalkerImpl() { if (Walker) return Walker.get(); - Walker = llvm::make_unique<CachingWalker>(this, AA, DT); + if (!WalkerBase) + WalkerBase = llvm::make_unique<ClobberWalkerBase>(this, AA, DT); + + Walker = llvm::make_unique<CachingWalker>(this, WalkerBase.get()); return Walker.get(); } +MemorySSAWalker *MemorySSA::getSkipSelfWalker() { + if (SkipWalker) + return SkipWalker.get(); + + if (!WalkerBase) + WalkerBase = llvm::make_unique<ClobberWalkerBase>(this, AA, DT); + + SkipWalker = llvm::make_unique<SkipSelfWalker>(this, WalkerBase.get()); + return SkipWalker.get(); + } + + // This is a helper function used by the creation routines. It places NewAccess // into the access and defs lists for a given basic block, at the given // insertion point. @@ -1461,15 +1568,25 @@ void MemorySSA::insertIntoListsBefore(MemoryAccess *What, const BasicBlock *BB, BlockNumberingValid.erase(BB); } +void MemorySSA::prepareForMoveTo(MemoryAccess *What, BasicBlock *BB) { + // Keep it in the lookup tables, remove from the lists + removeFromLists(What, false); + + // Note that moving should implicitly invalidate the optimized state of a + // MemoryUse (and Phis can't be optimized). However, it doesn't do so for a + // MemoryDef. + if (auto *MD = dyn_cast<MemoryDef>(What)) + MD->resetOptimized(); + What->setBlock(BB); +} + // Move What before Where in the IR. The end result is that What will belong to // the right lists and have the right Block set, but will not otherwise be // correct. It will not have the right defining access, and if it is a def, // things below it will not properly be updated. void MemorySSA::moveTo(MemoryUseOrDef *What, BasicBlock *BB, AccessList::iterator Where) { - // Keep it in the lookup tables, remove from the lists - removeFromLists(What, false); - What->setBlock(BB); + prepareForMoveTo(What, BB); insertIntoListsBefore(What, BB, Where); } @@ -1485,8 +1602,7 @@ void MemorySSA::moveTo(MemoryAccess *What, BasicBlock *BB, assert(Inserted && "Cannot move a Phi to a block that already has one"); } - removeFromLists(What, false); - What->setBlock(BB); + prepareForMoveTo(What, BB); insertIntoListsForBlock(What, BB, Point); } @@ -1500,9 +1616,10 @@ MemoryPhi *MemorySSA::createMemoryPhi(BasicBlock *BB) { } MemoryUseOrDef *MemorySSA::createDefinedAccess(Instruction *I, - MemoryAccess *Definition) { + MemoryAccess *Definition, + const MemoryUseOrDef *Template) { assert(!isa<PHINode>(I) && "Cannot create a defined access for a PHI"); - MemoryUseOrDef *NewAccess = createNewAccess(I); + MemoryUseOrDef *NewAccess = createNewAccess(I, Template); assert( NewAccess != nullptr && "Tried to create a memory access for a non-memory touching instruction"); @@ -1525,7 +1642,8 @@ static inline bool isOrdered(const Instruction *I) { } /// Helper function to create new memory accesses -MemoryUseOrDef *MemorySSA::createNewAccess(Instruction *I) { +MemoryUseOrDef *MemorySSA::createNewAccess(Instruction *I, + const MemoryUseOrDef *Template) { // The assume intrinsic has a control dependency which we model by claiming // that it writes arbitrarily. Ignore that fake memory dependency here. // FIXME: Replace this special casing with a more accurate modelling of @@ -1534,18 +1652,31 @@ MemoryUseOrDef *MemorySSA::createNewAccess(Instruction *I) { if (II->getIntrinsicID() == Intrinsic::assume) return nullptr; - // Find out what affect this instruction has on memory. - ModRefInfo ModRef = AA->getModRefInfo(I, None); - // The isOrdered check is used to ensure that volatiles end up as defs - // (atomics end up as ModRef right now anyway). Until we separate the - // ordering chain from the memory chain, this enables people to see at least - // some relative ordering to volatiles. Note that getClobberingMemoryAccess - // will still give an answer that bypasses other volatile loads. TODO: - // Separate memory aliasing and ordering into two different chains so that we - // can precisely represent both "what memory will this read/write/is clobbered - // by" and "what instructions can I move this past". - bool Def = isModSet(ModRef) || isOrdered(I); - bool Use = isRefSet(ModRef); + bool Def, Use; + if (Template) { + Def = dyn_cast_or_null<MemoryDef>(Template) != nullptr; + Use = dyn_cast_or_null<MemoryUse>(Template) != nullptr; +#if !defined(NDEBUG) + ModRefInfo ModRef = AA->getModRefInfo(I, None); + bool DefCheck, UseCheck; + DefCheck = isModSet(ModRef) || isOrdered(I); + UseCheck = isRefSet(ModRef); + assert(Def == DefCheck && (Def || Use == UseCheck) && "Invalid template"); +#endif + } else { + // Find out what affect this instruction has on memory. + ModRefInfo ModRef = AA->getModRefInfo(I, None); + // The isOrdered check is used to ensure that volatiles end up as defs + // (atomics end up as ModRef right now anyway). Until we separate the + // ordering chain from the memory chain, this enables people to see at least + // some relative ordering to volatiles. Note that getClobberingMemoryAccess + // will still give an answer that bypasses other volatile loads. TODO: + // Separate memory aliasing and ordering into two different chains so that + // we can precisely represent both "what memory will this read/write/is + // clobbered by" and "what instructions can I move this past". + Def = isModSet(ModRef) || isOrdered(I); + Use = isRefSet(ModRef); + } // It's possible for an instruction to not modify memory at all. During // construction, we ignore them. @@ -1648,6 +1779,34 @@ void MemorySSA::verifyMemorySSA() const { verifyOrdering(F); verifyDominationNumbers(F); Walker->verify(this); + verifyClobberSanity(F); +} + +/// Check sanity of the clobbering instruction for access MA. +void MemorySSA::checkClobberSanityAccess(const MemoryAccess *MA) const { + if (const auto *MUD = dyn_cast<MemoryUseOrDef>(MA)) { + if (!MUD->isOptimized()) + return; + auto *I = MUD->getMemoryInst(); + auto Loc = MemoryLocation::getOrNone(I); + if (Loc == None) + return; + auto *Clobber = MUD->getOptimized(); + UpwardsMemoryQuery Q(I, MUD); + checkClobberSanity(MUD, Clobber, *Loc, *this, Q, *AA, true); + } +} + +void MemorySSA::verifyClobberSanity(const Function &F) const { +#if !defined(NDEBUG) && defined(EXPENSIVE_CHECKS) + for (const BasicBlock &BB : F) { + const AccessList *Accesses = getBlockAccesses(&BB); + if (!Accesses) + continue; + for (const MemoryAccess &MA : *Accesses) + checkClobberSanityAccess(&MA); + } +#endif } /// Verify that all of the blocks we believe to have valid domination numbers @@ -1691,6 +1850,7 @@ void MemorySSA::verifyDominationNumbers(const Function &F) const { /// Verify that the order and existence of MemoryAccesses matches the /// order and existence of memory affecting instructions. void MemorySSA::verifyOrdering(Function &F) const { +#ifndef NDEBUG // Walk all the blocks, comparing what the lookups think and what the access // lists think, as well as the order in the blocks vs the order in the access // lists. @@ -1749,6 +1909,7 @@ void MemorySSA::verifyOrdering(Function &F) const { } ActualDefs.clear(); } +#endif } /// Verify the domination properties of MemorySSA by checking that each @@ -1791,6 +1952,7 @@ void MemorySSA::verifyUseInDefs(MemoryAccess *Def, MemoryAccess *Use) const { /// accesses and verifying that, for each use, it appears in the /// appropriate def's use list void MemorySSA::verifyDefUses(Function &F) const { +#ifndef NDEBUG for (BasicBlock &B : F) { // Phi nodes are attached to basic blocks if (MemoryPhi *Phi = getMemoryAccess(&B)) { @@ -1811,14 +1973,7 @@ void MemorySSA::verifyDefUses(Function &F) const { } } } -} - -MemoryUseOrDef *MemorySSA::getMemoryAccess(const Instruction *I) const { - return cast_or_null<MemoryUseOrDef>(ValueToMemoryAccess.lookup(I)); -} - -MemoryPhi *MemorySSA::getMemoryAccess(const BasicBlock *BB) const { - return cast_or_null<MemoryPhi>(ValueToMemoryAccess.lookup(cast<Value>(BB))); +#endif } /// Perform a local numbering on blocks so that instruction ordering can be @@ -2051,25 +2206,11 @@ void MemorySSAWrapperPass::print(raw_ostream &OS, const Module *M) const { MemorySSAWalker::MemorySSAWalker(MemorySSA *M) : MSSA(M) {} -MemorySSA::CachingWalker::CachingWalker(MemorySSA *M, AliasAnalysis *A, - DominatorTree *D) - : MemorySSAWalker(M), Walker(*M, *A, *D) {} - -void MemorySSA::CachingWalker::invalidateInfo(MemoryAccess *MA) { - if (auto *MUD = dyn_cast<MemoryUseOrDef>(MA)) - MUD->resetOptimized(); -} - -/// Walk the use-def chains starting at \p MA and find +/// Walk the use-def chains starting at \p StartingAccess and find /// the MemoryAccess that actually clobbers Loc. /// /// \returns our clobbering memory access -MemoryAccess *MemorySSA::CachingWalker::getClobberingMemoryAccess( - MemoryAccess *StartingAccess, UpwardsMemoryQuery &Q) { - return Walker.findClobber(StartingAccess, Q); -} - -MemoryAccess *MemorySSA::CachingWalker::getClobberingMemoryAccess( +MemoryAccess *MemorySSA::ClobberWalkerBase::getClobberingMemoryAccessBase( MemoryAccess *StartingAccess, const MemoryLocation &Loc) { if (isa<MemoryPhi>(StartingAccess)) return StartingAccess; @@ -2082,7 +2223,7 @@ MemoryAccess *MemorySSA::CachingWalker::getClobberingMemoryAccess( // Conservatively, fences are always clobbers, so don't perform the walk if we // hit a fence. - if (!ImmutableCallSite(I) && I->isFenceLike()) + if (!isa<CallBase>(I) && I->isFenceLike()) return StartingUseOrDef; UpwardsMemoryQuery Q; @@ -2093,11 +2234,12 @@ MemoryAccess *MemorySSA::CachingWalker::getClobberingMemoryAccess( // Unlike the other function, do not walk to the def of a def, because we are // handed something we already believe is the clobbering access. + // We never set SkipSelf to true in Q in this method. MemoryAccess *DefiningAccess = isa<MemoryUse>(StartingUseOrDef) ? StartingUseOrDef->getDefiningAccess() : StartingUseOrDef; - MemoryAccess *Clobber = getClobberingMemoryAccess(DefiningAccess, Q); + MemoryAccess *Clobber = Walker.findClobber(DefiningAccess, Q); LLVM_DEBUG(dbgs() << "Starting Memory SSA clobber for " << *I << " is "); LLVM_DEBUG(dbgs() << *StartingUseOrDef << "\n"); LLVM_DEBUG(dbgs() << "Final Memory SSA clobber for " << *I << " is "); @@ -2106,26 +2248,33 @@ MemoryAccess *MemorySSA::CachingWalker::getClobberingMemoryAccess( } MemoryAccess * -MemorySSA::CachingWalker::getClobberingMemoryAccess(MemoryAccess *MA) { +MemorySSA::ClobberWalkerBase::getClobberingMemoryAccessBase(MemoryAccess *MA, + bool SkipSelf) { auto *StartingAccess = dyn_cast<MemoryUseOrDef>(MA); // If this is a MemoryPhi, we can't do anything. if (!StartingAccess) return MA; + bool IsOptimized = false; + // If this is an already optimized use or def, return the optimized result. // Note: Currently, we store the optimized def result in a separate field, // since we can't use the defining access. - if (StartingAccess->isOptimized()) - return StartingAccess->getOptimized(); + if (StartingAccess->isOptimized()) { + if (!SkipSelf || !isa<MemoryDef>(StartingAccess)) + return StartingAccess->getOptimized(); + IsOptimized = true; + } const Instruction *I = StartingAccess->getMemoryInst(); - UpwardsMemoryQuery Q(I, StartingAccess); // We can't sanely do anything with a fence, since they conservatively clobber // all memory, and have no locations to get pointers from to try to // disambiguate. - if (!Q.IsCall && I->isFenceLike()) + if (!isa<CallBase>(I) && I->isFenceLike()) return StartingAccess; + UpwardsMemoryQuery Q(I, StartingAccess); + if (isUseTriviallyOptimizableToLiveOnEntry(*MSSA->AA, I)) { MemoryAccess *LiveOnEntry = MSSA->getLiveOnEntryDef(); StartingAccess->setOptimized(LiveOnEntry); @@ -2133,33 +2282,71 @@ MemorySSA::CachingWalker::getClobberingMemoryAccess(MemoryAccess *MA) { return LiveOnEntry; } - // Start with the thing we already think clobbers this location - MemoryAccess *DefiningAccess = StartingAccess->getDefiningAccess(); + MemoryAccess *OptimizedAccess; + if (!IsOptimized) { + // Start with the thing we already think clobbers this location + MemoryAccess *DefiningAccess = StartingAccess->getDefiningAccess(); + + // At this point, DefiningAccess may be the live on entry def. + // If it is, we will not get a better result. + if (MSSA->isLiveOnEntryDef(DefiningAccess)) { + StartingAccess->setOptimized(DefiningAccess); + StartingAccess->setOptimizedAccessType(None); + return DefiningAccess; + } - // At this point, DefiningAccess may be the live on entry def. - // If it is, we will not get a better result. - if (MSSA->isLiveOnEntryDef(DefiningAccess)) { - StartingAccess->setOptimized(DefiningAccess); - StartingAccess->setOptimizedAccessType(None); - return DefiningAccess; - } + OptimizedAccess = Walker.findClobber(DefiningAccess, Q); + StartingAccess->setOptimized(OptimizedAccess); + if (MSSA->isLiveOnEntryDef(OptimizedAccess)) + StartingAccess->setOptimizedAccessType(None); + else if (Q.AR == MustAlias) + StartingAccess->setOptimizedAccessType(MustAlias); + } else + OptimizedAccess = StartingAccess->getOptimized(); - MemoryAccess *Result = getClobberingMemoryAccess(DefiningAccess, Q); LLVM_DEBUG(dbgs() << "Starting Memory SSA clobber for " << *I << " is "); - LLVM_DEBUG(dbgs() << *DefiningAccess << "\n"); - LLVM_DEBUG(dbgs() << "Final Memory SSA clobber for " << *I << " is "); - LLVM_DEBUG(dbgs() << *Result << "\n"); - - StartingAccess->setOptimized(Result); - if (MSSA->isLiveOnEntryDef(Result)) - StartingAccess->setOptimizedAccessType(None); - else if (Q.AR == MustAlias) - StartingAccess->setOptimizedAccessType(MustAlias); + LLVM_DEBUG(dbgs() << *StartingAccess << "\n"); + LLVM_DEBUG(dbgs() << "Optimized Memory SSA clobber for " << *I << " is "); + LLVM_DEBUG(dbgs() << *OptimizedAccess << "\n"); + + MemoryAccess *Result; + if (SkipSelf && isa<MemoryPhi>(OptimizedAccess) && + isa<MemoryDef>(StartingAccess)) { + assert(isa<MemoryDef>(Q.OriginalAccess)); + Q.SkipSelfAccess = true; + Result = Walker.findClobber(OptimizedAccess, Q); + } else + Result = OptimizedAccess; + + LLVM_DEBUG(dbgs() << "Result Memory SSA clobber [SkipSelf = " << SkipSelf); + LLVM_DEBUG(dbgs() << "] for " << *I << " is " << *Result << "\n"); return Result; } MemoryAccess * +MemorySSA::CachingWalker::getClobberingMemoryAccess(MemoryAccess *MA) { + return Walker->getClobberingMemoryAccessBase(MA, false); +} + +MemoryAccess * +MemorySSA::CachingWalker::getClobberingMemoryAccess(MemoryAccess *MA, + const MemoryLocation &Loc) { + return Walker->getClobberingMemoryAccessBase(MA, Loc); +} + +MemoryAccess * +MemorySSA::SkipSelfWalker::getClobberingMemoryAccess(MemoryAccess *MA) { + return Walker->getClobberingMemoryAccessBase(MA, true); +} + +MemoryAccess * +MemorySSA::SkipSelfWalker::getClobberingMemoryAccess(MemoryAccess *MA, + const MemoryLocation &Loc) { + return Walker->getClobberingMemoryAccessBase(MA, Loc); +} + +MemoryAccess * DoNothingMemorySSAWalker::getClobberingMemoryAccess(MemoryAccess *MA) { if (auto *Use = dyn_cast<MemoryUseOrDef>(MA)) return Use->getDefiningAccess(); |