diff --git a/include/swift/SILOptimizer/Analysis/AliasAnalysis.h b/include/swift/SILOptimizer/Analysis/AliasAnalysis.h index 1aba911f6ce..1ac61099733 100644 --- a/include/swift/SILOptimizer/Analysis/AliasAnalysis.h +++ b/include/swift/SILOptimizer/Analysis/AliasAnalysis.h @@ -13,53 +13,19 @@ #ifndef SWIFT_SILOPTIMIZER_ANALYSIS_ALIASANALYSIS_H #define SWIFT_SILOPTIMIZER_ANALYSIS_ALIASANALYSIS_H -#include "swift/Basic/ValueEnumerator.h" #include "swift/SIL/ApplySite.h" #include "swift/SIL/SILInstruction.h" #include "swift/SILOptimizer/Analysis/Analysis.h" -#include "swift/SILOptimizer/Analysis/SideEffectAnalysis.h" #include "llvm/ADT/DenseMap.h" -using swift::RetainObserveKind; - -namespace { - - /// A key used for the AliasAnalysis cache. - /// - /// This struct represents the argument list to the method 'alias'. The two - /// SILValue pointers are mapped to integer indices because we need an - /// efficient way to invalidate them (the mechanism is described below). The - /// Type arguments are translated to void* because their underlying storage is - /// opaque pointers that never goes away. - struct AliasKeyTy { - // The SILValue pair: - swift::ValueIndexTy V1, V2; - // The TBAAType pair: - void *T1, *T2; - }; - - /// A key used for the MemoryBehavior Analysis cache. - /// - /// The two SILValue pointers are mapped to integer indices because we need an - /// efficient way to invalidate them (the mechanism is described below). The - /// RetainObserveKind represents the inspection mode for the memory behavior - /// analysis. - struct MemBehaviorKeyTy { - // The SILValue pair: - swift::ValueIndexTy V1, V2; - }; -} - namespace swift { -class SILInstruction; -class ValueBase; class SideEffectAnalysis; class EscapeAnalysis; /// This class is a simple wrapper around an alias analysis cache. This is /// needed since we do not have an "analysis" infrastructure. -class AliasAnalysis : public SILAnalysis { +class AliasAnalysis { public: /// This enum describes the different kinds of aliasing relations between @@ -89,12 +55,28 @@ public: }; private: - SILModule *Mod; - SideEffectAnalysis *SEA; - EscapeAnalysis *EA; + /// A key used for the AliasAnalysis cache. + /// + /// This struct represents the argument list to the method 'alias'. + struct AliasCacheKey { + // The SILValue pair: + SILValue V1, V2; + // The TBAAType pair: + void *T1, *T2; + }; + + friend struct ::llvm::DenseMapInfo; + + /// A key used for the MemoryBehavior Analysis cache. + using MemBehaviorCacheKey = std::pair; + + using ScopeCacheKey = std::pair; using TBAACacheKey = std::pair; + SideEffectAnalysis *SEA; + EscapeAnalysis *EA; + /// A cache for the computation of TBAA. True means that the types may /// alias. False means that the types must not alias. /// @@ -105,33 +87,27 @@ private: /// AliasAnalysis value cache. /// /// The alias() method uses this map to cache queries. - llvm::DenseMap AliasCache; + llvm::DenseMap AliasCache; using MemoryBehavior = SILInstruction::MemoryBehavior; + /// MemoryBehavior value cache. /// /// The computeMemoryBehavior() method uses this map to cache queries. - llvm::DenseMap MemoryBehaviorCache; + llvm::DenseMap MemoryBehaviorCache; /// Set of instructions inside immutable-scopes. /// - /// Contains pairs of intruction indices: the first instruction is the begin- - /// scope instruction (e.g. begin_access), the second instruction is an + /// Contains pairs of intructions: the first instruction is the begin-scope + /// instruction (e.g. begin_access), the second instruction is an /// instruction inside the scope (only may-write instructions are considered). - llvm::DenseSet instsInImmutableScopes; + llvm::DenseSet instsInImmutableScopes; /// Computed immutable scopes. /// - /// Contains the begin-scope instruction's indices (e.g. begin_access) of - /// all computed scopes. - llvm::DenseSet immutableScopeComputed; - - /// The caches can't directly map a pair of value/instruction pointers - /// to results because we'd like to be able to remove deleted instruction - /// pointers without having to scan the whole map. So, instead of storing - /// pointers we map pointers to indices and store the indices. - ValueEnumerator ValueToIndex; - ValueEnumerator InstructionToIndex; + /// Contains the begin-scope instructions (e.g. begin_access) of all computed + /// scopes. + llvm::SmallPtrSet immutableScopeComputed; AliasResult aliasAddressProjection(SILValue V1, SILValue V2, SILValue O1, SILValue O2); @@ -144,34 +120,15 @@ private: /// Returns True if memory of type \p T1 and \p T2 may alias. bool typesMayAlias(SILType T1, SILType T2, const SILFunction &F); - virtual void handleDeleteNotification(SILNode *node) override; - - virtual bool needsNotifications() override { return true; } - - void computeImmutableScope(SingleValueInstruction *beginScopeInst, - ValueIndexTy beginIdx); + void computeImmutableScope(SingleValueInstruction *beginScopeInst); bool isInImmutableScope(SILInstruction *inst, SILValue V); public: - AliasAnalysis(SILModule *M) - : SILAnalysis(SILAnalysisKind::Alias), Mod(M), SEA(nullptr), EA(nullptr) { - } + AliasAnalysis(SideEffectAnalysis *SEA, EscapeAnalysis *EA) + : SEA(SEA), EA(EA) {} - static bool classof(const SILAnalysis *S) { - return S->getKind() == SILAnalysisKind::Alias; - } - - virtual void initialize(SILPassManager *PM) override; - - /// Explicitly invalidate an instruction. - /// - /// This can be useful to update the alias analysis within a pass. - /// It's needed if e.g. \p inst is an address projection and its operand gets - /// replaced with a different underlying object. - void invalidateInstruction(SILInstruction *inst) { - handleDeleteNotification(inst->asSILNode()); - } + static SILAnalysisKind getAnalysisKind() { return SILAnalysisKind::Alias; } /// Perform an alias query to see if V1, V2 refer to the same values. AliasResult alias(SILValue V1, SILValue V2, SILType TBAAType1 = SILType(), @@ -249,37 +206,6 @@ public: /// Returns true if \p Ptr may be released by the builtin \p BI. bool canBuiltinDecrementRefCount(BuiltinInst *BI, SILValue Ptr); - - /// Encodes the alias query as a AliasKeyTy. - /// The parameters to this function are identical to the parameters of alias() - /// and this method serializes them into a key for the alias analysis cache. - AliasKeyTy toAliasKey(SILValue V1, SILValue V2, SILType Type1, SILType Type2); - - /// Encodes the memory behavior query as a MemBehaviorKeyTy. - MemBehaviorKeyTy toMemoryBehaviorKey(SILInstruction *V1, SILValue V2); - - virtual void invalidate() override { - AliasCache.clear(); - MemoryBehaviorCache.clear(); - InstructionToIndex.clear(); - ValueToIndex.clear(); - instsInImmutableScopes.clear(); - immutableScopeComputed.clear(); - } - - virtual void invalidate(SILFunction *, - SILAnalysis::InvalidationKind K) override { - invalidate(); - } - - /// Notify the analysis about a newly created function. - virtual void notifyAddedOrModifiedFunction(SILFunction *F) override {} - - /// Notify the analysis about a function which will be deleted from the - /// module. - virtual void notifyWillDeleteFunction(SILFunction *F) override {} - - virtual void invalidateFunctionTables() override { } }; @@ -293,51 +219,32 @@ SILType computeTBAAType(SILValue V); } // end namespace swift namespace llvm { - template <> struct DenseMapInfo { - static inline AliasKeyTy getEmptyKey() { - auto Allone = std::numeric_limits::max(); - return {0, Allone, nullptr, nullptr}; - } - static inline AliasKeyTy getTombstoneKey() { - auto Allone = std::numeric_limits::max(); - return {Allone, 0, nullptr, nullptr}; - } - static unsigned getHashValue(const AliasKeyTy Val) { - unsigned H = 0; - H ^= DenseMapInfo::getHashValue(Val.V1); - H ^= DenseMapInfo::getHashValue(Val.V2); - H ^= DenseMapInfo::getHashValue(Val.T1); - H ^= DenseMapInfo::getHashValue(Val.T2); - return H; - } - static bool isEqual(const AliasKeyTy LHS, const AliasKeyTy RHS) { - return LHS.V1 == RHS.V1 && - LHS.V2 == RHS.V2 && - LHS.T1 == RHS.T1 && - LHS.T2 == RHS.T2; - } - }; +template <> struct DenseMapInfo { + using AliasCacheKey = swift::AliasAnalysis::AliasCacheKey; - template <> struct DenseMapInfo { - static inline MemBehaviorKeyTy getEmptyKey() { - auto Allone = std::numeric_limits::max(); - return {0, Allone}; - } - static inline MemBehaviorKeyTy getTombstoneKey() { - auto Allone = std::numeric_limits::max(); - return {Allone, 0}; - } - static unsigned getHashValue(const MemBehaviorKeyTy V) { - unsigned H = 0; - H ^= DenseMapInfo::getHashValue(V.V1); - H ^= DenseMapInfo::getHashValue(V.V2); - return H; - } - static bool isEqual(const MemBehaviorKeyTy LHS, - const MemBehaviorKeyTy RHS) { - return LHS.V1 == RHS.V1 && LHS.V2 == RHS.V2; - } - }; + static inline AliasCacheKey getEmptyKey() { + return {DenseMapInfo::getEmptyKey(), swift::SILValue(), + nullptr, nullptr}; + } + static inline AliasCacheKey getTombstoneKey() { + return {DenseMapInfo::getTombstoneKey(), swift::SILValue(), + nullptr, nullptr}; + } + static unsigned getHashValue(const AliasCacheKey Val) { + unsigned H = 0; + H ^= DenseMapInfo::getHashValue(Val.V1); + H ^= DenseMapInfo::getHashValue(Val.V2); + H ^= DenseMapInfo::getHashValue(Val.T1); + H ^= DenseMapInfo::getHashValue(Val.T2); + return H; + } + static bool isEqual(const AliasCacheKey LHS, const AliasCacheKey RHS) { + return LHS.V1 == RHS.V1 && + LHS.V2 == RHS.V2 && + LHS.T1 == RHS.T1 && + LHS.T2 == RHS.T2; + } +}; } #endif diff --git a/include/swift/SILOptimizer/Analysis/EpilogueARCAnalysis.h b/include/swift/SILOptimizer/Analysis/EpilogueARCAnalysis.h index d483ca695e2..b24eba5948a 100644 --- a/include/swift/SILOptimizer/Analysis/EpilogueARCAnalysis.h +++ b/include/swift/SILOptimizer/Analysis/EpilogueARCAnalysis.h @@ -273,18 +273,17 @@ public: }; class EpilogueARCAnalysis : public FunctionAnalysisBase { + /// Backlink to the pass manager. + SILPassManager *passManager = nullptr; /// Current post order analysis we are using. - PostOrderAnalysis *PO; - /// Current alias analysis we are using. - AliasAnalysis *AA; + PostOrderAnalysis *PO = nullptr; /// Current RC Identity analysis we are using. - RCIdentityAnalysis *RC; - + RCIdentityAnalysis *RC = nullptr; + public: EpilogueARCAnalysis(SILModule *) : FunctionAnalysisBase( - SILAnalysisKind::EpilogueARC), - PO(nullptr), AA(nullptr), RC(nullptr) {} + SILAnalysisKind::EpilogueARC) {} EpilogueARCAnalysis(const EpilogueARCAnalysis &) = delete; EpilogueARCAnalysis &operator=(const EpilogueARCAnalysis &) = delete; @@ -312,9 +311,7 @@ public: virtual void initialize(SILPassManager *PM) override; virtual std::unique_ptr - newFunctionAnalysis(SILFunction *F) override { - return std::make_unique(F, PO, AA, RC); - } + newFunctionAnalysis(SILFunction *F) override; virtual bool shouldInvalidate(SILAnalysis::InvalidationKind K) override { return true; diff --git a/include/swift/SILOptimizer/PassManager/PassManager.h b/include/swift/SILOptimizer/PassManager/PassManager.h index 8c82ff0169d..713891eab9c 100644 --- a/include/swift/SILOptimizer/PassManager/PassManager.h +++ b/include/swift/SILOptimizer/PassManager/PassManager.h @@ -132,6 +132,15 @@ public: llvm_unreachable("Unable to find analysis for requested type."); } + template + T *getAnalysis(SILFunction *f) { + for (SILAnalysis *A : Analyses) { + if (A->getKind() == T::getAnalysisKind()) + return static_cast *>(A)->get(f); + } + llvm_unreachable("Unable to find analysis for requested type."); + } + /// \returns the module that the pass manager owns. SILModule *getModule() { return Mod; } diff --git a/include/swift/SILOptimizer/PassManager/Transforms.h b/include/swift/SILOptimizer/PassManager/Transforms.h index edc9177a11c..9955ac0b863 100644 --- a/include/swift/SILOptimizer/PassManager/Transforms.h +++ b/include/swift/SILOptimizer/PassManager/Transforms.h @@ -86,6 +86,9 @@ namespace swift { template T* getAnalysis() { return PM->getAnalysis(); } + template + T* getAnalysis(SILFunction *f) { return PM->getAnalysis(f); } + const SILOptions &getOptions() { return PM->getOptions(); } }; diff --git a/lib/SILOptimizer/ARC/ARCLoopOpts.cpp b/lib/SILOptimizer/ARC/ARCLoopOpts.cpp index aa54592497e..24f0ace6347 100644 --- a/lib/SILOptimizer/ARC/ARCLoopOpts.cpp +++ b/lib/SILOptimizer/ARC/ARCLoopOpts.cpp @@ -66,7 +66,7 @@ class ARCLoopOpts : public SILFunctionTransform { } // Get all of the analyses that we need. - auto *AA = getAnalysis(); + auto *AA = getAnalysis(F); auto *RCFI = getAnalysis()->get(F); auto *EAFI = getAnalysis()->get(F); auto *LRFI = getAnalysis()->get(F); diff --git a/lib/SILOptimizer/ARC/ARCSequenceOpts.cpp b/lib/SILOptimizer/ARC/ARCSequenceOpts.cpp index a3a0cb35980..4b932aa15d5 100644 --- a/lib/SILOptimizer/ARC/ARCSequenceOpts.cpp +++ b/lib/SILOptimizer/ARC/ARCSequenceOpts.cpp @@ -260,7 +260,7 @@ class ARCSequenceOpts : public SILFunctionTransform { return; if (!EnableLoopARC) { - auto *AA = getAnalysis(); + auto *AA = getAnalysis(F); auto *POTA = getAnalysis(); auto *RCFI = getAnalysis()->get(F); auto *EAFI = getAnalysis()->get(F); @@ -288,7 +288,7 @@ class ARCSequenceOpts : public SILFunctionTransform { LA->unlockInvalidation(); } - auto *AA = getAnalysis(); + auto *AA = getAnalysis(F); auto *POTA = getAnalysis(); auto *RCFI = getAnalysis()->get(F); auto *EAFI = getAnalysis()->get(F); diff --git a/lib/SILOptimizer/Analysis/AliasAnalysis.cpp b/lib/SILOptimizer/Analysis/AliasAnalysis.cpp index 421a3784253..3bdab76f0cf 100644 --- a/lib/SILOptimizer/Analysis/AliasAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/AliasAnalysis.cpp @@ -31,12 +31,6 @@ using namespace swift; -// The AliasAnalysis Cache must not grow beyond this size. -// We limit the size of the AA cache to 2**14 because we want to limit the -// memory usage of this cache. -static const int AliasAnalysisMaxCacheSize = 16384; - - //===----------------------------------------------------------------------===// // AA Debugging //===----------------------------------------------------------------------===// @@ -538,27 +532,6 @@ bool AliasAnalysis::typesMayAlias(SILType T1, SILType T2, return MA; } -void AliasAnalysis::handleDeleteNotification(SILNode *node) { - // The pointer 'node' is going away. We can't scan the whole cache - // and remove all of the occurrences of the pointer. Instead we remove - // the pointer from the index caches. - - if (auto *value = dyn_cast(node)) - ValueToIndex.invalidateValue(value); - - if (auto *inst = dyn_cast(node)) { - InstructionToIndex.invalidateValue(inst); - - // When a MultipleValueInstruction is deleted, we have to invalidate all - // the instruction results. - if (auto *mvi = dyn_cast(inst)) { - for (unsigned idx = 0, end = mvi->getNumResults(); idx < end; ++idx) { - ValueToIndex.invalidateValue(mvi->getResult(idx)); - } - } - } -} - //===----------------------------------------------------------------------===// // Entry Points //===----------------------------------------------------------------------===// @@ -567,7 +540,8 @@ void AliasAnalysis::handleDeleteNotification(SILNode *node) { /// to disambiguate the two values. AliasResult AliasAnalysis::alias(SILValue V1, SILValue V2, SILType TBAAType1, SILType TBAAType2) { - AliasKeyTy Key = toAliasKey(V1, V2, TBAAType1, TBAAType2); + AliasCacheKey Key = {V1, V2, TBAAType1.getOpaqueValue(), + TBAAType2.getOpaqueValue()}; // Check if we've already computed this result. auto It = AliasCache.find(Key); @@ -575,11 +549,6 @@ AliasResult AliasAnalysis::alias(SILValue V1, SILValue V2, return It->second; } - // Flush the cache if the size of the cache is too large. - if (AliasCache.size() > AliasAnalysisMaxCacheSize) { - AliasCache.clear(); - } - // Calculate the aliasing result and store it in the cache. auto Result = aliasInner(V1, V2, TBAAType1, TBAAType2); AliasCache[Key] = Result; @@ -807,24 +776,35 @@ bool AliasAnalysis::mayValueReleaseInterfereWithInstruction( return EA->mayReleaseReferenceContent(releasedReference, accessedPointer); } -void AliasAnalysis::initialize(SILPassManager *PM) { - SEA = PM->getAnalysis(); - EA = PM->getAnalysis(); -} +namespace { + +class AliasAnalysisContainer : public FunctionAnalysisBase { + SideEffectAnalysis *SEA = nullptr; + EscapeAnalysis *EA = nullptr; + +public: + AliasAnalysisContainer() : FunctionAnalysisBase(SILAnalysisKind::Alias) {} + + virtual bool shouldInvalidate(SILAnalysis::InvalidationKind K) override { + return K & InvalidationKind::Instructions; + } + + // Computes loop information for the given function using dominance + // information. + virtual std::unique_ptr + newFunctionAnalysis(SILFunction *F) override { + assert(EA && SEA && "dependent analysis not initialized"); + return std::make_unique(SEA, EA); + } + + virtual void initialize(SILPassManager *PM) override { + SEA = PM->getAnalysis(); + EA = PM->getAnalysis(); + } +}; + +} // end anonymous namespace SILAnalysis *swift::createAliasAnalysis(SILModule *M) { - return new AliasAnalysis(M); -} - -AliasKeyTy AliasAnalysis::toAliasKey(SILValue V1, SILValue V2, - SILType Type1, SILType Type2) { - ValueIndexTy idx1 = ValueToIndex.getIndex(V1); - assert(idx1 != std::numeric_limits::max() && - "~0 index reserved for empty/tombstone keys"); - ValueIndexTy idx2 = ValueToIndex.getIndex(V2); - assert(idx2 != std::numeric_limits::max() && - "~0 index reserved for empty/tombstone keys"); - void *t1 = Type1.getOpaqueValue(); - void *t2 = Type2.getOpaqueValue(); - return {idx1, idx2, t1, t2}; + return new AliasAnalysisContainer(); } diff --git a/lib/SILOptimizer/Analysis/EpilogueARCAnalysis.cpp b/lib/SILOptimizer/Analysis/EpilogueARCAnalysis.cpp index cd057ace2ec..325895dbc4f 100644 --- a/lib/SILOptimizer/Analysis/EpilogueARCAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/EpilogueARCAnalysis.cpp @@ -172,11 +172,17 @@ bool EpilogueARCContext::computeEpilogueARC() { //===----------------------------------------------------------------------===// void EpilogueARCAnalysis::initialize(SILPassManager *PM) { - AA = PM->getAnalysis(); + passManager = PM; PO = PM->getAnalysis(); RC = PM->getAnalysis(); } +std::unique_ptr +EpilogueARCAnalysis::newFunctionAnalysis(SILFunction *F) { + return std::make_unique(F, PO, + passManager->getAnalysis(F), RC); +} + SILAnalysis *swift::createEpilogueARCAnalysis(SILModule *M) { return new EpilogueARCAnalysis(M); } diff --git a/lib/SILOptimizer/Analysis/MemoryBehavior.cpp b/lib/SILOptimizer/Analysis/MemoryBehavior.cpp index 39b0695aeaf..39dcb0d09d9 100644 --- a/lib/SILOptimizer/Analysis/MemoryBehavior.cpp +++ b/lib/SILOptimizer/Analysis/MemoryBehavior.cpp @@ -25,16 +25,6 @@ using namespace swift; -// The MemoryBehavior Cache must not grow beyond this size. -// We limit the size of the MB cache to 2**14 because we want to limit the -// memory usage of this cache. -static const int MemoryBehaviorAnalysisMaxCacheSize = 16384; - -// The maximum size of instsInImmutableScopes. -// Usually more than enough. But in corner cases it can grow quadratically (in -// case of many large nested immutable scopes). -static const int ImmutableScopeInstsMaxSize = 18384; - //===----------------------------------------------------------------------===// // Memory Behavior Implementation //===----------------------------------------------------------------------===// @@ -525,18 +515,13 @@ visitBeginCOWMutationInst(BeginCOWMutationInst *BCMI) { MemBehavior AliasAnalysis::computeMemoryBehavior(SILInstruction *Inst, SILValue V) { - MemBehaviorKeyTy Key = toMemoryBehaviorKey(Inst, V); + MemBehaviorCacheKey Key = {V, Inst}; // Check if we've already computed this result. auto It = MemoryBehaviorCache.find(Key); if (It != MemoryBehaviorCache.end()) { return It->second; } - // Flush the cache if the size of the cache is too large. - if (MemoryBehaviorCache.size() > MemoryBehaviorAnalysisMaxCacheSize) { - MemoryBehaviorCache.clear(); - } - // Calculate the aliasing result and store it in the cache. auto Result = computeMemoryBehaviorInner(Inst, V); MemoryBehaviorCache[Key] = Result; @@ -586,8 +571,7 @@ static SILValue getBeginScopeInst(SILValue V) { /// The \p beginScopeInst is either a ``begin_access [read]`` or the begin of a /// borrow scope (begin_borrow, load_borrow) of an immutable copy-on-write /// buffer. -void AliasAnalysis::computeImmutableScope(SingleValueInstruction *beginScopeInst, - ValueIndexTy beginIdx) { +void AliasAnalysis::computeImmutableScope(SingleValueInstruction *beginScopeInst) { BasicBlockSet visitedBlocks(beginScopeInst->getFunction()); llvm::SmallVector, 16> workList; @@ -636,8 +620,7 @@ void AliasAnalysis::computeImmutableScope(SingleValueInstruction *beginScopeInst break; } if (inst->mayWriteToMemory()) { - instsInImmutableScopes.insert({beginIdx, - InstructionToIndex.getIndex(inst)}); + instsInImmutableScopes.insert({beginScopeInst, inst}); } } } @@ -668,20 +651,11 @@ bool AliasAnalysis::isInImmutableScope(SILInstruction *inst, SILValue V) { if (!beginScopeInst) return false; - ValueIndexTy beginIdx = InstructionToIndex.getIndex(beginScopeInst); - // Recompute the scope if not done yet. - if (immutableScopeComputed.insert(beginIdx).second) { - // In practice this will never happen. Just be be sure to not run into - // quadratic complexity in obscure corner cases. - if (instsInImmutableScopes.size() > ImmutableScopeInstsMaxSize) - return false; - - computeImmutableScope(beginScopeInst, beginIdx); + if (immutableScopeComputed.insert(beginScopeInst).second) { + computeImmutableScope(beginScopeInst); } - - ValueIndexTy instIdx = InstructionToIndex.getIndex(inst); - return instsInImmutableScopes.contains({beginIdx, instIdx}); + return instsInImmutableScopes.contains({beginScopeInst, inst}); } MemBehavior @@ -700,14 +674,3 @@ AliasAnalysis::computeMemoryBehaviorInner(SILInstruction *Inst, SILValue V) { } return result; } - -MemBehaviorKeyTy AliasAnalysis::toMemoryBehaviorKey(SILInstruction *V1, - SILValue V2) { - ValueIndexTy idx1 = InstructionToIndex.getIndex(V1); - assert(idx1 != std::numeric_limits::max() && - "~0 index reserved for empty/tombstone keys"); - ValueIndexTy idx2 = ValueToIndex.getIndex(V2); - assert(idx2 != std::numeric_limits::max() && - "~0 index reserved for empty/tombstone keys"); - return {idx1, idx2}; -} diff --git a/lib/SILOptimizer/LoopTransforms/LICM.cpp b/lib/SILOptimizer/LoopTransforms/LICM.cpp index b73da1f4b68..cd5cf1254d3 100644 --- a/lib/SILOptimizer/LoopTransforms/LICM.cpp +++ b/lib/SILOptimizer/LoopTransforms/LICM.cpp @@ -1467,7 +1467,7 @@ public: DominanceAnalysis *DA = PM->getAnalysis(); PostDominanceAnalysis *PDA = PM->getAnalysis(); - AliasAnalysis *AA = PM->getAnalysis(); + AliasAnalysis *AA = PM->getAnalysis(F); SideEffectAnalysis *SEA = PM->getAnalysis(); AccessedStorageAnalysis *ASA = getAnalysis(); DominanceInfo *DomTree = nullptr; diff --git a/lib/SILOptimizer/SILCombiner/SILCombine.cpp b/lib/SILOptimizer/SILCombiner/SILCombine.cpp index f254a2a80d9..0d065be99f9 100644 --- a/lib/SILOptimizer/SILCombiner/SILCombine.cpp +++ b/lib/SILOptimizer/SILCombiner/SILCombine.cpp @@ -387,7 +387,7 @@ class SILCombine : public SILFunctionTransform { /// The entry point to the transformation. void run() override { - auto *AA = PM->getAnalysis(); + auto *AA = PM->getAnalysis(getFunction()); auto *DA = PM->getAnalysis(); auto *PCA = PM->getAnalysis(); auto *CHA = PM->getAnalysis(); diff --git a/lib/SILOptimizer/Transforms/ARCCodeMotion.cpp b/lib/SILOptimizer/Transforms/ARCCodeMotion.cpp index 9baaf56dea8..c731ec820cd 100644 --- a/lib/SILOptimizer/Transforms/ARCCodeMotion.cpp +++ b/lib/SILOptimizer/Transforms/ARCCodeMotion.cpp @@ -1189,7 +1189,7 @@ public: POA->invalidateFunction(F); auto *PO = POA->get(F); - auto *AA = PM->getAnalysis(); + auto *AA = PM->getAnalysis(F); auto *RCFI = PM->getAnalysis()->get(F); llvm::SpecificBumpPtrAllocator BPA; diff --git a/lib/SILOptimizer/Transforms/COWOpts.cpp b/lib/SILOptimizer/Transforms/COWOpts.cpp index de13369819e..7a2c0e96e27 100644 --- a/lib/SILOptimizer/Transforms/COWOpts.cpp +++ b/lib/SILOptimizer/Transforms/COWOpts.cpp @@ -89,7 +89,7 @@ void COWOptsPass::run() { LLVM_DEBUG(llvm::dbgs() << "*** RedundantPhiElimination on function: " << F->getName() << " ***\n"); - AA = PM->getAnalysis(); + AA = PM->getAnalysis(F); bool changed = false; for (SILBasicBlock &block : *F) { diff --git a/lib/SILOptimizer/Transforms/DeadStoreElimination.cpp b/lib/SILOptimizer/Transforms/DeadStoreElimination.cpp index 41a146cf09e..c8e6bd4d287 100644 --- a/lib/SILOptimizer/Transforms/DeadStoreElimination.cpp +++ b/lib/SILOptimizer/Transforms/DeadStoreElimination.cpp @@ -1275,7 +1275,7 @@ public: LLVM_DEBUG(llvm::dbgs() << "*** DSE on function: " << F->getName() << " ***\n"); - auto *AA = PM->getAnalysis(); + auto *AA = PM->getAnalysis(F); auto *TE = PM->getAnalysis(); auto *EAFI = PM->getAnalysis()->get(F); diff --git a/lib/SILOptimizer/Transforms/RedundantLoadElimination.cpp b/lib/SILOptimizer/Transforms/RedundantLoadElimination.cpp index 5a71965f8be..c3b8ee87d9a 100644 --- a/lib/SILOptimizer/Transforms/RedundantLoadElimination.cpp +++ b/lib/SILOptimizer/Transforms/RedundantLoadElimination.cpp @@ -1681,7 +1681,7 @@ public: LLVM_DEBUG(llvm::dbgs() << "*** RLE on function: " << F->getName() << " ***\n"); - auto *AA = PM->getAnalysis(); + auto *AA = PM->getAnalysis(F); auto *TE = PM->getAnalysis(); auto *PO = PM->getAnalysis()->get(F); auto *EAFI = PM->getAnalysis()->get(F); diff --git a/lib/SILOptimizer/Transforms/SILCodeMotion.cpp b/lib/SILOptimizer/Transforms/SILCodeMotion.cpp index b0a1c444f88..5f6cd3a25a2 100644 --- a/lib/SILOptimizer/Transforms/SILCodeMotion.cpp +++ b/lib/SILOptimizer/Transforms/SILCodeMotion.cpp @@ -1778,7 +1778,7 @@ public: if (F->hasOwnership()) return; - auto *AA = getAnalysis(); + auto *AA = getAnalysis(F); auto *PO = getAnalysis()->get(F); auto *RCIA = getAnalysis()->get(getFunction()); diff --git a/lib/SILOptimizer/Transforms/TempLValueOpt.cpp b/lib/SILOptimizer/Transforms/TempLValueOpt.cpp index 9679c17609c..26c41f89405 100644 --- a/lib/SILOptimizer/Transforms/TempLValueOpt.cpp +++ b/lib/SILOptimizer/Transforms/TempLValueOpt.cpp @@ -78,10 +78,8 @@ public: void run() override; private: - AliasAnalysis *AA = nullptr; - - bool tempLValueOpt(CopyAddrInst *copyInst); - bool combineCopyAndDestroy(CopyAddrInst *copyInst); + void tempLValueOpt(CopyAddrInst *copyInst); + void combineCopyAndDestroy(CopyAddrInst *copyInst); }; void TempLValueOptPass::run() { @@ -92,9 +90,6 @@ void TempLValueOptPass::run() { LLVM_DEBUG(llvm::dbgs() << "*** TempLValueOptPass on function: " << F->getName() << " ***\n"); - AA = PM->getAnalysis(); - - bool changed = false; for (SILBasicBlock &block : *F) { // First collect all copy_addr instructions upfront to avoid iterator // invalidation problems (the optimizations might delete the copy_addr @@ -106,14 +101,10 @@ void TempLValueOptPass::run() { } // Do the optimizations. for (CopyAddrInst *copyInst : copyInsts) { - changed |= combineCopyAndDestroy(copyInst); - changed |= tempLValueOpt(copyInst); + combineCopyAndDestroy(copyInst); + tempLValueOpt(copyInst); } } - - if (changed) { - invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions); - } } static SingleValueInstruction *isMovableProjection(SILValue addr) { @@ -129,7 +120,7 @@ static SingleValueInstruction *isMovableProjection(SILValue addr) { return nullptr; } -bool TempLValueOptPass::tempLValueOpt(CopyAddrInst *copyInst) { +void TempLValueOptPass::tempLValueOpt(CopyAddrInst *copyInst) { // An overview of the algorithm: // @@ -147,11 +138,11 @@ bool TempLValueOptPass::tempLValueOpt(CopyAddrInst *copyInst) { // 'destroy_addr %destination' is inserted before the first use of %temp. if (!copyInst->isTakeOfSrc()) - return false; + return; auto *temporary = dyn_cast(copyInst->getSrc()); if (!temporary) - return false; + return; // Collect all users of the temporary into a set. Also, for simplicity, // require that all users are within a single basic block. @@ -160,7 +151,7 @@ bool TempLValueOptPass::tempLValueOpt(CopyAddrInst *copyInst) { for (Operand *use : temporary->getUses()) { SILInstruction *user = use->getUser(); if (user->getParent() != block) - return false; + return; users.insert(user); } @@ -176,7 +167,7 @@ bool TempLValueOptPass::tempLValueOpt(CopyAddrInst *copyInst) { // Just to be on the safe side, bail if it's not the case (instead of an // assert). if (users.count(projInst)) - return false; + return; projections.insert(projInst); destRootAddr = projInst->getOperand(0); } @@ -185,6 +176,7 @@ bool TempLValueOptPass::tempLValueOpt(CopyAddrInst *copyInst) { SILInstruction *destRootInst = destRootAddr->getDefiningInstruction(); // Iterate over the liferange of the temporary and make some validity checks. + AliasAnalysis *AA = nullptr; SILInstruction *beginOfLiferange = nullptr; bool endOfLiferangeReached = false; for (auto iter = temporary->getIterator(); iter != block->end(); ++iter) { @@ -197,7 +189,7 @@ bool TempLValueOptPass::tempLValueOpt(CopyAddrInst *copyInst) { // Check if the copyInst is the last user of the temporary (beside the // dealloc_stack). if (endOfLiferangeReached) - return false; + return; // Find the first user of the temporary to get a more precise liferange. // It would be too conservative to treat the alloc_stack itself as the @@ -213,8 +205,11 @@ bool TempLValueOptPass::tempLValueOpt(CopyAddrInst *copyInst) { // temporary, we cannot replace all uses of the temporary with the // destination (it would break the def-use dominance rule). if (inst == destRootInst) - return false; + return; + if (!AA) + AA = PM->getAnalysis(getFunction()); + // Check if the destination is not accessed within the liferange of // the temporary. // This is unlikely, because the destination is initialized at the @@ -223,7 +218,7 @@ bool TempLValueOptPass::tempLValueOpt(CopyAddrInst *copyInst) { if (AA->mayReadOrWriteMemory(inst, destination) && // Needed to treat init_existential_addr as not-writing projection. projections.count(inst) == 0) - return false; + return; } } assert(endOfLiferangeReached); @@ -253,18 +248,17 @@ bool TempLValueOptPass::tempLValueOpt(CopyAddrInst *copyInst) { user->eraseFromParent(); break; default: - AA->invalidateInstruction(user); use->set(destination); } } temporary->eraseFromParent(); copyInst->eraseFromParent(); - return true; + invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions); } -bool TempLValueOptPass::combineCopyAndDestroy(CopyAddrInst *copyInst) { +void TempLValueOptPass::combineCopyAndDestroy(CopyAddrInst *copyInst) { if (copyInst->isTakeOfSrc()) - return false; + return; // Find a destroy_addr of the copy's source address. DestroyAddrInst *destroy = nullptr; @@ -274,7 +268,7 @@ bool TempLValueOptPass::combineCopyAndDestroy(CopyAddrInst *copyInst) { } SILBasicBlock *block = copyInst->getParent(); if (!destroy || destroy->getParent() != block) - return false; + return; assert(destroy->getOperand() == copyInst->getSrc()); // Check if the destroy_addr is after the copy_addr and if there are no @@ -290,16 +284,16 @@ bool TempLValueOptPass::combineCopyAndDestroy(CopyAddrInst *copyInst) { for (auto debugInst : debugInsts) { debugInst->eraseFromParent(); } - return true; + invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions); + return; } if (auto *debugInst = dyn_cast(inst)) { if (debugInst->getOperand() == copyInst->getSrc()) debugInsts.push_back(debugInst); } if (inst->mayReadOrWriteMemory()) - return false; + return; } - return false; } } // end anonymous namespace diff --git a/lib/SILOptimizer/Transforms/TempRValueElimination.cpp b/lib/SILOptimizer/Transforms/TempRValueElimination.cpp index 993486709d9..becb48225bb 100644 --- a/lib/SILOptimizer/Transforms/TempRValueElimination.cpp +++ b/lib/SILOptimizer/Transforms/TempRValueElimination.cpp @@ -75,8 +75,6 @@ namespace { /// /// TODO: Check if we still need to handle stores when RLE supports OSSA. class TempRValueOptPass : public SILFunctionTransform { - AliasAnalysis *aa = nullptr; - bool collectLoads(Operand *addressUse, CopyAddrInst *originalCopy, SmallPtrSetImpl &loadInsts); bool collectLoadsFromProjection(SingleValueInstruction *projection, @@ -84,16 +82,17 @@ class TempRValueOptPass : public SILFunctionTransform { SmallPtrSetImpl &loadInsts); SILInstruction *getLastUseWhileSourceIsNotModified( - CopyAddrInst *copyInst, const SmallPtrSetImpl &useInsts); + CopyAddrInst *copyInst, const SmallPtrSetImpl &useInsts, + AliasAnalysis *aa); bool checkTempObjectDestroy(AllocStackInst *tempObj, CopyAddrInst *copyInst); - bool extendAccessScopes(CopyAddrInst *copyInst, SILInstruction *lastUseInst); + bool extendAccessScopes(CopyAddrInst *copyInst, SILInstruction *lastUseInst, + AliasAnalysis *aa); - bool tryOptimizeCopyIntoTemp(CopyAddrInst *copyInst); - std::pair - tryOptimizeStoreIntoTemp(StoreInst *si); + void tryOptimizeCopyIntoTemp(CopyAddrInst *copyInst); + SILBasicBlock::iterator tryOptimizeStoreIntoTemp(StoreInst *si); void run() override; }; @@ -306,7 +305,8 @@ collectLoads(Operand *addressUse, CopyAddrInst *originalCopy, /// of the temporary and look for the last use, which effectively ends the /// lifetime. SILInstruction *TempRValueOptPass::getLastUseWhileSourceIsNotModified( - CopyAddrInst *copyInst, const SmallPtrSetImpl &useInsts) { + CopyAddrInst *copyInst, const SmallPtrSetImpl &useInsts, + AliasAnalysis *aa) { if (useInsts.empty()) return copyInst; unsigned numLoadsFound = 0; @@ -358,7 +358,7 @@ SILInstruction *TempRValueOptPass::getLastUseWhileSourceIsNotModified( /// We must not replace %temp with %a after the end_access. Instead we try to /// move the end_access after "use %temp". bool TempRValueOptPass::extendAccessScopes( - CopyAddrInst *copyInst, SILInstruction *lastUseInst) { + CopyAddrInst *copyInst, SILInstruction *lastUseInst, AliasAnalysis *aa) { SILValue copySrc = copyInst->getSrc(); EndAccessInst *endAccessToMove = nullptr; @@ -460,13 +460,13 @@ bool TempRValueOptPass::checkTempObjectDestroy( } /// Tries to perform the temporary rvalue copy elimination for \p copyInst -bool TempRValueOptPass::tryOptimizeCopyIntoTemp(CopyAddrInst *copyInst) { +void TempRValueOptPass::tryOptimizeCopyIntoTemp(CopyAddrInst *copyInst) { if (!copyInst->isInitializationOfDest()) - return false; + return; auto *tempObj = dyn_cast(copyInst->getDest()); if (!tempObj) - return false; + return; bool isOSSA = copyInst->getFunction()->hasOwnership(); @@ -502,21 +502,23 @@ bool TempRValueOptPass::tryOptimizeCopyIntoTemp(CopyAddrInst *copyInst) { // Otherwise we would risk of inserting the destroy too early. // So we just treat the destroy_addr as any other use of tempObj. if (user->getParent() != copyInst->getParent()) - return false; + return; loadInsts.insert(user); } continue; } if (!collectLoads(useOper, copyInst, loadInsts)) - return false; + return; } + AliasAnalysis *aa = getPassManager()->getAnalysis(getFunction()); + // Check if the source is modified within the lifetime of the temporary. - SILInstruction *lastLoadInst = getLastUseWhileSourceIsNotModified(copyInst, - loadInsts); + SILInstruction *lastLoadInst = + getLastUseWhileSourceIsNotModified(copyInst, loadInsts, aa); if (!lastLoadInst) - return false; + return; // We cannot insert the destroy of copySrc after lastLoadInst if copySrc is // re-initialized by exactly this instruction. @@ -527,13 +529,13 @@ bool TempRValueOptPass::tryOptimizeCopyIntoTemp(CopyAddrInst *copyInst) { if (needToInsertDestroy && lastLoadInst != copyInst && !isa(lastLoadInst) && aa->mayWriteToMemory(lastLoadInst, copySrc)) - return false; + return; if (!isOSSA && !checkTempObjectDestroy(tempObj, copyInst)) - return false; + return; - if (!extendAccessScopes(copyInst, lastLoadInst)) - return false; + if (!extendAccessScopes(copyInst, lastLoadInst, aa)) + return; LLVM_DEBUG(llvm::dbgs() << " Success: replace temp" << *tempObj); @@ -556,7 +558,6 @@ bool TempRValueOptPass::tryOptimizeCopyIntoTemp(CopyAddrInst *copyInst) { while (!tempObj->use_empty()) { Operand *use = *tempObj->use_begin(); SILInstruction *user = use->getUser(); - aa->invalidateInstruction(user); switch (user->getKind()) { case SILInstructionKind::DestroyAddrInst: @@ -591,25 +592,25 @@ bool TempRValueOptPass::tryOptimizeCopyIntoTemp(CopyAddrInst *copyInst) { } tempObj->eraseFromParent(); - return true; + invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions); } -std::pair +SILBasicBlock::iterator TempRValueOptPass::tryOptimizeStoreIntoTemp(StoreInst *si) { // If our store is an assign, bail. if (si->getOwnershipQualifier() == StoreOwnershipQualifier::Assign) - return {std::next(si->getIterator()), false}; + return std::next(si->getIterator()); auto *tempObj = dyn_cast(si->getDest()); if (!tempObj) { - return {std::next(si->getIterator()), false}; + return std::next(si->getIterator()); } // If our tempObj has a dynamic lifetime (meaning it is conditionally // initialized, conditionally taken, etc), we can not convert its uses to SSA // while eliminating it simply. So bail. if (tempObj->hasDynamicLifetime()) { - return {std::next(si->getIterator()), false}; + return std::next(si->getIterator()); } // Scan all uses of the temporary storage (tempObj) to verify they all refer @@ -632,14 +633,14 @@ TempRValueOptPass::tryOptimizeStoreIntoTemp(StoreInst *si) { break; case SILInstructionKind::CopyAddrInst: if (cast(user)->getDest() == tempObj) - return {std::next(si->getIterator()), false}; + return std::next(si->getIterator()); break; case SILInstructionKind::MarkDependenceInst: if (cast(user)->getValue() == tempObj) - return {std::next(si->getIterator()), false}; + return std::next(si->getIterator()); break; default: - return {std::next(si->getIterator()), false}; + return std::next(si->getIterator()); } } @@ -734,7 +735,8 @@ TempRValueOptPass::tryOptimizeStoreIntoTemp(StoreInst *si) { auto nextIter = std::next(si->getIterator()); si->eraseFromParent(); tempObj->eraseFromParent(); - return {nextIter, true}; + invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions); + return nextIter; } //===----------------------------------------------------------------------===// @@ -746,9 +748,6 @@ void TempRValueOptPass::run() { LLVM_DEBUG(llvm::dbgs() << "Copy Peephole in Func " << getFunction()->getName() << "\n"); - aa = getPassManager()->getAnalysis(); - bool changed = false; - // Find all copy_addr instructions. llvm::SmallSetVector deadCopies; for (auto &block : *getFunction()) { @@ -759,13 +758,12 @@ void TempRValueOptPass::run() { if (auto *copyInst = dyn_cast(&*ii)) { // In case of success, this may delete instructions, but not the // CopyInst itself. - changed |= tryOptimizeCopyIntoTemp(copyInst); + tryOptimizeCopyIntoTemp(copyInst); // Remove identity copies which either directly result from successfully // calling tryOptimizeCopyIntoTemp or was created by an earlier // iteration, where another copy_addr copied the temporary back to the // source location. if (copyInst->getSrc() == copyInst->getDest()) { - changed = true; deadCopies.insert(copyInst); } ++ii; @@ -773,9 +771,7 @@ void TempRValueOptPass::run() { } if (auto *si = dyn_cast(&*ii)) { - bool madeSingleChange; - std::tie(ii, madeSingleChange) = tryOptimizeStoreIntoTemp(si); - changed |= madeSingleChange; + ii = tryOptimizeStoreIntoTemp(si); continue; } @@ -794,7 +790,6 @@ void TempRValueOptPass::run() { DeadEndBlocks deBlocks(getFunction()); for (auto *deadCopy : deadCopies) { - assert(changed); auto *srcInst = deadCopy->getSrc()->getDefiningInstruction(); deadCopy->eraseFromParent(); // Simplify any access scope markers that were only used by the dead @@ -803,7 +798,7 @@ void TempRValueOptPass::run() { simplifyAndReplaceAllSimplifiedUsesAndErase(srcInst, callbacks, &deBlocks); } } - if (changed) { + if (!deadCopies.empty()) { invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions); } } diff --git a/lib/SILOptimizer/UtilityPasses/AADumper.cpp b/lib/SILOptimizer/UtilityPasses/AADumper.cpp index 6da3331d837..6fd87494740 100644 --- a/lib/SILOptimizer/UtilityPasses/AADumper.cpp +++ b/lib/SILOptimizer/UtilityPasses/AADumper.cpp @@ -64,7 +64,7 @@ class SILAADumper : public SILModuleTransform { if (!gatherValues(Fn, Values)) continue; - AliasAnalysis *AA = PM->getAnalysis(); + AliasAnalysis *AA = PM->getAnalysis(&Fn); // A cache llvm::DenseMap Results; diff --git a/lib/SILOptimizer/UtilityPasses/EpilogueRetainReleaseMatcherDumper.cpp b/lib/SILOptimizer/UtilityPasses/EpilogueRetainReleaseMatcherDumper.cpp index c5bba2cd4a3..9abaf9b53a3 100644 --- a/lib/SILOptimizer/UtilityPasses/EpilogueRetainReleaseMatcherDumper.cpp +++ b/lib/SILOptimizer/UtilityPasses/EpilogueRetainReleaseMatcherDumper.cpp @@ -39,13 +39,14 @@ namespace { class SILEpilogueRetainReleaseMatcherDumper : public SILModuleTransform { void run() override { - auto *AA = PM->getAnalysis(); auto *RCIA = getAnalysis(); for (auto &Fn: *getModule()) { // Function is not definition. if (!Fn.isDefinition()) continue; + auto *AA = PM->getAnalysis(&Fn); + llvm::outs() << "START: sil @" << Fn.getName() << "\n"; // Handle @owned return value. diff --git a/lib/SILOptimizer/UtilityPasses/MemBehaviorDumper.cpp b/lib/SILOptimizer/UtilityPasses/MemBehaviorDumper.cpp index 7750ccd5403..6bd67c6f88c 100644 --- a/lib/SILOptimizer/UtilityPasses/MemBehaviorDumper.cpp +++ b/lib/SILOptimizer/UtilityPasses/MemBehaviorDumper.cpp @@ -83,7 +83,7 @@ class MemBehaviorDumper : public SILModuleTransform { if (!gatherValues(Fn, Values)) continue; - AliasAnalysis *AA = PM->getAnalysis(); + AliasAnalysis *AA = PM->getAnalysis(&Fn); unsigned PairCount = 0; for (auto &BB : Fn) {