Index: lib/Analysis/GlobalsModRef.cpp =================================================================== --- lib/Analysis/GlobalsModRef.cpp +++ lib/Analysis/GlobalsModRef.cpp @@ -592,6 +592,67 @@ } } +// 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 Visited; + SmallVector Inputs; + Visited.insert(V); + Inputs.push_back(V); + do { + const Value *Input = Inputs.pop_back_val(); + + if (isa(Input)) + // This is a load (transitively) from a global. If this aliased another global, + // its address would escape, so no alias. + continue; + if (isa(Input) || isa(Input) || isa(Input) || + isa(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. + 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(Input)) { + Inputs.push_back(GetUnderlyingObject(LI->getPointerOperand(), DL)); + continue; + } + if (auto *SI = dyn_cast(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(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 @@ -666,22 +727,28 @@ // 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(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(GetUnderlyingObject(LI->getPointerOperand(), DL))) + const Value *Ptr = GetUnderlyingObject(LI->getPointerOperand(), DL); + if (isa(Ptr)) continue; - // Otherwise, a load could come from anywhere, so bail. - return false; + if (isNonEscapingGlobalNoAliasWithLoad(GV, Ptr, Depth, DL)) { + // The load does not alias with GV. + continue; + } else { + // 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(Input)) { const Value *LHS = GetUnderlyingObject(SI->getTrueValue(), DL); const Value *RHS = GetUnderlyingObject(SI->getFalseValue(), DL); Index: test/Analysis/GlobalsModRef/nonescaping-noalias.ll =================================================================== --- test/Analysis/GlobalsModRef/nonescaping-noalias.ll +++ test/Analysis/GlobalsModRef/nonescaping-noalias.ll @@ -97,3 +97,20 @@ %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 +}