33 #define DEBUG_TYPE "globalsmodref-aa"
36 "Number of global vars without address taken");
37 STATISTIC(NumNonAddrTakenFunctions,
"Number of functions without address taken");
38 STATISTIC(NumNoMemFunctions,
"Number of functions that do not access memory");
39 STATISTIC(NumReadMemFunctions,
"Number of functions that only read memory");
40 STATISTIC(NumIndirectGlobalVars,
"Number of indirect global objects");
70 AlignedMap(
const AlignedMap &Arg) : Map(Arg.Map) {}
75 struct AlignedMapPointerTraits {
76 static inline void *getAsVoidPointer(AlignedMap *
P) {
return P; }
77 static inline AlignedMap *getFromVoidPointer(
void *P) {
78 return (AlignedMap *)
P;
80 enum { NumLowBitsAvailable = 3 };
81 static_assert(
alignof(AlignedMap) >= (1 << NumLowBitsAvailable),
82 "AlignedMap insufficiently aligned to have enough low bits.");
87 enum { MayReadAnyGlobal = 4 };
90 static_assert((MayReadAnyGlobal &
MRI_ModRef) == 0,
91 "ModRef and the MayReadAnyGlobal flag bits overlap.");
92 static_assert(((MayReadAnyGlobal | MRI_ModRef) >>
93 AlignedMapPointerTraits::NumLowBitsAvailable) == 0,
94 "Insufficient low bits to store our flag and ModRef info.");
99 delete Info.getPointer();
105 : Info(nullptr, Arg.Info.
getInt()) {
106 if (
const auto *ArgPtr = Arg.Info.
getPointer())
107 Info.setPointer(
new AlignedMap(*ArgPtr));
110 : Info(Arg.Info.getPointer(), Arg.Info.
getInt()) {
111 Arg.Info.setPointerAndInt(
nullptr, 0);
114 delete Info.getPointer();
115 Info.setPointerAndInt(
nullptr, RHS.Info.
getInt());
116 if (
const auto *RHSPtr = RHS.Info.
getPointer())
117 Info.setPointer(
new AlignedMap(*RHSPtr));
121 delete Info.getPointer();
122 Info.setPointerAndInt(RHS.Info.getPointer(), RHS.Info.getInt());
134 Info.setInt(Info.getInt() | NewMRI);
148 if (AlignedMap *
P = Info.getPointer()) {
149 auto I =
P->Map.find(&GV);
150 if (
I !=
P->Map.end())
165 for (
const auto &
G :
P->Map)
170 AlignedMap *
P = Info.getPointer();
172 P =
new AlignedMap();
175 auto &GlobalMRI = P->Map[&GV];
182 if (AlignedMap *
P = Info.getPointer())
195 void GlobalsAAResult::DeletionCallbackHandle::deleted() {
196 Value *V = getValPtr();
197 if (
auto *
F = dyn_cast<Function>(V))
198 GAR->FunctionInfos.erase(
F);
201 if (GAR->NonAddressTakenGlobals.erase(GV)) {
204 if (GAR->IndirectGlobals.erase(GV)) {
206 for (
auto I = GAR->AllocsForIndirectGlobals.begin(),
207 E = GAR->AllocsForIndirectGlobals.end();
210 GAR->AllocsForIndirectGlobals.erase(
I);
215 for (
auto &FIPair : GAR->FunctionInfos)
216 FIPair.second.eraseModRefInfoForGlobal(*GV);
221 GAR->AllocsForIndirectGlobals.erase(V);
225 GAR->Handles.erase(
I);
235 else if ((FI->getModRefInfo() &
MRI_Mod) == 0)
251 else if ((FI->getModRefInfo() &
MRI_Mod) == 0)
261 GlobalsAAResult::getFunctionInfo(
const Function *
F) {
262 auto I = FunctionInfos.find(F);
263 if (
I != FunctionInfos.end())
272 void GlobalsAAResult::AnalyzeGlobals(
Module &M) {
276 if (!AnalyzeUsesOfPointer(&F)) {
278 NonAddressTakenGlobals.insert(&F);
279 TrackedFunctions.
insert(&F);
280 Handles.emplace_front(*
this, &F);
281 Handles.front().I = Handles.begin();
282 ++NumNonAddrTakenFunctions;
287 if (GV.hasLocalLinkage()) {
288 if (!AnalyzeUsesOfPointer(&GV, &Readers,
289 GV.isConstant() ?
nullptr : &Writers)) {
291 NonAddressTakenGlobals.insert(&GV);
292 Handles.emplace_front(*
this, &GV);
293 Handles.front().I = Handles.begin();
296 if (TrackedFunctions.
insert(Reader).second) {
297 Handles.emplace_front(*
this, Reader);
298 Handles.front().I = Handles.begin();
300 FunctionInfos[Reader].addModRefInfoForGlobal(GV,
MRI_Ref);
303 if (!GV.isConstant())
305 if (TrackedFunctions.
insert(Writer).second) {
306 Handles.emplace_front(*
this, Writer);
307 Handles.front().I = Handles.begin();
309 FunctionInfos[Writer].addModRefInfoForGlobal(GV,
MRI_Mod);
311 ++NumNonAddrTakenGlobalVars;
314 if (GV.getValueType()->isPointerTy() &&
315 AnalyzeIndirectGlobalMemory(&GV))
316 ++NumIndirectGlobalVars;
329 bool GlobalsAAResult::AnalyzeUsesOfPointer(
Value *V,
337 User *
I = U.getUser();
338 if (
LoadInst *LI = dyn_cast<LoadInst>(I)) {
340 Readers->
insert(LI->getParent()->getParent());
341 }
else if (
StoreInst *SI = dyn_cast<StoreInst>(I)) {
342 if (V ==
SI->getOperand(1)) {
344 Writers->
insert(
SI->getParent()->getParent());
345 }
else if (
SI->getOperand(1) != OkayStoreDest) {
349 if (AnalyzeUsesOfPointer(I, Readers, Writers))
352 if (AnalyzeUsesOfPointer(I, Readers, Writers, OkayStoreDest))
357 if (
CS.isDataOperand(&U)) {
361 Writers->
insert(
CS->getParent()->getParent());
366 }
else if (
ICmpInst *ICI = dyn_cast<ICmpInst>(I)) {
367 if (!isa<ConstantPointerNull>(ICI->getOperand(1)))
369 }
else if (
Constant *
C = dyn_cast<Constant>(I)) {
371 if (isa<GlobalValue>(
C) ||
C->isConstantUsed())
388 bool GlobalsAAResult::AnalyzeIndirectGlobalMemory(
GlobalVariable *GV) {
391 std::vector<Value *> AllocRelatedValues;
395 if (!
C->isNullValue())
401 if (
LoadInst *LI = dyn_cast<LoadInst>(U)) {
405 if (AnalyzeUsesOfPointer(LI))
408 }
else if (
StoreInst *SI = dyn_cast<StoreInst>(U)) {
410 if (
SI->getOperand(0) == GV)
414 if (isa<ConstantPointerNull>(
SI->getOperand(0)))
426 if (AnalyzeUsesOfPointer(Ptr,
nullptr,
nullptr,
431 AllocRelatedValues.push_back(Ptr);
440 while (!AllocRelatedValues.empty()) {
441 AllocsForIndirectGlobals[AllocRelatedValues.back()] = GV;
442 Handles.emplace_front(*
this, AllocRelatedValues.back());
443 Handles.front().I = Handles.begin();
444 AllocRelatedValues.pop_back();
446 IndirectGlobals.insert(GV);
447 Handles.emplace_front(*
this, GV);
448 Handles.front().I = Handles.begin();
452 void GlobalsAAResult::CollectSCCMembership(
CallGraph &CG) {
457 const std::vector<CallGraphNode *> &SCC = *
I;
458 assert(!SCC.empty() &&
"SCC with no functions?");
460 for (
auto *CGN : SCC)
461 if (
Function *F = CGN->getFunction())
462 FunctionToSCCMap[F] = SCCID;
475 const std::vector<CallGraphNode *> &SCC = *
I;
476 assert(!SCC.empty() &&
"SCC with no functions?");
478 if (!SCC[0]->getFunction() || !SCC[0]->getFunction()->isDefinitionExact()) {
482 for (
auto *Node : SCC)
483 FunctionInfos.erase(Node->getFunction());
487 FunctionInfo &FI = FunctionInfos[SCC[0]->getFunction()];
488 bool KnowNothing =
false;
492 for (
unsigned i = 0, e = SCC.size();
i != e && !KnowNothing; ++
i) {
508 FI.setMayReadAnyGlobal();
519 CI !=
E && !KnowNothing; ++CI)
520 if (
Function *Callee = CI->second->getFunction()) {
521 if (FunctionInfo *CalleeFI = getFunctionInfo(Callee)) {
523 FI.addFunctionInfo(*CalleeFI);
539 for (
auto *Node : SCC)
540 FunctionInfos.erase(Node->getFunction());
545 for (
auto *Node : SCC) {
559 }
else if (
Function *Callee =
CS.getCalledFunction()) {
561 if (Callee->isIntrinsic()) {
572 if (I.mayReadFromMemory())
574 if (I.mayWriteToMemory())
579 if ((FI.getModRefInfo() &
MRI_Mod) == 0)
580 ++NumReadMemFunctions;
588 FunctionInfo CachedFI = FI;
589 for (
unsigned i = 1, e = SCC.size();
i != e; ++
i)
590 FunctionInfos[SCC[
i]->getFunction()] = CachedFI;
608 if (isa<GlobalValue>(Input) || isa<Argument>(Input) || isa<CallInst>(Input) ||
609 isa<InvokeInst>(Input))
625 if (
auto *LI = dyn_cast<LoadInst>(Input)) {
629 if (
auto *
SI = dyn_cast<SelectInst>(Input)) {
632 if (Visited.
insert(LHS).second)
634 if (Visited.
insert(RHS).second)
638 if (
auto *PN = dyn_cast<PHINode>(Input)) {
639 for (
const Value *
Op : PN->incoming_values()) {
648 }
while (!Inputs.
empty());
679 bool GlobalsAAResult::isNonEscapingGlobalNoAlias(
const GlobalValue *GV,
695 if (
auto *InputGV = dyn_cast<GlobalValue>(Input)) {
705 if (GVar && InputGVar &&
706 !GVar->isDeclaration() && !InputGVar->isDeclaration() &&
707 !GVar->isInterposable() && !InputGVar->isInterposable()) {
708 Type *GVType = GVar->getInitializer()->getType();
709 Type *InputGVType = InputGVar->getInitializer()->getType();
721 if (isa<Argument>(Input) || isa<CallInst>(Input) ||
722 isa<InvokeInst>(Input)) {
736 if (
auto *LI = dyn_cast<LoadInst>(Input)) {
746 if (
auto *SI = dyn_cast<SelectInst>(Input)) {
749 if (Visited.
insert(LHS).second)
751 if (Visited.
insert(RHS).second)
755 if (
auto *PN = dyn_cast<PHINode>(Input)) {
756 for (
const Value *
Op : PN->incoming_values()) {
771 }
while (!Inputs.
empty());
793 if (GV1 && !NonAddressTakenGlobals.count(GV1))
795 if (GV2 && !NonAddressTakenGlobals.count(GV2))
800 if (GV1 && GV2 && GV1 != GV2)
807 if ((GV1 || GV2) && GV1 != GV2)
812 if ((GV1 || GV2) && GV1 != GV2) {
814 const Value *UV = GV1 ? UV2 : UV1;
815 if (isNonEscapingGlobalNoAlias(GV, UV))
827 if (
const LoadInst *LI = dyn_cast<LoadInst>(UV1))
828 if (
GlobalVariable *GV = dyn_cast<GlobalVariable>(LI->getOperand(0)))
829 if (IndirectGlobals.count(GV))
831 if (
const LoadInst *LI = dyn_cast<LoadInst>(UV2))
832 if (
const GlobalVariable *GV = dyn_cast<GlobalVariable>(LI->getOperand(0)))
833 if (IndirectGlobals.count(GV))
839 GV1 = AllocsForIndirectGlobals.lookup(UV1);
841 GV2 = AllocsForIndirectGlobals.lookup(UV2);
846 if (GV1 && GV2 && GV1 != GV2)
853 if ((GV1 || GV2) && GV1 != GV2)
867 for (
auto &
A : CS.
args()) {
877 return ConservativeResult;
880 return ConservativeResult;
897 if (NonAddressTakenGlobals.count(GV))
899 Known = FI->getModRefInfoForGlobal(*GV) |
900 getModRefInfoForArgument(CS, GV);
907 GlobalsAAResult::GlobalsAAResult(
const DataLayout &DL,
912 :
AAResultBase(std::move(Arg)), DL(Arg.DL), TLI(Arg.TLI),
913 NonAddressTakenGlobals(std::move(Arg.NonAddressTakenGlobals)),
914 IndirectGlobals(std::move(Arg.IndirectGlobals)),
915 AllocsForIndirectGlobals(std::move(Arg.AllocsForIndirectGlobals)),
916 FunctionInfos(std::move(Arg.FunctionInfos)),
917 Handles(std::move(Arg.Handles)) {
919 for (
auto &
H : Handles) {
933 Result.CollectSCCMembership(CG);
936 Result.AnalyzeGlobals(M);
939 Result.AnalyzeCallGraph(CG, M);
954 "Globals Alias Analysis",
false,
true)
961 return new GlobalsAAWrapperPass();
970 M, getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(),
971 getAnalysis<CallGraphWrapperPass>().getCallGraph())));
Legacy wrapper pass to provide the GlobalsAAResult object.
void push_back(const T &Elt)
bool isAllocationFn(const Value *V, const TargetLibraryInfo *TLI, bool LookThroughBitCast=false)
Tests if a value is a call or invoke to a library function that allocates or reallocates memory (eith...
This builds on the llvm/ADT/GraphTraits.h file to find the strongly connected components (SCCs) of a ...
A parsed version of the target data layout string in and methods for querying it. ...
const_iterator end(StringRef path)
Get end iterator over path.
bool doFinalization(Module &M) override
doFinalization - Virtual method overriden by subclasses to do any necessary clean up after all passes...
iterator_range< use_iterator > uses()
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
void addFunctionInfo(const FunctionInfo &FI)
Add mod/ref info from another function into ours, saturating towards MRI_ModRef.
STATISTIC(NumFunctions,"Total number of functions")
void setMayReadAnyGlobal()
Sets this function as potentially reading from any global.
globals Globals Alias Analysis
static cl::opt< bool > EnableUnsafeGlobalsModRefAliasResults("enable-unsafe-globalsmodref-alias-results", cl::init(false), cl::Hidden)
FunctionInfo & operator=(const FunctionInfo &RHS)
This is the interface for a simple mod/ref and alias analysis over globals.
bool onlyReadsMemory() const
Determine if the function does not access or only reads memory.
A Module instance is used to store all the information related to an LLVM module. ...
bool isIntrinsic() const
isIntrinsic - Returns true if the function's name starts with "llvm.".
FunctionInfo & operator=(FunctionInfo &&RHS)
bool onlyReadsMemory() const
Determine if the call does not access or only reads memory.
const_iterator begin(StringRef path)
Get begin iterator over path.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly...
The two locations do not alias at all.
An instruction for reading from memory.
void GetUnderlyingObjects(Value *V, SmallVectorImpl< Value * > &Objects, const DataLayout &DL, LoopInfo *LI=nullptr, unsigned MaxLookup=6)
This method is similar to GetUnderlyingObject except that it can look through phi and select instruct...
const Constant * getInitializer() const
getInitializer - Return the initializer for this global variable.
ModRefInfo getModRefInfo() const
Returns the ModRefInfo info for this function.
A node in the call graph for a module.
The mod/ref information collected for a particular function.
The access modifies the value stored in memory.
void addModRefInfoForGlobal(const GlobalValue &GV, ModRefInfo NewMRI)
const CallInst * isFreeCall(const Value *I, const TargetLibraryInfo *TLI)
isFreeCall - Returns non-null if the value is a call to the builtin free()
This indicates that the function could not be classified into one of the behaviors above...
A templated base class for SmallPtrSet which provides the typesafe interface that is common across al...
std::vector< CallRecord >::iterator iterator
AnalysisUsage & addRequired()
bool mayReadAnyGlobal() const
Returns whether this function may read any global variable, and we don't know which global...
#define INITIALIZE_PASS_DEPENDENCY(depName)
ModRefInfo
Flags indicating whether a memory access modifies or references memory.
static unsigned getInt(StringRef R)
Get an unsigned integer, including error checks.
A Use represents the edge between a Value definition and its users.
The access references the value stored in memory.
LLVM_NODISCARD bool empty() const
bool isIdentifiedObject(const Value *V)
Return true if this pointer refers to a distinct and identifiable object.
A CRTP-driven "mixin" base class to help implement the function alias analysis results concept...
scc_iterator< T > scc_begin(const T &G)
Construct the begin iterator for a deduced graph type T.
static GlobalsAAResult analyzeModule(Module &M, const TargetLibraryInfo &TLI, CallGraph &CG)
PointerTy getPointer() const
bool runOnModule(Module &M) override
runOnModule - Virtual method overriden by subclasses to process the module being operated on...
GlobalsAAResult run(Module &M, ModuleAnalysisManager &AM)
FunctionModRefBehavior
Summary of how a function affects memory in the program.
An instruction for storing to memory.
AliasResult alias(const MemoryLocation &LocA, const MemoryLocation &LocB)
FunctionInfo(const FunctionInfo &Arg)
bool doesNotAccessMemory() const
Determine if the function does not access memory.
static GCRegistry::Add< CoreCLRGC > E("coreclr","CoreCLR-compatible GC")
bool hasOperandBundles() const
INITIALIZE_PASS_BEGIN(GlobalsAAWrapperPass,"globals-aa","Globals Alias Analysis", false, true) INITIALIZE_PASS_END(GlobalsAAWrapperPass
FunctionModRefBehavior getModRefBehavior(ImmutableCallSite CS)
bool isSized(SmallPtrSetImpl< Type * > *Visited=nullptr) const
Return true if it makes sense to take the size of this type.
The access neither references nor modifies the value stored in memory.
initializer< Ty > init(const Ty &Val)
iterator_range< IterTy > args() const
The ModulePass which wraps up a CallGraph and the logic to build it.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs...ExtraArgs)
Get the result of an analysis pass for a given IR unit.
FunctionInfo(FunctionInfo &&Arg)
The instances of the Type class are immutable: once they are created, they are never changed...
AliasResult alias(const MemoryLocation &LocA, const MemoryLocation &LocB)
alias - If one of the pointers is to a global that we are tracking, and the other is some random poin...
An alias analysis result set for globals.
This is an important base class in LLVM.
FunctionModRefBehavior getModRefBehavior(const Function *F)
getModRefBehavior - Return the behavior of the specified function if called from the specified call s...
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
AliasResult
The possible results of an alias query.
Represent the analysis usage information of a pass.
This instruction compares its operands according to the predicate given to the constructor.
INITIALIZE_PASS_END(RegBankSelect, DEBUG_TYPE,"Assign register bank of generic virtual registers", false, false) RegBankSelect
bool isPointerTy() const
True if this is an instance of PointerType.
bool onlyAccessesArgMemory() const
Determine if the call can access memmory only using pointers based on its arguments.
Value * GetUnderlyingObject(Value *V, const DataLayout &DL, unsigned MaxLookup=6)
This method strips off any GEP address adjustments and pointer casts from the specified value...
This function does not perform any non-local loads or stores to memory.
void initializeGlobalsAAWrapperPassPass(PassRegistry &)
bool doesNotAccessMemory() const
Determine if the call does not access memory.
const Value * Ptr
The address of the start of the location.
Representation for a specific memory location.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements...
uint64_t getTypeAllocSize(Type *Ty) const
Returns the offset in bytes between successive objects of the specified type, including alignment pad...
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small...
Module.h This file contains the declarations for the Module class.
Type * getType() const
All values are typed, get the type of this value.
Provides information about what library functions are available for the current target.
void eraseModRefInfoForGlobal(const GlobalValue &GV)
Clear a global's ModRef info.
LLVM_NODISCARD T pop_back_val()
void addModRefInfo(ModRefInfo NewMRI)
Adds new ModRefInfo for this function to its state.
This function does not perform any non-local stores or volatile loads, but may read from any memory l...
static GCRegistry::Add< ShadowStackGC > C("shadow-stack","Very portable GC for uncooperative code generators")
ModRefInfo getModRefInfoForGlobal(const GlobalValue &GV) const
Returns the ModRefInfo info for this function w.r.t.
void setPreservesAll()
Set by analyses that do not transform their input at all.
iterator_range< user_iterator > users()
void setPointerAndInt(PointerTy PtrVal, IntType IntVal)
unsigned getOpcode() const
Return the opcode for this Instruction or ConstantExpr.
An analysis pass to compute the CallGraph for a Module.
const DataLayout & getDataLayout() const
Get the data layout for the module's target platform.
The basic data container for the call graph of a Module of IR.
#define LLVM_ALIGNAS(x)
LLVM_ALIGNAS
bool isDeclaration() const
Return true if the primary definition of this global value is outside of the current translation unit...
FunctionInfo()
Checks to document the invariants of the bit packing here.
ImmutableCallSite - establish a view to a call site for examination.
ModulePass * createGlobalsAAWrapperPass()
The access both references and modifies the value stored in memory.
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
bool isAllocLikeFn(const Value *V, const TargetLibraryInfo *TLI, bool LookThroughBitCast=false)
Tests if a value is a call or invoke to a library function that allocates memory (either malloc...
LLVM_NODISCARD std::enable_if<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type >::type dyn_cast(const Y &Val)
bool hasLocalLinkage() const
ModRefInfo getModRefInfo(ImmutableCallSite CS, const MemoryLocation &Loc)
Analysis pass providing the TargetLibraryInfo.
globals Globals Alias false
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
FunTy * getCalledFunction() const
getCalledFunction - Return the function being called if this is a direct call, otherwise return null ...
Module * getParent()
Get the module that this global value is contained inside of...
LLVM Value Representation.
inst_range instructions(Function *F)
A container for analyses that lazily runs them and caches their results.
static GCRegistry::Add< ErlangGC > A("erlang","erlang-compatible garbage collector")
A special type used by analysis passes to provide an address that identifies that particular analysis...
ModRefInfo getModRefInfo(ImmutableCallSite CS, const MemoryLocation &Loc)
static bool isNonEscapingGlobalNoAliasWithLoad(const GlobalValue *GV, const Value *V, int &Depth, const DataLayout &DL)
Enumerate the SCCs of a directed graph in reverse topological order of the SCC DAG.
bool is_contained(R &&Range, const E &Element)
Wrapper function around std::find to detect if an element exists in a container.
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...