mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-26 04:32:44 +01:00
[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
This commit is contained in:
parent
a87ba0206e
commit
ee690e2eb4
@ -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;
|
||||
}
|
||||
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)))
|
||||
continue;
|
||||
|
||||
// Otherwise, a load could come from anywhere, so bail.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Recurse through a limited number of selects and PHIs. This is an
|
||||
// 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.
|
||||
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;
|
||||
}
|
||||
if (auto *SI = dyn_cast<SelectInst>(Input)) {
|
||||
const Value *LHS = GetUnderlyingObject(SI->getTrueValue(), DL);
|
||||
const Value *RHS = GetUnderlyingObject(SI->getFalseValue(), DL);
|
||||
|
@ -97,3 +97,20 @@ exit:
|
||||
%v = load i32, i32* @g1
|
||||
ret i32 %v
|
||||
}
|
||||
|
||||
define i32 @test5(i32** %param) {
|
||||
; Ensure that we can fold a store to a load of a global across a store to
|
||||
; a parameter that has been dereferenced when the global is non-escaping.
|
||||
;
|
||||
; CHECK-LABEL: @test5(
|
||||
; CHECK: %p = load i32*
|
||||
; CHECK: store i32 42, i32* @g1
|
||||
; CHECK-NOT: load i32
|
||||
; CHECK: ret i32 42
|
||||
entry:
|
||||
%p = load i32*, i32** %param
|
||||
store i32 42, i32* @g1
|
||||
store i32 7, i32* %p
|
||||
%v = load i32, i32* @g1
|
||||
ret i32 %v
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user