Move the CapturesBefore tracker from AA into CaptureTracking

There were two generally-useful CaptureTracker classes defined in LLVM: the
simple tracker defined in CaptureTracking (and made available via the
PointerMayBeCaptured utility function), and the CapturesBefore tracker
available only inside of AA. This change moves the CapturesBefore tracker into
CaptureTracking, generalizes it slightly (by adding a ReturnCaptures
parameter), and makes it generally available via a PointerMayBeCapturedBefore
utility function.

This logic will be needed, for example, to perform noalias function parameter
attribute inference.

No functionality change intended.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@213519 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Hal Finkel 2014-07-21 13:15:48 +00:00
parent 6dbe7b1e31
commit 8db585afaa
3 changed files with 96 additions and 50 deletions

View File

@ -18,6 +18,8 @@ namespace llvm {
class Value;
class Use;
class Instruction;
class DominatorTree;
/// PointerMayBeCaptured - Return true if this pointer value may be captured
/// by the enclosing function (which is required to exist). This routine can
@ -30,6 +32,19 @@ namespace llvm {
bool ReturnCaptures,
bool StoreCaptures);
/// 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
/// instruction are considered. 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.
bool PointerMayBeCapturedBefore(const Value *V, bool ReturnCaptures,
bool StoreCaptures, const Instruction *I,
DominatorTree *DT);
/// 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.

View File

@ -388,53 +388,6 @@ AliasAnalysis::getModRefInfo(const AtomicRMWInst *RMW, const Location &Loc) {
return ModRef;
}
namespace {
/// 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
/// as the given instruction and the use.
struct CapturesBefore : public CaptureTracker {
CapturesBefore(const Instruction *I, DominatorTree *DT)
: BeforeHere(I), DT(DT), Captured(false) {}
void tooManyUses() override { Captured = true; }
bool shouldExplore(const Use *U) override {
Instruction *I = cast<Instruction>(U->getUser());
BasicBlock *BB = I->getParent();
// We explore this usage only if the usage can reach "BeforeHere".
// If use is not reachable from entry, there is no need to explore.
if (BeforeHere != I && !DT->isReachableFromEntry(BB))
return false;
// If the value is defined in the same basic block as use and BeforeHere,
// there is no need to explore the use if BeforeHere dominates use.
// Check whether there is a path from I to BeforeHere.
if (BeforeHere != I && DT->dominates(BeforeHere, I) &&
!isPotentiallyReachable(I, BeforeHere, DT))
return false;
return true;
}
bool captured(const Use *U) override {
Instruction *I = cast<Instruction>(U->getUser());
BasicBlock *BB = I->getParent();
// Same logic as in shouldExplore.
if (BeforeHere != I && !DT->isReachableFromEntry(BB))
return false;
if (BeforeHere != I && DT->dominates(BeforeHere, I) &&
!isPotentiallyReachable(I, BeforeHere, DT))
return false;
Captured = true;
return true;
}
const Instruction *BeforeHere;
DominatorTree *DT;
bool Captured;
};
}
// FIXME: this is really just shoring-up a deficiency in alias analysis.
// BasicAA isn't willing to spend linear time determining whether an alloca
// was captured before or after this particular call, while we are. However,
@ -454,9 +407,8 @@ AliasAnalysis::callCapturesBefore(const Instruction *I,
if (!CS.getInstruction() || CS.getInstruction() == Object)
return AliasAnalysis::ModRef;
CapturesBefore CB(I, DT);
llvm::PointerMayBeCaptured(Object, &CB);
if (CB.Captured)
if (llvm::PointerMayBeCapturedBefore(Object, /* ReturnCaptures */ true,
/* StoreCaptures */ true, I, DT))
return AliasAnalysis::ModRef;
unsigned ArgNo = 0;

View File

@ -20,8 +20,10 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/CaptureTracking.h"
#include "llvm/Analysis/CFG.h"
#include "llvm/IR/CallSite.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Instructions.h"
using namespace llvm;
@ -49,6 +51,57 @@ namespace {
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
/// as the given instruction and the use.
struct CapturesBefore : public CaptureTracker {
CapturesBefore(bool ReturnCaptures, const Instruction *I, DominatorTree *DT)
: BeforeHere(I), DT(DT), ReturnCaptures(ReturnCaptures),
Captured(false) {}
void tooManyUses() override { Captured = true; }
bool shouldExplore(const Use *U) override {
Instruction *I = cast<Instruction>(U->getUser());
BasicBlock *BB = I->getParent();
// We explore this usage only if the usage can reach "BeforeHere".
// If use is not reachable from entry, there is no need to explore.
if (BeforeHere != I && !DT->isReachableFromEntry(BB))
return false;
// If the value is defined in the same basic block as use and BeforeHere,
// there is no need to explore the use if BeforeHere dominates use.
// Check whether there is a path from I to BeforeHere.
if (BeforeHere != I && DT->dominates(BeforeHere, I) &&
!isPotentiallyReachable(I, BeforeHere, DT))
return false;
return true;
}
bool captured(const Use *U) override {
if (isa<ReturnInst>(U->getUser()) && !ReturnCaptures)
return false;
Instruction *I = cast<Instruction>(U->getUser());
BasicBlock *BB = I->getParent();
// Same logic as in shouldExplore.
if (BeforeHere != I && !DT->isReachableFromEntry(BB))
return false;
if (BeforeHere != I && DT->dominates(BeforeHere, I) &&
!isPotentiallyReachable(I, BeforeHere, DT))
return false;
Captured = true;
return true;
}
const Instruction *BeforeHere;
DominatorTree *DT;
bool ReturnCaptures;
bool Captured;
};
}
/// PointerMayBeCaptured - Return true if this pointer value may be captured
@ -74,6 +127,32 @@ bool llvm::PointerMayBeCaptured(const Value *V,
return SCT.Captured;
}
/// 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
/// instruction are considered. 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.
bool llvm::PointerMayBeCapturedBefore(const Value *V, bool ReturnCaptures,
bool StoreCaptures, const Instruction *I,
DominatorTree *DT) {
assert(!isa<GlobalValue>(V) &&
"It doesn't make sense to ask whether a global is captured.");
if (!DT)
return PointerMayBeCaptured(V, ReturnCaptures, StoreCaptures);
// TODO: See comment in PointerMayBeCaptured regarding what could be done
// with StoreCaptures.
CapturesBefore CB(ReturnCaptures, I, DT);
PointerMayBeCaptured(V, &CB);
return CB.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.