Index: include/llvm/Analysis/CaptureTracking.h =================================================================== --- include/llvm/Analysis/CaptureTracking.h +++ include/llvm/Analysis/CaptureTracking.h @@ -21,6 +21,7 @@ class Instruction; class DominatorTree; class OrderedBasicBlock; + class AAResults; /// PointerMayBeCaptured - Return true if this pointer value may be captured /// by the enclosing function (which is required to exist). This routine can @@ -33,6 +34,17 @@ bool ReturnCaptures, bool StoreCaptures); + /// PointerMayBeCaptured - Return true if this pointer value may be captured + /// by the enclosing function (which is required to exist). This routine can + /// be expensive, so consider caching the results. The boolean ReturnCaptures + /// specifies whether returning the value (or part of it) from the function + /// counts as capturing it or not. The boolean StoreCaptures specified + /// whether storing the value (or part of it) into memory anywhere + /// automatically counts as capturing it or not. For the latter to have + /// effect, Alias Analysis results are required. + bool PointerMayBeCaptured(const Value *V, bool ReturnCaptures, + bool StoreCaptures, AAResults *AA); + /// PointerMayBeCapturedBefore - Return true if this pointer value may be /// captured by the enclosing function (which is required to exist). If a /// DominatorTree is provided, only captures which happen before the given Index: include/llvm/Transforms/Utils/LoopUtils.h =================================================================== --- include/llvm/Transforms/Utils/LoopUtils.h +++ include/llvm/Transforms/Utils/LoopUtils.h @@ -303,7 +303,7 @@ const SCEV *Expr = nullptr); /// Returns true if \p Phi is a floating point induction in the loop \p L. - /// If \p Phi is an induction, the induction descriptor \p D will contain + /// If \p Phi is an induction, the induction descriptor \p D will contain /// the data describing this induction. static bool isFPInductionPHI(PHINode *Phi, const Loop* L, ScalarEvolution *SE, InductionDescriptor &D); @@ -432,7 +432,8 @@ SmallVectorImpl &, PredIteratorCache &, LoopInfo *, DominatorTree *, const TargetLibraryInfo *, - Loop *, AliasSetTracker *, LoopSafetyInfo *); + AliasAnalysis *AA, Loop *, AliasSetTracker *, + LoopSafetyInfo *); /// \brief Computes safety information for a loop /// checks loop body & header for the possibility of may throw Index: lib/Analysis/CaptureTracking.cpp =================================================================== --- lib/Analysis/CaptureTracking.cpp +++ lib/Analysis/CaptureTracking.cpp @@ -54,6 +54,70 @@ bool Captured; }; + struct OptimisticCaptureTracker : public CaptureTracker { + + OptimisticCaptureTracker(bool ReturnCaptures, bool StoreCaptures, + AliasAnalysis *AA) + : ReturnCaptures(ReturnCaptures), StoreCaptures(StoreCaptures), AA(AA), + Captured(false) {} + + void tooManyUses() override { Captured = true; } + + bool storeCaptures(const StoreInst *S) { + if (StoreCaptures) + return true; + + if (!AA) + return true; + + const Function *F = S->getFunction(); + const Value *Ptr = S->getPointerOperand(); + + // Check if the pointer is stored to a function argument. + for (auto &Arg : F->getArgumentList()) { + if (!isa(Arg.getType())) + continue; + + if (auto *V = dyn_cast(&Arg)) { + if (!AA->isNoAlias(Ptr, V)) { + return true; + } + } + } + + // Check if the pointer is stored to a global. + for (auto &Global : F->getParent()->globals()) { + if (auto *V = dyn_cast(&Global)) { + if (!AA->isNoAlias(Ptr, V)) { + return true; + } + } + } + + return false; + } + + bool captured(const Use *U) override { + + if (isa(U->getUser()) && !ReturnCaptures) + return false; + + if (auto *S = dyn_cast(U->getUser())) + if (!storeCaptures(S)) + return false; + + Captured = true; + return true; + } + + bool ReturnCaptures; + bool StoreCaptures; + + AliasAnalysis *AA; + + bool Captured; + }; + /// Only find pointer captures which happen before the given instruction. Uses /// the dominator tree to determine whether one instruction is before another. /// Only support the case where the Value is defined in the same basic block @@ -165,11 +229,36 @@ // to determine whether this store is not actually an escape point. // In that case, BasicAliasAnalysis should be updated as well to // take advantage of this. - (void)StoreCaptures; + //(void)StoreCaptures; + + // TODO: We can essentially the SimpleCaptureTracker completely with the + // Optimistic one and possibly reuse the name? + + // SimpleCaptureTracker SCT(ReturnCaptures); + // PointerMayBeCaptured(V, &SCT); + // return SCT.Captured; + + OptimisticCaptureTracker OCT(ReturnCaptures, StoreCaptures, nullptr); + PointerMayBeCaptured(V, &OCT); + return OCT.Captured; +} + +/// PointerMayBeCaptured - Return true if this pointer value may be captured by +/// the enclosing function (which is required to exist). This routine can be +/// expensive, so consider caching the results. The boolean ReturnCaptures +/// specifies whether returning the value (or part of it) from the function +/// counts as capturing it or not. The boolean StoreCaptures specified whether +/// storing the value (or part of it) into memory anywhere automatically counts +/// as capturing it or not. For the latter to have effect, Alias Analysis +/// results are required. +bool llvm::PointerMayBeCaptured(const Value *V, bool ReturnCaptures, + bool StoreCaptures, AliasAnalysis *AA) { + assert(!isa(V) && + "It doesn't make sense to ask whether a global is captured."); - SimpleCaptureTracker SCT(ReturnCaptures); - PointerMayBeCaptured(V, &SCT); - return SCT.Captured; + OptimisticCaptureTracker OCT(ReturnCaptures, StoreCaptures, AA); + PointerMayBeCaptured(V, &OCT); + return OCT.Captured; } /// PointerMayBeCapturedBefore - Return true if this pointer value may be Index: lib/Transforms/Scalar/DeadStoreElimination.cpp =================================================================== --- lib/Transforms/Scalar/DeadStoreElimination.cpp +++ lib/Transforms/Scalar/DeadStoreElimination.cpp @@ -1089,8 +1089,9 @@ // where the allocation doesn't escape before the last // throwing instruction; PointerMayBeCaptured // reasonably fast approximation. - IsStoreDeadOnUnwind = isAllocLikeFn(Underlying, TLI) && - !PointerMayBeCaptured(Underlying, false, true); + IsStoreDeadOnUnwind = + isAllocLikeFn(Underlying, TLI) && + !PointerMayBeCaptured(Underlying, false, false, AA); } if (!IsStoreDeadOnUnwind) break; Index: lib/Transforms/Scalar/LICM.cpp =================================================================== --- lib/Transforms/Scalar/LICM.cpp +++ lib/Transforms/Scalar/LICM.cpp @@ -250,8 +250,9 @@ // Loop over all of the alias sets in the tracker object. for (AliasSet &AS : *CurAST) - Changed |= promoteLoopAccessesToScalars( - AS, ExitBlocks, InsertPts, PIC, LI, DT, TLI, L, CurAST, &SafetyInfo); + Changed |= + promoteLoopAccessesToScalars(AS, ExitBlocks, InsertPts, PIC, LI, DT, + TLI, AA, L, CurAST, &SafetyInfo); // Once we have promoted values across the loop body we have to recursively // reform LCSSA as any nested loop may now have values defined within the @@ -843,7 +844,8 @@ AliasSet &AS, SmallVectorImpl &ExitBlocks, SmallVectorImpl &InsertPts, PredIteratorCache &PIC, LoopInfo *LI, DominatorTree *DT, const TargetLibraryInfo *TLI, - Loop *CurLoop, AliasSetTracker *CurAST, LoopSafetyInfo *SafetyInfo) { + AliasAnalysis *AA, Loop *CurLoop, AliasSetTracker *CurAST, + LoopSafetyInfo *SafetyInfo) { // Verify inputs. assert(LI != nullptr && DT != nullptr && CurLoop != nullptr && CurAST != nullptr && SafetyInfo != nullptr && @@ -1007,8 +1009,8 @@ // paths which originally didn't have them without violating the memory // model. Value *Object = GetUnderlyingObject(SomePtr, MDL); - PromotionIsLegal = - isAllocLikeFn(Object, TLI) && !PointerMayBeCaptured(Object, true, true); + PromotionIsLegal = isAllocLikeFn(Object, TLI) && + !PointerMayBeCaptured(Object, true, false, AA); } if (!PromotionIsLegal) return Changed;