mirror of
https://github.com/RPCS3/llvm.git
synced 2024-12-25 05:25:53 +00:00
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:
parent
6dbe7b1e31
commit
8db585afaa
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user