#include "llvm/Analysis/GlobalsModRef.h"
#include "llvm/ADT/SCCIterator.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/MemoryBuiltins.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Support/CommandLine.h"
using namespace llvm;
#define DEBUG_TYPE "globalsmodref-aa"
STATISTIC(NumNonAddrTakenGlobalVars,
"Number of global vars without address taken");
STATISTIC(NumNonAddrTakenFunctions,"Number of functions without address taken");
STATISTIC(NumNoMemFunctions, "Number of functions that do not access memory");
STATISTIC(NumReadMemFunctions, "Number of functions that only read memory");
STATISTIC(NumIndirectGlobalVars, "Number of indirect global objects");
static cl::opt<bool> EnableUnsafeGlobalsModRefAliasResults(
"enable-unsafe-globalsmodref-alias-results", cl::init(false), cl::Hidden);
class GlobalsAAResult::FunctionInfo {
typedef SmallDenseMap<const GlobalValue *, ModRefInfo, 16> GlobalInfoMapType;
struct LLVM_ALIGNAS(8) AlignedMap {
AlignedMap() {}
AlignedMap(const AlignedMap &Arg) : Map(Arg.Map) {}
GlobalInfoMapType Map;
};
struct AlignedMapPointerTraits {
static inline void *getAsVoidPointer(AlignedMap *P) { return P; }
static inline AlignedMap *getFromVoidPointer(void *P) {
return (AlignedMap *)P;
}
enum { NumLowBitsAvailable = 3 };
static_assert(AlignOf<AlignedMap>::Alignment >= (1 << NumLowBitsAvailable),
"AlignedMap insufficiently aligned to have enough low bits.");
};
enum { MayReadAnyGlobal = 4 };
static_assert((MayReadAnyGlobal & MRI_ModRef) == 0,
"ModRef and the MayReadAnyGlobal flag bits overlap.");
static_assert(((MayReadAnyGlobal | MRI_ModRef) >>
AlignedMapPointerTraits::NumLowBitsAvailable) == 0,
"Insufficient low bits to store our flag and ModRef info.");
public:
FunctionInfo() : Info() {}
~FunctionInfo() {
delete Info.getPointer();
}
FunctionInfo(const FunctionInfo &Arg)
: Info(nullptr, Arg.Info.getInt()) {
if (const auto *ArgPtr = Arg.Info.getPointer())
Info.setPointer(new AlignedMap(*ArgPtr));
}
FunctionInfo(FunctionInfo &&Arg)
: Info(Arg.Info.getPointer(), Arg.Info.getInt()) {
Arg.Info.setPointerAndInt(nullptr, 0);
}
FunctionInfo &operator=(const FunctionInfo &RHS) {
delete Info.getPointer();
Info.setPointerAndInt(nullptr, RHS.Info.getInt());
if (const auto *RHSPtr = RHS.Info.getPointer())
Info.setPointer(new AlignedMap(*RHSPtr));
return *this;
}
FunctionInfo &operator=(FunctionInfo &&RHS) {
delete Info.getPointer();
Info.setPointerAndInt(RHS.Info.getPointer(), RHS.Info.getInt());
RHS.Info.setPointerAndInt(nullptr, 0);
return *this;
}
ModRefInfo getModRefInfo() const {
return ModRefInfo(Info.getInt() & MRI_ModRef);
}
void addModRefInfo(ModRefInfo NewMRI) {
Info.setInt(Info.getInt() | NewMRI);
}
bool mayReadAnyGlobal() const { return Info.getInt() & MayReadAnyGlobal; }
void setMayReadAnyGlobal() { Info.setInt(Info.getInt() | MayReadAnyGlobal); }
ModRefInfo getModRefInfoForGlobal(const GlobalValue &GV) const {
ModRefInfo GlobalMRI = mayReadAnyGlobal() ? MRI_Ref : MRI_NoModRef;
if (AlignedMap *P = Info.getPointer()) {
auto I = P->Map.find(&GV);
if (I != P->Map.end())
GlobalMRI = ModRefInfo(GlobalMRI | I->second);
}
return GlobalMRI;
}
void addFunctionInfo(const FunctionInfo &FI) {
addModRefInfo(FI.getModRefInfo());
if (FI.mayReadAnyGlobal())
setMayReadAnyGlobal();
if (AlignedMap *P = FI.Info.getPointer())
for (const auto &G : P->Map)
addModRefInfoForGlobal(*G.first, G.second);
}
void addModRefInfoForGlobal(const GlobalValue &GV, ModRefInfo NewMRI) {
AlignedMap *P = Info.getPointer();
if (!P) {
P = new AlignedMap();
Info.setPointer(P);
}
auto &GlobalMRI = P->Map[&GV];
GlobalMRI = ModRefInfo(GlobalMRI | NewMRI);
}
void eraseModRefInfoForGlobal(const GlobalValue &GV) {
if (AlignedMap *P = Info.getPointer())
P->Map.erase(&GV);
}
private:
PointerIntPair<AlignedMap *, 3, unsigned, AlignedMapPointerTraits> Info;
};
void GlobalsAAResult::DeletionCallbackHandle::deleted() {
Value *V = getValPtr();
if (auto *F = dyn_cast<Function>(V))
GAR->FunctionInfos.erase(F);
if (GlobalValue *GV = dyn_cast<GlobalValue>(V)) {
if (GAR->NonAddressTakenGlobals.erase(GV)) {
if (GAR->IndirectGlobals.erase(GV)) {
for (auto I = GAR->AllocsForIndirectGlobals.begin(),
E = GAR->AllocsForIndirectGlobals.end();
I != E; ++I)
if (I->second == GV)
GAR->AllocsForIndirectGlobals.erase(I);
}
for (auto &FIPair : GAR->FunctionInfos)
FIPair.second.eraseModRefInfoForGlobal(*GV);
}
}
GAR->AllocsForIndirectGlobals.erase(V);
setValPtr(nullptr);
GAR->Handles.erase(I);
}
FunctionModRefBehavior GlobalsAAResult::getModRefBehavior(const Function *F) {
FunctionModRefBehavior Min = FMRB_UnknownModRefBehavior;
if (FunctionInfo *FI = getFunctionInfo(F)) {
if (FI->getModRefInfo() == MRI_NoModRef)
Min = FMRB_DoesNotAccessMemory;
else if ((FI->getModRefInfo() & MRI_Mod) == 0)
Min = FMRB_OnlyReadsMemory;
}
return FunctionModRefBehavior(AAResultBase::getModRefBehavior(F) & Min);
}
FunctionModRefBehavior
GlobalsAAResult::getModRefBehavior(ImmutableCallSite CS) {
FunctionModRefBehavior Min = FMRB_UnknownModRefBehavior;
if (const Function *F = CS.getCalledFunction())
if (FunctionInfo *FI = getFunctionInfo(F)) {
if (FI->getModRefInfo() == MRI_NoModRef)
Min = FMRB_DoesNotAccessMemory;
else if ((FI->getModRefInfo() & MRI_Mod) == 0)
Min = FMRB_OnlyReadsMemory;
}
return FunctionModRefBehavior(AAResultBase::getModRefBehavior(CS) & Min);
}
GlobalsAAResult::FunctionInfo *
GlobalsAAResult::getFunctionInfo(const Function *F) {
auto I = FunctionInfos.find(F);
if (I != FunctionInfos.end())
return &I->second;
return nullptr;
}
void GlobalsAAResult::AnalyzeGlobals(Module &M) {
SmallPtrSet<Function *, 64> TrackedFunctions;
for (Function &F : M)
if (F.hasLocalLinkage())
if (!AnalyzeUsesOfPointer(&F)) {
NonAddressTakenGlobals.insert(&F);
TrackedFunctions.insert(&F);
Handles.emplace_front(*this, &F);
Handles.front().I = Handles.begin();
++NumNonAddrTakenFunctions;
}
SmallPtrSet<Function *, 64> Readers, Writers;
for (GlobalVariable &GV : M.globals())
if (GV.hasLocalLinkage()) {
if (!AnalyzeUsesOfPointer(&GV, &Readers,
GV.isConstant() ? nullptr : &Writers)) {
NonAddressTakenGlobals.insert(&GV);
Handles.emplace_front(*this, &GV);
Handles.front().I = Handles.begin();
for (Function *Reader : Readers) {
if (TrackedFunctions.insert(Reader).second) {
Handles.emplace_front(*this, Reader);
Handles.front().I = Handles.begin();
}
FunctionInfos[Reader].addModRefInfoForGlobal(GV, MRI_Ref);
}
if (!GV.isConstant()) for (Function *Writer : Writers) {
if (TrackedFunctions.insert(Writer).second) {
Handles.emplace_front(*this, Writer);
Handles.front().I = Handles.begin();
}
FunctionInfos[Writer].addModRefInfoForGlobal(GV, MRI_Mod);
}
++NumNonAddrTakenGlobalVars;
if (GV.getType()->getElementType()->isPointerTy() &&
AnalyzeIndirectGlobalMemory(&GV))
++NumIndirectGlobalVars;
}
Readers.clear();
Writers.clear();
}
}
bool GlobalsAAResult::AnalyzeUsesOfPointer(Value *V,
SmallPtrSetImpl<Function *> *Readers,
SmallPtrSetImpl<Function *> *Writers,
GlobalValue *OkayStoreDest) {
if (!V->getType()->isPointerTy())
return true;
for (Use &U : V->uses()) {
User *I = U.getUser();
if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
if (Readers)
Readers->insert(LI->getParent()->getParent());
} else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
if (V == SI->getOperand(1)) {
if (Writers)
Writers->insert(SI->getParent()->getParent());
} else if (SI->getOperand(1) != OkayStoreDest) {
return true; }
} else if (Operator::getOpcode(I) == Instruction::GetElementPtr) {
if (AnalyzeUsesOfPointer(I, Readers, Writers))
return true;
} else if (Operator::getOpcode(I) == Instruction::BitCast) {
if (AnalyzeUsesOfPointer(I, Readers, Writers, OkayStoreDest))
return true;
} else if (auto CS = CallSite(I)) {
if (!CS.isCallee(&U)) {
if (isFreeCall(I, &TLI)) {
if (Writers)
Writers->insert(CS->getParent()->getParent());
} else if (CS.doesNotCapture(CS.getArgumentNo(&U))) {
Function *ParentF = CS->getParent()->getParent();
if (FunctionToSCCMap[ParentF] ==
FunctionToSCCMap[CS.getCalledFunction()])
return true;
if (Readers)
Readers->insert(ParentF);
if (Writers)
Writers->insert(ParentF);
} else {
return true; }
}
} else if (ICmpInst *ICI = dyn_cast<ICmpInst>(I)) {
if (!isa<ConstantPointerNull>(ICI->getOperand(1)))
return true; } else {
return true;
}
}
return false;
}
bool GlobalsAAResult::AnalyzeIndirectGlobalMemory(GlobalVariable *GV) {
std::vector<Value *> AllocRelatedValues;
if (Constant *C = GV->getInitializer())
if (!C->isNullValue())
return false;
for (User *U : GV->users()) {
if (LoadInst *LI = dyn_cast<LoadInst>(U)) {
if (AnalyzeUsesOfPointer(LI))
return false; } else if (StoreInst *SI = dyn_cast<StoreInst>(U)) {
if (SI->getOperand(0) == GV)
return false;
if (isa<ConstantPointerNull>(SI->getOperand(0)))
continue;
Value *Ptr = GetUnderlyingObject(SI->getOperand(0),
GV->getParent()->getDataLayout());
if (!isAllocLikeFn(Ptr, &TLI))
return false;
if (AnalyzeUsesOfPointer(Ptr, nullptr, nullptr,
GV))
return false;
AllocRelatedValues.push_back(Ptr);
} else {
return false;
}
}
while (!AllocRelatedValues.empty()) {
AllocsForIndirectGlobals[AllocRelatedValues.back()] = GV;
Handles.emplace_front(*this, AllocRelatedValues.back());
Handles.front().I = Handles.begin();
AllocRelatedValues.pop_back();
}
IndirectGlobals.insert(GV);
Handles.emplace_front(*this, GV);
Handles.front().I = Handles.begin();
return true;
}
void GlobalsAAResult::CollectSCCMembership(CallGraph &CG) {
unsigned SCCID = 0;
for (scc_iterator<CallGraph *> I = scc_begin(&CG); !I.isAtEnd(); ++I) {
const std::vector<CallGraphNode *> &SCC = *I;
assert(!SCC.empty() && "SCC with no functions?");
for (auto *CGN : SCC)
if (Function *F = CGN->getFunction())
FunctionToSCCMap[F] = SCCID;
++SCCID;
}
}
void GlobalsAAResult::AnalyzeCallGraph(CallGraph &CG, Module &M) {
for (scc_iterator<CallGraph *> I = scc_begin(&CG); !I.isAtEnd(); ++I) {
const std::vector<CallGraphNode *> &SCC = *I;
assert(!SCC.empty() && "SCC with no functions?");
if (!SCC[0]->getFunction() || SCC[0]->getFunction()->mayBeOverridden()) {
for (auto *Node : SCC)
FunctionInfos.erase(Node->getFunction());
continue;
}
FunctionInfo &FI = FunctionInfos[SCC[0]->getFunction()];
bool KnowNothing = false;
for (unsigned i = 0, e = SCC.size(); i != e && !KnowNothing; ++i) {
Function *F = SCC[i]->getFunction();
if (!F) {
KnowNothing = true;
break;
}
if (F->isDeclaration()) {
if (F->doesNotAccessMemory()) {
} else if (F->onlyReadsMemory()) {
FI.addModRefInfo(MRI_Ref);
if (!F->isIntrinsic())
FI.setMayReadAnyGlobal();
} else {
FI.addModRefInfo(MRI_ModRef);
KnowNothing = !F->isIntrinsic();
}
continue;
}
for (CallGraphNode::iterator CI = SCC[i]->begin(), E = SCC[i]->end();
CI != E && !KnowNothing; ++CI)
if (Function *Callee = CI->second->getFunction()) {
if (FunctionInfo *CalleeFI = getFunctionInfo(Callee)) {
FI.addFunctionInfo(*CalleeFI);
} else {
CallGraphNode *CalleeNode = CG[Callee];
if (std::find(SCC.begin(), SCC.end(), CalleeNode) == SCC.end())
KnowNothing = true;
}
} else {
KnowNothing = true;
}
}
if (KnowNothing) {
for (auto *Node : SCC)
FunctionInfos.erase(Node->getFunction());
continue;
}
for (auto *Node : SCC) {
if (FI.getModRefInfo() == MRI_ModRef)
break; for (Instruction &I : instructions(Node->getFunction())) {
if (FI.getModRefInfo() == MRI_ModRef)
break;
if (auto CS = CallSite(&I)) {
if (isAllocationFn(&I, &TLI) || isFreeCall(&I, &TLI)) {
FI.addModRefInfo(MRI_ModRef);
} else if (Function *Callee = CS.getCalledFunction()) {
if (Callee->isIntrinsic()) {
FunctionModRefBehavior Behaviour =
AAResultBase::getModRefBehavior(Callee);
FI.addModRefInfo(ModRefInfo(Behaviour & MRI_ModRef));
}
}
continue;
}
if (I.mayReadFromMemory())
FI.addModRefInfo(MRI_Ref);
if (I.mayWriteToMemory())
FI.addModRefInfo(MRI_Mod);
}
}
if ((FI.getModRefInfo() & MRI_Mod) == 0)
++NumReadMemFunctions;
if (FI.getModRefInfo() == MRI_NoModRef)
++NumNoMemFunctions;
FunctionInfo CachedFI = FI;
for (unsigned i = 1, e = SCC.size(); i != e; ++i)
FunctionInfos[SCC[i]->getFunction()] = CachedFI;
}
}
static bool isNonEscapingGlobalNoAliasWithLoad(const GlobalValue *GV,
const Value *V,
int &Depth,
const DataLayout &DL) {
SmallPtrSet<const Value *, 8> Visited;
SmallVector<const Value *, 8> Inputs;
Visited.insert(V);
Inputs.push_back(V);
do {
const Value *Input = Inputs.pop_back_val();
if (isa<GlobalValue>(Input) || isa<Argument>(Input) || isa<CallInst>(Input) ||
isa<InvokeInst>(Input))
continue;
if (++Depth > 4)
return false;
if (auto *LI = dyn_cast<LoadInst>(Input)) {
Inputs.push_back(GetUnderlyingObject(LI->getPointerOperand(), DL));
continue;
}
if (auto *SI = dyn_cast<SelectInst>(Input)) {
const Value *LHS = GetUnderlyingObject(SI->getTrueValue(), DL);
const Value *RHS = GetUnderlyingObject(SI->getFalseValue(), DL);
if (Visited.insert(LHS).second)
Inputs.push_back(LHS);
if (Visited.insert(RHS).second)
Inputs.push_back(RHS);
continue;
}
if (auto *PN = dyn_cast<PHINode>(Input)) {
for (const Value *Op : PN->incoming_values()) {
Op = GetUnderlyingObject(Op, DL);
if (Visited.insert(Op).second)
Inputs.push_back(Op);
}
continue;
}
return false;
} while (!Inputs.empty());
return true;
}
bool GlobalsAAResult::isNonEscapingGlobalNoAlias(const GlobalValue *GV,
const Value *V) {
SmallPtrSet<const Value *, 8> Visited;
SmallVector<const Value *, 8> Inputs;
Visited.insert(V);
Inputs.push_back(V);
int Depth = 0;
do {
const Value *Input = Inputs.pop_back_val();
if (auto *InputGV = dyn_cast<GlobalValue>(Input)) {
if (InputGV == GV)
return false;
auto *GVar = dyn_cast<GlobalVariable>(GV);
auto *InputGVar = dyn_cast<GlobalVariable>(InputGV);
if (GVar && InputGVar &&
!GVar->isDeclaration() && !InputGVar->isDeclaration() &&
!GVar->mayBeOverridden() && !InputGVar->mayBeOverridden()) {
Type *GVType = GVar->getInitializer()->getType();
Type *InputGVType = InputGVar->getInitializer()->getType();
if (GVType->isSized() && InputGVType->isSized() &&
(DL.getTypeAllocSize(GVType) > 0) &&
(DL.getTypeAllocSize(InputGVType) > 0))
continue;
}
return false;
}
if (isa<Argument>(Input) || isa<CallInst>(Input) ||
isa<InvokeInst>(Input)) {
continue;
}
if (++Depth > 4)
return false;
if (auto *LI = dyn_cast<LoadInst>(Input)) {
const Value *Ptr = GetUnderlyingObject(LI->getPointerOperand(), DL);
if (isNonEscapingGlobalNoAliasWithLoad(GV, Ptr, Depth, DL))
continue;
return false;
}
if (auto *SI = dyn_cast<SelectInst>(Input)) {
const Value *LHS = GetUnderlyingObject(SI->getTrueValue(), DL);
const Value *RHS = GetUnderlyingObject(SI->getFalseValue(), DL);
if (Visited.insert(LHS).second)
Inputs.push_back(LHS);
if (Visited.insert(RHS).second)
Inputs.push_back(RHS);
continue;
}
if (auto *PN = dyn_cast<PHINode>(Input)) {
for (const Value *Op : PN->incoming_values()) {
Op = GetUnderlyingObject(Op, DL);
if (Visited.insert(Op).second)
Inputs.push_back(Op);
}
continue;
}
return false;
} while (!Inputs.empty());
return true;
}
AliasResult GlobalsAAResult::alias(const MemoryLocation &LocA,
const MemoryLocation &LocB) {
const Value *UV1 = GetUnderlyingObject(LocA.Ptr, DL);
const Value *UV2 = GetUnderlyingObject(LocB.Ptr, DL);
const GlobalValue *GV1 = dyn_cast<GlobalValue>(UV1);
const GlobalValue *GV2 = dyn_cast<GlobalValue>(UV2);
if (GV1 || GV2) {
if (GV1 && !NonAddressTakenGlobals.count(GV1))
GV1 = nullptr;
if (GV2 && !NonAddressTakenGlobals.count(GV2))
GV2 = nullptr;
if (GV1 && GV2 && GV1 != GV2)
return NoAlias;
if (EnableUnsafeGlobalsModRefAliasResults)
if ((GV1 || GV2) && GV1 != GV2)
return NoAlias;
if ((GV1 || GV2) && GV1 != GV2) {
const GlobalValue *GV = GV1 ? GV1 : GV2;
const Value *UV = GV1 ? UV2 : UV1;
if (isNonEscapingGlobalNoAlias(GV, UV))
return NoAlias;
}
}
GV1 = GV2 = nullptr;
if (const LoadInst *LI = dyn_cast<LoadInst>(UV1))
if (GlobalVariable *GV = dyn_cast<GlobalVariable>(LI->getOperand(0)))
if (IndirectGlobals.count(GV))
GV1 = GV;
if (const LoadInst *LI = dyn_cast<LoadInst>(UV2))
if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(LI->getOperand(0)))
if (IndirectGlobals.count(GV))
GV2 = GV;
if (!GV1)
GV1 = AllocsForIndirectGlobals.lookup(UV1);
if (!GV2)
GV2 = AllocsForIndirectGlobals.lookup(UV2);
if (GV1 && GV2 && GV1 != GV2)
return NoAlias;
if (EnableUnsafeGlobalsModRefAliasResults)
if ((GV1 || GV2) && GV1 != GV2)
return NoAlias;
return AAResultBase::alias(LocA, LocB);
}
ModRefInfo GlobalsAAResult::getModRefInfoForArgument(ImmutableCallSite CS,
const GlobalValue *GV) {
if (CS.doesNotAccessMemory())
return MRI_NoModRef;
ModRefInfo ConservativeResult = CS.onlyReadsMemory() ? MRI_Ref : MRI_ModRef;
for (auto &A : CS.args()) {
SmallVector<Value*, 4> Objects;
GetUnderlyingObjects(A, Objects, DL);
if (!std::all_of(Objects.begin(), Objects.end(), [&GV](const Value *V) {
return isIdentifiedObject(V);
}))
return ConservativeResult;
if (std::find(Objects.begin(), Objects.end(), GV) != Objects.end())
return ConservativeResult;
}
return MRI_NoModRef;
}
ModRefInfo GlobalsAAResult::getModRefInfo(ImmutableCallSite CS,
const MemoryLocation &Loc) {
unsigned Known = MRI_ModRef;
if (const GlobalValue *GV =
dyn_cast<GlobalValue>(GetUnderlyingObject(Loc.Ptr, DL)))
if (GV->hasLocalLinkage())
if (const Function *F = CS.getCalledFunction())
if (NonAddressTakenGlobals.count(GV))
if (const FunctionInfo *FI = getFunctionInfo(F))
Known = FI->getModRefInfoForGlobal(*GV) |
getModRefInfoForArgument(CS, GV);
if (Known == MRI_NoModRef)
return MRI_NoModRef; return ModRefInfo(Known & AAResultBase::getModRefInfo(CS, Loc));
}
GlobalsAAResult::GlobalsAAResult(const DataLayout &DL,
const TargetLibraryInfo &TLI)
: AAResultBase(TLI), DL(DL) {}
GlobalsAAResult::GlobalsAAResult(GlobalsAAResult &&Arg)
: AAResultBase(std::move(Arg)), DL(Arg.DL),
NonAddressTakenGlobals(std::move(Arg.NonAddressTakenGlobals)),
IndirectGlobals(std::move(Arg.IndirectGlobals)),
AllocsForIndirectGlobals(std::move(Arg.AllocsForIndirectGlobals)),
FunctionInfos(std::move(Arg.FunctionInfos)),
Handles(std::move(Arg.Handles)) {
for (auto &H : Handles) {
assert(H.GAR == &Arg);
H.GAR = this;
}
}
GlobalsAAResult
GlobalsAAResult::analyzeModule(Module &M, const TargetLibraryInfo &TLI,
CallGraph &CG) {
GlobalsAAResult Result(M.getDataLayout(), TLI);
Result.CollectSCCMembership(CG);
Result.AnalyzeGlobals(M);
Result.AnalyzeCallGraph(CG, M);
return Result;
}
GlobalsAAResult GlobalsAA::run(Module &M, AnalysisManager<Module> *AM) {
return GlobalsAAResult::analyzeModule(M,
AM->getResult<TargetLibraryAnalysis>(M),
AM->getResult<CallGraphAnalysis>(M));
}
char GlobalsAA::PassID;
char GlobalsAAWrapperPass::ID = 0;
INITIALIZE_PASS_BEGIN(GlobalsAAWrapperPass, "globals-aa",
"Globals Alias Analysis", false, true)
INITIALIZE_PASS_DEPENDENCY(CallGraphWrapperPass)
INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
INITIALIZE_PASS_END(GlobalsAAWrapperPass, "globals-aa",
"Globals Alias Analysis", false, true)
ModulePass *llvm::createGlobalsAAWrapperPass() {
return new GlobalsAAWrapperPass();
}
GlobalsAAWrapperPass::GlobalsAAWrapperPass() : ModulePass(ID) {
initializeGlobalsAAWrapperPassPass(*PassRegistry::getPassRegistry());
}
bool GlobalsAAWrapperPass::runOnModule(Module &M) {
Result.reset(new GlobalsAAResult(GlobalsAAResult::analyzeModule(
M, getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(),
getAnalysis<CallGraphWrapperPass>().getCallGraph())));
return false;
}
bool GlobalsAAWrapperPass::doFinalization(Module &M) {
Result.reset();
return false;
}
void GlobalsAAWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesAll();
AU.addRequired<CallGraphWrapperPass>();
AU.addRequired<TargetLibraryInfoWrapperPass>();
}