mirror of
https://github.com/RPCSX/llvm.git
synced 2024-11-26 05:00:26 +00:00
Less template, more virtual! Refactoring suggested by Chris in code review.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@145014 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
173862e546
commit
7912ef97ff
@ -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
|
||||
|
@ -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.
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user