diff options
| author | James Molloy <james.molloy@arm.com> | 2015-10-22 13:44:26 +0000 |
|---|---|---|
| committer | James Molloy <james.molloy@arm.com> | 2015-10-22 13:44:26 +0000 |
| commit | 5b2a732fac0cfaf28adcfe5cab5d2e8d35a7434f (patch) | |
| tree | 9fc52dc882d70f91efe9ac1fa9e08caf8e393915 /llvm/lib/Analysis/GlobalsModRef.cpp | |
| parent | 5a4d8cd5190ff52027f93417ed120e6da75fa1cd (diff) | |
| download | bcm5719-llvm-5b2a732fac0cfaf28adcfe5cab5d2e8d35a7434f.tar.gz bcm5719-llvm-5b2a732fac0cfaf28adcfe5cab5d2e8d35a7434f.zip | |
[GlobalsAA] Loosen an overly conservative bailout
Instead of bailing out when we see loads, analyze them. If we can prove that the loaded-from address must escape, then we can conclude that a load from that address must escape too and therefore cannot alias a non-addr-taken global.
When checking if a Value can alias a non-addr-taken global, if the Value is a LoadInst of a non-global, recurse instead of bailing.
If we can follow a trail of loads up to some base that is captured, we know by inference that all the loads we followed are also captured.
llvm-svn: 251017
Diffstat (limited to 'llvm/lib/Analysis/GlobalsModRef.cpp')
| -rw-r--r-- | llvm/lib/Analysis/GlobalsModRef.cpp | 80 |
1 files changed, 71 insertions, 9 deletions
diff --git a/llvm/lib/Analysis/GlobalsModRef.cpp b/llvm/lib/Analysis/GlobalsModRef.cpp index 979e2de0fcf..3b808e371db 100644 --- a/llvm/lib/Analysis/GlobalsModRef.cpp +++ b/llvm/lib/Analysis/GlobalsModRef.cpp @@ -595,6 +595,66 @@ void GlobalsAAResult::AnalyzeCallGraph(CallGraph &CG, Module &M) { } } +// GV is a non-escaping global. V is a pointer address that has been loaded from. +// If we can prove that V must escape, we can conclude that a load from V cannot +// alias GV. +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)) + // Arguments to functions or returns from functions are inherently + // escaping, so we can immediately classify those as not aliasing any + // non-addr-taken globals. + // + // (Transitive) loads from a global are also safe - if this aliased + // another global, its address would escape, so no alias. + continue; + + // Recurse through a limited number of selects, loads and PHIs. This is an + // arbitrary depth of 4, lower numbers could be used to fix compile time + // issues if needed, but this is generally expected to be only be important + // for small depths. + 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()); + + // All inputs were known to be no-alias. + return true; +} + // There are particular cases where we can conclude no-alias between // a non-addr-taken global and some other underlying object. Specifically, // a non-addr-taken global is known to not be escaped from any function. It is @@ -669,22 +729,24 @@ bool GlobalsAAResult::isNonEscapingGlobalNoAlias(const GlobalValue *GV, // non-addr-taken globals. continue; } + + // Recurse through a limited number of selects, loads and PHIs. This is an + // arbitrary depth of 4, lower numbers could be used to fix compile time + // issues if needed, but this is generally expected to be only be important + // for small depths. + if (++Depth > 4) + return false; + if (auto *LI = dyn_cast<LoadInst>(Input)) { // A pointer loaded from a global would have been captured, and we know // that the global is non-escaping, so no alias. - if (isa<GlobalValue>(GetUnderlyingObject(LI->getPointerOperand(), DL))) + const Value *Ptr = GetUnderlyingObject(LI->getPointerOperand(), DL); + if (isNonEscapingGlobalNoAliasWithLoad(GV, Ptr, Depth, DL)) + // The load does not alias with GV. continue; - // Otherwise, a load could come from anywhere, so bail. return false; } - - // Recurse through a limited number of selects and PHIs. This is an - // arbitrary depth of 4, lower numbers could be used to fix compile time - // issues if needed, but this is generally expected to be only be important - // for small depths. - if (++Depth > 4) - return false; if (auto *SI = dyn_cast<SelectInst>(Input)) { const Value *LHS = GetUnderlyingObject(SI->getTrueValue(), DL); const Value *RHS = GetUnderlyingObject(SI->getFalseValue(), DL); |

