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");
68 struct alignas(8) AlignedMap {
70 AlignedMap(
const AlignedMap &
Arg) : Map(Arg.Map) {}
71 GlobalInfoMapType 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.");
91 enum { MayReadAnyGlobal = 4 };
96 "ModRef and the MayReadAnyGlobal flag bits overlap.");
97 static_assert(((MayReadAnyGlobal |
99 AlignedMapPointerTraits::NumLowBitsAvailable) == 0,
100 "Insufficient low bits to store our flag and ModRef info.");
105 delete Info.getPointer();
112 if (
const auto *ArgPtr = Arg.Info.
getPointer())
113 Info.setPointer(
new AlignedMap(*ArgPtr));
117 Arg.Info.setPointerAndInt(
nullptr, 0);
120 delete Info.getPointer();
121 Info.setPointerAndInt(
nullptr, RHS.Info.
getInt());
122 if (
const auto *RHSPtr = RHS.Info.
getPointer())
123 Info.setPointer(
new AlignedMap(*RHSPtr));
127 delete Info.getPointer();
128 Info.setPointerAndInt(RHS.Info.getPointer(), RHS.Info.getInt());
129 RHS.Info.setPointerAndInt(
nullptr, 0);
163 if (AlignedMap *
P =
Info.getPointer()) {
164 auto I =
P->Map.find(&GV);
165 if (
I !=
P->Map.end())
180 for (
const auto &
G :
P->Map)
185 AlignedMap *
P =
Info.getPointer();
187 P =
new AlignedMap();
190 auto &GlobalMRI = P->Map[&GV];
197 if (AlignedMap *
P =
Info.getPointer())
210 void GlobalsAAResult::DeletionCallbackHandle::deleted() {
211 Value *V = getValPtr();
212 if (
auto *
F = dyn_cast<Function>(V))
213 GAR->FunctionInfos.erase(
F);
216 if (GAR->NonAddressTakenGlobals.erase(GV)) {
219 if (GAR->IndirectGlobals.erase(GV)) {
221 for (
auto I = GAR->AllocsForIndirectGlobals.begin(),
222 E = GAR->AllocsForIndirectGlobals.end();
225 GAR->AllocsForIndirectGlobals.erase(
I);
230 for (
auto &FIPair : GAR->FunctionInfos)
231 FIPair.second.eraseModRefInfoForGlobal(*GV);
236 GAR->AllocsForIndirectGlobals.erase(V);
240 GAR->Handles.erase(
I);
250 else if (!
isModSet(FI->getModRefInfo()))
266 else if (!
isModSet(FI->getModRefInfo()))
276 GlobalsAAResult::getFunctionInfo(
const Function *
F) {
277 auto I = FunctionInfos.find(F);
278 if (
I != FunctionInfos.end())
287 void GlobalsAAResult::AnalyzeGlobals(
Module &M) {
291 if (!AnalyzeUsesOfPointer(&F)) {
293 NonAddressTakenGlobals.
insert(&F);
294 TrackedFunctions.
insert(&F);
295 Handles.emplace_front(*
this, &F);
296 Handles.front().I = Handles.begin();
297 ++NumNonAddrTakenFunctions;
302 if (GV.hasLocalLinkage()) {
303 if (!AnalyzeUsesOfPointer(&GV, &Readers,
304 GV.isConstant() ? nullptr : &Writers)) {
306 NonAddressTakenGlobals.
insert(&GV);
307 Handles.emplace_front(*
this, &GV);
308 Handles.front().I = Handles.begin();
311 if (TrackedFunctions.
insert(Reader).second) {
312 Handles.emplace_front(*
this, Reader);
313 Handles.front().I = Handles.begin();
318 if (!GV.isConstant())
320 if (TrackedFunctions.
insert(Writer).second) {
321 Handles.emplace_front(*
this, Writer);
322 Handles.front().I = Handles.begin();
326 ++NumNonAddrTakenGlobalVars;
329 if (GV.getValueType()->isPointerTy() &&
330 AnalyzeIndirectGlobalMemory(&GV))
331 ++NumIndirectGlobalVars;
344 bool GlobalsAAResult::AnalyzeUsesOfPointer(
Value *V,
352 User *
I = U.getUser();
353 if (
LoadInst *LI = dyn_cast<LoadInst>(I)) {
355 Readers->
insert(LI->getParent()->getParent());
356 }
else if (
StoreInst *
SI = dyn_cast<StoreInst>(I)) {
357 if (V ==
SI->getOperand(1)) {
359 Writers->
insert(
SI->getParent()->getParent());
360 }
else if (
SI->getOperand(1) != OkayStoreDest) {
364 if (AnalyzeUsesOfPointer(I, Readers, Writers))
367 if (AnalyzeUsesOfPointer(I, Readers, Writers, OkayStoreDest))
369 }
else if (
auto *Call = dyn_cast<CallBase>(I)) {
372 if (Call->isDataOperand(&U)) {
374 if (Call->isArgOperand(&U) &&
isFreeCall(I, &TLI)) {
376 Writers->
insert(Call->getParent()->getParent());
381 }
else if (
ICmpInst *ICI = dyn_cast<ICmpInst>(I)) {
382 if (!isa<ConstantPointerNull>(ICI->getOperand(1)))
384 }
else if (
Constant *
C = dyn_cast<Constant>(I)) {
386 if (isa<GlobalValue>(
C) ||
C->isConstantUsed())
403 bool GlobalsAAResult::AnalyzeIndirectGlobalMemory(
GlobalVariable *GV) {
406 std::vector<Value *> AllocRelatedValues;
410 if (!
C->isNullValue())
416 if (
LoadInst *LI = dyn_cast<LoadInst>(U)) {
420 if (AnalyzeUsesOfPointer(LI))
423 }
else if (
StoreInst *
SI = dyn_cast<StoreInst>(U)) {
425 if (
SI->getOperand(0) == GV)
429 if (isa<ConstantPointerNull>(
SI->getOperand(0)))
441 if (AnalyzeUsesOfPointer(Ptr,
nullptr,
nullptr,
446 AllocRelatedValues.push_back(Ptr);
455 while (!AllocRelatedValues.empty()) {
456 AllocsForIndirectGlobals[AllocRelatedValues.back()] = GV;
457 Handles.emplace_front(*
this, AllocRelatedValues.back());
458 Handles.front().I = Handles.begin();
459 AllocRelatedValues.pop_back();
461 IndirectGlobals.insert(GV);
462 Handles.emplace_front(*
this, GV);
463 Handles.front().I = Handles.begin();
467 void GlobalsAAResult::CollectSCCMembership(
CallGraph &CG) {
472 const std::vector<CallGraphNode *> &SCC = *
I;
473 assert(!SCC.empty() &&
"SCC with no functions?");
475 for (
auto *CGN : SCC)
477 FunctionToSCCMap[F] = SCCID;
490 const std::vector<CallGraphNode *> &SCC = *
I;
491 assert(!SCC.empty() &&
"SCC with no functions?");
495 if (!F || !F->isDefinitionExact()) {
499 for (
auto *Node : SCC)
500 FunctionInfos.erase(Node->getFunction());
505 Handles.emplace_front(*
this, F);
506 Handles.front().I = Handles.begin();
507 bool KnowNothing =
false;
511 for (
unsigned i = 0, e = SCC.size(); i != e && !KnowNothing; ++i) {
519 if (F->doesNotAccessMemory()) {
521 }
else if (F->onlyReadsMemory()) {
523 if (!F->isIntrinsic() && !F->onlyAccessesArgMemory())
531 KnowNothing = !F->isIntrinsic();
537 CI !=
E && !KnowNothing; ++CI)
557 for (
auto *Node : SCC)
558 FunctionInfos.erase(Node->getFunction());
563 for (
auto *Node : SCC) {
579 if (
auto *Call = dyn_cast<CallBase>(&
I)) {
586 if (
Callee->isIntrinsic()) {
587 if (isa<DbgInfoIntrinsic>(Call))
601 if (
I.mayReadFromMemory())
603 if (
I.mayWriteToMemory())
609 ++NumReadMemFunctions;
618 for (
unsigned i = 1, e = SCC.size(); i != e; ++i)
637 if (isa<GlobalValue>(Input) || isa<Argument>(Input) || isa<CallInst>(Input) ||
638 isa<InvokeInst>(Input))
654 if (
auto *LI = dyn_cast<LoadInst>(Input)) {
658 if (
auto *
SI = dyn_cast<SelectInst>(Input)) {
661 if (Visited.
insert(LHS).second)
663 if (Visited.
insert(RHS).second)
667 if (
auto *PN = dyn_cast<PHINode>(Input)) {
668 for (
const Value *
Op : PN->incoming_values()) {
677 }
while (!Inputs.
empty());
708 bool GlobalsAAResult::isNonEscapingGlobalNoAlias(
const GlobalValue *GV,
724 if (
auto *InputGV = dyn_cast<GlobalValue>(Input)) {
734 if (GVar && InputGVar &&
735 !GVar->isDeclaration() && !InputGVar->isDeclaration() &&
736 !GVar->isInterposable() && !InputGVar->isInterposable()) {
737 Type *GVType = GVar->getInitializer()->getType();
738 Type *InputGVType = InputGVar->getInitializer()->getType();
740 (DL.getTypeAllocSize(GVType) > 0) &&
741 (DL.getTypeAllocSize(InputGVType) > 0))
750 if (isa<Argument>(Input) || isa<CallInst>(Input) ||
751 isa<InvokeInst>(Input)) {
765 if (
auto *LI = dyn_cast<LoadInst>(Input)) {
775 if (
auto *
SI = dyn_cast<SelectInst>(Input)) {
778 if (Visited.
insert(LHS).second)
780 if (Visited.
insert(RHS).second)
784 if (
auto *PN = dyn_cast<PHINode>(Input)) {
785 for (
const Value *
Op : PN->incoming_values()) {
800 }
while (!Inputs.
empty());
822 if (GV1 && !NonAddressTakenGlobals.count(GV1))
824 if (GV2 && !NonAddressTakenGlobals.count(GV2))
829 if (GV1 && GV2 && GV1 != GV2)
836 if ((GV1 || GV2) && GV1 != GV2)
841 if ((GV1 || GV2) && GV1 != GV2) {
843 const Value *UV = GV1 ? UV2 : UV1;
844 if (isNonEscapingGlobalNoAlias(GV, UV))
856 if (
const LoadInst *LI = dyn_cast<LoadInst>(UV1))
857 if (
GlobalVariable *GV = dyn_cast<GlobalVariable>(LI->getOperand(0)))
858 if (IndirectGlobals.count(GV))
860 if (
const LoadInst *LI = dyn_cast<LoadInst>(UV2))
861 if (
const GlobalVariable *GV = dyn_cast<GlobalVariable>(LI->getOperand(0)))
862 if (IndirectGlobals.count(GV))
868 GV1 = AllocsForIndirectGlobals.lookup(UV1);
870 GV2 = AllocsForIndirectGlobals.lookup(UV2);
875 if (GV1 && GV2 && GV1 != GV2)
882 if ((GV1 || GV2) && GV1 != GV2)
897 for (
auto &A : Call->
args()) {
907 return ConservativeResult;
910 return ConservativeResult;
927 if (NonAddressTakenGlobals.count(GV))
929 Known =
unionModRef(FI->getModRefInfoForGlobal(*GV),
930 getModRefInfoForArgument(Call, GV));
937 GlobalsAAResult::GlobalsAAResult(
const DataLayout &DL,
943 NonAddressTakenGlobals(
std::move(
Arg.NonAddressTakenGlobals)),
944 IndirectGlobals(
std::move(
Arg.IndirectGlobals)),
945 AllocsForIndirectGlobals(
std::move(
Arg.AllocsForIndirectGlobals)),
946 FunctionInfos(
std::move(
Arg.FunctionInfos)),
947 Handles(
std::move(
Arg.Handles)) {
949 for (
auto &
H : Handles) {
963 Result.CollectSCCMembership(CG);
966 Result.AnalyzeGlobals(M);
969 Result.AnalyzeCallGraph(CG, M);
984 "Globals Alias Analysis",
false,
true)
991 return new GlobalsAAWrapperPass();
1000 M, getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(),
1001 getAnalysis<CallGraphWrapperPass>().getCallGraph())));
Legacy wrapper pass to provide the GlobalsAAResult object.
The access may reference and may modify the value stored in memory.
const Function & getFunction() const
LLVM_NODISCARD ModRefInfo unionModRef(const ModRefInfo MRI1, const ModRefInfo MRI2)
bool hasOperandBundles() const
Return true if this User has any operand bundles.
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()
The access neither references nor modifies the value stored in memory.
bool hasLocalLinkage() const
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
bool doesNotAccessMemory(unsigned OpNo) const
const_iterator begin(StringRef path, Style style=Style::native)
Get begin iterator over path.
void addFunctionInfo(const FunctionInfo &FI)
Add mod/ref info from another function into ours, saturating towards ModRef.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
void setMayReadAnyGlobal()
Sets this function as potentially reading from any global.
const Constant * getInitializer() const
getInitializer - Return the initializer for this global variable.
This class represents lattice values for constants.
globals Globals Alias Analysis
PointerTy getPointer() const
static cl::opt< bool > EnableUnsafeGlobalsModRefAliasResults("enable-unsafe-globalsmodref-alias-results", cl::init(false), cl::Hidden)
FunctionInfo & operator=(const FunctionInfo &RHS)
ModRefInfo getModRefInfoForGlobal(const GlobalValue &GV) const
Returns the ModRefInfo info for this function w.r.t.
This is the interface for a simple mod/ref and alias analysis over globals.
A Module instance is used to store all the information related to an LLVM module. ...
bool isSized(SmallPtrSetImpl< Type *> *Visited=nullptr) const
Return true if it makes sense to take the size of this type.
void push_back(const T &Elt)
The two locations do not alias at all.
FunctionInfo & operator=(FunctionInfo &&RHS)
FunctionModRefBehavior getModRefBehavior(const CallBase *Call)
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly...
STATISTIC(NumFunctions, "Total number of functions")
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
block Block Frequency true
An instruction for reading from memory.
A node in the call graph for a module.
LLVM_NODISCARD bool isModAndRefSet(const ModRefInfo MRI)
The mod/ref information collected for a particular function.
ModRefInfo globalClearMayReadAnyGlobal(int I) const
This method clears MayReadAnyGlobal bit added by GlobalsAAResult to return the corresponding ModRefIn...
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...
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)
const DataLayout & getDataLayout() const
Get the data layout for the module's target platform.
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 may reference the value stored in memory.
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)
Type * getType() const
All values are typed, get the type of this value.
bool runOnModule(Module &M) override
runOnModule - Virtual method overriden by subclasses to process the module being operated on...
GlobalsAAResult run(Module &M, ModuleAnalysisManager &AM)
The access may reference, modify or both the value stored in memory, a mustAlias relation was found...
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)
ModRefInfo getModRefInfo() const
Returns the ModRefInfo info for this function.
static Function * getFunction(Constant *C)
amdgpu Simplify well known AMD library false Value * Callee
Analysis containing CSE Info
AliasResult
The possible results of an alias query.
initializer< Ty > init(const Ty &Val)
LLVM_NODISCARD ModRefInfo setMust(const ModRefInfo MRI)
The ModulePass which wraps up a CallGraph and the logic to build it.
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.
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This is an important base class in LLVM.
bool isPointerTy() const
True if this is an instance of PointerType.
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.
Represent the analysis usage information of a pass.
This instruction compares its operands according to the predicate given to the constructor.
iterator_range< User::op_iterator > args()
Iteration adapter for range-for loops.
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...
INITIALIZE_PASS_END(RegBankSelect, DEBUG_TYPE, "Assign register bank of generic virtual registers", false, false) RegBankSelect
This function does not perform any non-local loads or stores to memory.
void initializeGlobalsAAWrapperPassPass(PassRegistry &)
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...
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.
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...
The access may modify the value stored in memory.
void setPreservesAll()
Set by analyses that do not transform their input at all.
iterator_range< user_iterator > users()
amdgpu Simplify well known AMD library false Value Value * Arg
An analysis pass to compute the CallGraph for a Module.
LLVM_NODISCARD bool isModSet(const ModRefInfo MRI)
The basic data container for the call graph of a Module of IR.
LLVM_NODISCARD bool empty() const
FunctionInfo()
Checks to document the invariants of the bit packing here.
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation.
ModulePass * createGlobalsAAWrapperPass()
LLVM_NODISCARD ModRefInfo intersectModRef(const ModRefInfo MRI1, const ModRefInfo MRI2)
bool onlyReadsMemory(unsigned OpNo) const
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...
INITIALIZE_PASS_BEGIN(GlobalsAAWrapperPass, "globals-aa", "Globals Alias Analysis", false, true) INITIALIZE_PASS_END(GlobalsAAWrapperPass
LLVM_NODISCARD std::enable_if<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type >::type dyn_cast(const Y &Val)
std::vector< CallRecord >::iterator iterator
Analysis pass providing the TargetLibraryInfo.
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...
ModRefInfo getModRefInfo(const CallBase *Call, const MemoryLocation &Loc)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Module * getParent()
Get the module that this global value is contained inside of...
LLVM Value Representation.
unsigned getOpcode() const
Return the opcode for this Instruction or ConstantExpr.
LLVM_NODISCARD ModRefInfo createModRefInfo(const FunctionModRefBehavior FMRB)
ModRefInfo
Flags indicating whether a memory access modifies or references memory.
inst_range instructions(Function *F)
A container for analyses that lazily runs them and caches their results.
LLVM_NODISCARD bool isModOrRefSet(const ModRefInfo MRI)
A special type used by analysis passes to provide an address that identifies that particular analysis...
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.
ModRefInfo getModRefInfo(const CallBase *Call, const MemoryLocation &Loc)
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...