diff options
-rw-r--r-- | include/llvm/Analysis/CaptureTracking.h | 147 | ||||
-rw-r--r-- | lib/Analysis/CaptureTracking.cpp | 109 | ||||
-rw-r--r-- | lib/Analysis/MemoryDependenceAnalysis.cpp | 4 |
3 files changed, 132 insertions, 128 deletions
diff --git a/include/llvm/Analysis/CaptureTracking.h b/include/llvm/Analysis/CaptureTracking.h index b033f14cec..b49646b2a2 100644 --- a/include/llvm/Analysis/CaptureTracking.h +++ b/include/llvm/Analysis/CaptureTracking.h @@ -33,132 +33,31 @@ namespace llvm { bool ReturnCaptures, bool StoreCaptures); + /// This callback is used in conjunction with PointerMayBeCaptured. In + /// addition to the interface here, you'll need to provide your own getters + /// to see whether anything was captured. + struct CaptureTracker { + /// tooManyUses - The depth of traversal has breached a limit. There may be + /// capturing instructions that will not be passed into captured(). + virtual void tooManyUses() = 0; + + /// shouldExplore - This is the use of a value derived from the pointer. + /// To prune the search (ie., assume that none of its users could possibly + /// capture) return false. To search it, return true. + /// + /// U->getUser() is always an Instruction. + virtual bool shouldExplore(Use *U) = 0; + + /// captured - The instruction I captured the pointer. Return true to + /// stop the traversal or false to continue looking for more capturing + /// instructions. + virtual bool captured(Instruction *I) = 0; + }; + /// PointerMayBeCaptured - Visit the value and the values derived from it and /// find values which appear to be capturing the pointer value. This feeds - /// results into and is controlled by the templated CaptureTracker object: - /// - /// struct YourCaptureTracker { - /// /// tooManyUses - The depth of traversal has breached a limit. - /// /// The tracker should conservatively assume that the value is captured. - /// void tooManyUses(); - /// - /// /// shouldExplore - This is the use of a value derived from the pointer. - /// /// Return false to prune the search (ie., assume that none of its users - /// /// could possibly capture) return false. To search it, return true. - /// /// - /// /// Also, U->getUser() is guaranteed to be an Instruction. - /// bool shouldExplore(Use *U); - /// - /// /// captured - The instruction I captured the pointer. Return true to - /// /// stop the traversal or false to continue looking for more capturing - /// /// instructions. - /// bool captured(Instruction *I); - /// - /// /// Provide your own getters for the state. - /// }; - template<typename CaptureTracker> - void PointerMayBeCaptured(const Value *V, CaptureTracker &Tracker); + /// results into and is controlled by the CaptureTracker object. + void PointerMayBeCaptured(const Value *V, CaptureTracker *Tracker); } // end namespace llvm -template<typename CaptureTracker> -void llvm::PointerMayBeCaptured(const llvm::Value *V, CaptureTracker &Tracker) { - assert(V->getType()->isPointerTy() && "Capture is for pointers only!"); - SmallVector<Use*, 20> Worklist; - SmallSet<Use*, 20> Visited; - int Count = 0; - - for (Value::const_use_iterator UI = V->use_begin(), UE = V->use_end(); - UI != UE; ++UI) { - // If there are lots of uses, conservatively say that the value - // is captured to avoid taking too much compile time. - if (Count++ >= 20) - return Tracker.tooManyUses(); - - Use *U = &UI.getUse(); - if (!Tracker.shouldExplore(U)) continue; - Visited.insert(U); - Worklist.push_back(U); - } - - while (!Worklist.empty()) { - Use *U = Worklist.pop_back_val(); - Instruction *I = cast<Instruction>(U->getUser()); - V = U->get(); - - switch (I->getOpcode()) { - case Instruction::Call: - case Instruction::Invoke: { - CallSite CS(I); - // Not captured if the callee is readonly, doesn't return a copy through - // its return value and doesn't unwind (a readonly function can leak bits - // by throwing an exception or not depending on the input value). - if (CS.onlyReadsMemory() && CS.doesNotThrow() && I->getType()->isVoidTy()) - break; - - // Not captured if only passed via 'nocapture' arguments. Note that - // calling a function pointer does not in itself cause the pointer to - // be captured. This is a subtle point considering that (for example) - // the callee might return its own address. It is analogous to saying - // that loading a value from a pointer does not cause the pointer to be - // captured, even though the loaded value might be the pointer itself - // (think of self-referential objects). - CallSite::arg_iterator B = CS.arg_begin(), E = CS.arg_end(); - for (CallSite::arg_iterator A = B; A != E; ++A) - if (A->get() == V && !CS.doesNotCapture(A - B)) - // The parameter is not marked 'nocapture' - captured. - if (Tracker.captured(I)) - return; - break; - } - case Instruction::Load: - // Loading from a pointer does not cause it to be captured. - break; - case Instruction::VAArg: - // "va-arg" from a pointer does not cause it to be captured. - break; - case Instruction::Store: - if (V == I->getOperand(0)) - // Stored the pointer - conservatively assume it may be captured. - if (Tracker.captured(I)) - return; - // Storing to the pointee does not cause the pointer to be captured. - break; - case Instruction::BitCast: - case Instruction::GetElementPtr: - case Instruction::PHI: - case Instruction::Select: - // The original value is not captured via this if the new value isn't. - for (Instruction::use_iterator UI = I->use_begin(), UE = I->use_end(); - UI != UE; ++UI) { - Use *U = &UI.getUse(); - if (Visited.insert(U)) - if (Tracker.shouldExplore(U)) - Worklist.push_back(U); - } - break; - case Instruction::ICmp: - // Don't count comparisons of a no-alias return value against null as - // captures. This allows us to ignore comparisons of malloc results - // with null, for example. - if (isNoAliasCall(V->stripPointerCasts())) - if (ConstantPointerNull *CPN = - dyn_cast<ConstantPointerNull>(I->getOperand(1))) - if (CPN->getType()->getAddressSpace() == 0) - break; - // Otherwise, be conservative. There are crazy ways to capture pointers - // using comparisons. - if (Tracker.captured(I)) - return; - break; - default: - // Something else - be conservative and say it is captured. - if (Tracker.captured(I)) - return; - break; - } - } - - // All uses examined. -} - #endif diff --git a/lib/Analysis/CaptureTracking.cpp b/lib/Analysis/CaptureTracking.cpp index a84dafb5fb..9be00971dc 100644 --- a/lib/Analysis/CaptureTracking.cpp +++ b/lib/Analysis/CaptureTracking.cpp @@ -20,7 +20,7 @@ using namespace llvm; namespace { - struct SimpleCaptureTracker { + struct SimpleCaptureTracker : public CaptureTracker { explicit SimpleCaptureTracker(bool ReturnCaptures) : ReturnCaptures(ReturnCaptures), Captured(false) {} @@ -58,6 +58,111 @@ bool llvm::PointerMayBeCaptured(const Value *V, (void)StoreCaptures; SimpleCaptureTracker SCT(ReturnCaptures); - PointerMayBeCaptured(V, SCT); + PointerMayBeCaptured(V, &SCT); return SCT.Captured; } + +/// TODO: Write a new FunctionPass AliasAnalysis so that it can keep +/// a cache. Then we can move the code from BasicAliasAnalysis into +/// that path, and remove this threshold. +static int const Threshold = 20; + +void llvm::PointerMayBeCaptured(const Value *V, CaptureTracker *Tracker) { + assert(V->getType()->isPointerTy() && "Capture is for pointers only!"); + SmallVector<Use*, Threshold> Worklist; + SmallSet<Use*, Threshold> Visited; + int Count = 0; + + for (Value::const_use_iterator UI = V->use_begin(), UE = V->use_end(); + UI != UE; ++UI) { + // If there are lots of uses, conservatively say that the value + // is captured to avoid taking too much compile time. + if (Count++ >= Threshold) + return Tracker->tooManyUses(); + + Use *U = &UI.getUse(); + if (!Tracker->shouldExplore(U)) continue; + Visited.insert(U); + Worklist.push_back(U); + } + + while (!Worklist.empty()) { + Use *U = Worklist.pop_back_val(); + Instruction *I = cast<Instruction>(U->getUser()); + V = U->get(); + + switch (I->getOpcode()) { + case Instruction::Call: + case Instruction::Invoke: { + CallSite CS(I); + // Not captured if the callee is readonly, doesn't return a copy through + // its return value and doesn't unwind (a readonly function can leak bits + // by throwing an exception or not depending on the input value). + if (CS.onlyReadsMemory() && CS.doesNotThrow() && I->getType()->isVoidTy()) + break; + + // Not captured if only passed via 'nocapture' arguments. Note that + // calling a function pointer does not in itself cause the pointer to + // be captured. This is a subtle point considering that (for example) + // the callee might return its own address. It is analogous to saying + // that loading a value from a pointer does not cause the pointer to be + // captured, even though the loaded value might be the pointer itself + // (think of self-referential objects). + CallSite::arg_iterator B = CS.arg_begin(), E = CS.arg_end(); + for (CallSite::arg_iterator A = B; A != E; ++A) + if (A->get() == V && !CS.doesNotCapture(A - B)) + // The parameter is not marked 'nocapture' - captured. + if (Tracker->captured(I)) + return; + break; + } + case Instruction::Load: + // Loading from a pointer does not cause it to be captured. + break; + case Instruction::VAArg: + // "va-arg" from a pointer does not cause it to be captured. + break; + case Instruction::Store: + if (V == I->getOperand(0)) + // Stored the pointer - conservatively assume it may be captured. + if (Tracker->captured(I)) + return; + // Storing to the pointee does not cause the pointer to be captured. + break; + case Instruction::BitCast: + case Instruction::GetElementPtr: + case Instruction::PHI: + case Instruction::Select: + // The original value is not captured via this if the new value isn't. + for (Instruction::use_iterator UI = I->use_begin(), UE = I->use_end(); + UI != UE; ++UI) { + Use *U = &UI.getUse(); + if (Visited.insert(U)) + if (Tracker->shouldExplore(U)) + Worklist.push_back(U); + } + break; + case Instruction::ICmp: + // Don't count comparisons of a no-alias return value against null as + // captures. This allows us to ignore comparisons of malloc results + // with null, for example. + if (isNoAliasCall(V->stripPointerCasts())) + if (ConstantPointerNull *CPN = + dyn_cast<ConstantPointerNull>(I->getOperand(1))) + if (CPN->getType()->getAddressSpace() == 0) + break; + // Otherwise, be conservative. There are crazy ways to capture pointers + // using comparisons. + if (Tracker->captured(I)) + return; + break; + default: + // Something else - be conservative and say it is captured. + if (Tracker->captured(I)) + return; + break; + } + } + + // All uses examined. +} diff --git a/lib/Analysis/MemoryDependenceAnalysis.cpp b/lib/Analysis/MemoryDependenceAnalysis.cpp index e779bf2b99..128c7f93a4 100644 --- a/lib/Analysis/MemoryDependenceAnalysis.cpp +++ b/lib/Analysis/MemoryDependenceAnalysis.cpp @@ -336,7 +336,7 @@ getLoadLoadClobberFullWidthSize(const Value *MemLocBase, int64_t MemLocOffs, namespace { /// Only find pointer captures which happen before the given instruction. Uses /// the dominator tree to determine whether one instruction is before another. - struct CapturesBefore { + struct CapturesBefore : public CaptureTracker { CapturesBefore(const Instruction *I, DominatorTree *DT) : BeforeHere(I), DT(DT), Captured(false) {} @@ -381,7 +381,7 @@ MemoryDependenceAnalysis::getModRefInfo(const Instruction *Inst, if (!CS.getInstruction()) return AliasAnalysis::ModRef; CapturesBefore CB(Inst, DT); - llvm::PointerMayBeCaptured(Object, CB); + llvm::PointerMayBeCaptured(Object, &CB); if (isa<Constant>(Object) || CS.getInstruction() == Object || CB.Captured) return AliasAnalysis::ModRef; |