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:
Nick Lewycky
2011-11-20 19:37:06 +00:00
parent 173862e546
commit 7912ef97ff
3 changed files with 132 additions and 128 deletions

View File

@@ -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.
}

View File

@@ -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;