[globals-aa] Improved isNonEscapingGlobalNoAlias. (#127707)

A non-escaping global should never alias with non-pointer values
and `ptr null`. This should improve disambiguation of global
pointers with relation to Flang runtime calls (given that
`nosync nocallback` attributes are properly set).
It also seems to be an obvious improvement with little overhead.
This commit is contained in:
Slava Zakharin 2025-02-19 17:09:29 -08:00 committed by GitHub
parent 19bad2ac4a
commit 75bd46e01f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 42 additions and 5 deletions

View File

@ -118,7 +118,8 @@ private:
bool AnalyzeIndirectGlobalMemory(GlobalVariable *GV);
void CollectSCCMembership(CallGraph &CG);
bool isNonEscapingGlobalNoAlias(const GlobalValue *GV, const Value *V);
bool isNonEscapingGlobalNoAlias(const GlobalValue *GV, const Value *V,
const Instruction *CtxI);
ModRefInfo getModRefInfoForArgument(const CallBase *Call,
const GlobalValue *GV, AAQueryInfo &AAQI);
};

View File

@ -713,13 +713,20 @@ static bool isNonEscapingGlobalNoAliasWithLoad(const GlobalValue *GV,
// active, or to be forced to operate as a module pass that cannot co-exist
// with an alias analysis such as GMR.
bool GlobalsAAResult::isNonEscapingGlobalNoAlias(const GlobalValue *GV,
const Value *V) {
const Value *V,
const Instruction *CtxI) {
// In order to know that the underlying object cannot alias the
// non-addr-taken global, we must know that it would have to be an escape.
// Thus if the underlying object is a function argument, a load from
// a global, or the return of a function, it cannot alias. We can also
// recurse through PHI nodes and select nodes provided all of their inputs
// resolve to one of these known-escaping roots.
// A non-addr-taken global cannot alias with any non-pointer value.
// Check this early and exit.
if (!V->getType()->isPointerTy())
return true;
SmallPtrSet<const Value *, 8> Visited;
SmallVector<const Value *, 8> Inputs;
Visited.insert(V);
@ -762,6 +769,14 @@ bool GlobalsAAResult::isNonEscapingGlobalNoAlias(const GlobalValue *GV,
continue;
}
if (CtxI)
if (auto *CPN = dyn_cast<ConstantPointerNull>(Input)) {
// Null pointer cannot alias with a non-addr-taken global.
const Function *F = CtxI->getFunction();
if (!NullPointerIsDefined(F, CPN->getType()->getAddressSpace()))
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
@ -820,7 +835,7 @@ bool GlobalsAAResult::invalidate(Module &, const PreservedAnalyses &PA,
/// address of the global isn't taken.
AliasResult GlobalsAAResult::alias(const MemoryLocation &LocA,
const MemoryLocation &LocB,
AAQueryInfo &AAQI, const Instruction *) {
AAQueryInfo &AAQI, const Instruction *CtxI) {
// Get the base object these pointers point to.
const Value *UV1 =
getUnderlyingObject(LocA.Ptr->stripPointerCastsForAliasAnalysis());
@ -856,7 +871,7 @@ AliasResult GlobalsAAResult::alias(const MemoryLocation &LocA,
if ((GV1 || GV2) && GV1 != GV2) {
const GlobalValue *GV = GV1 ? GV1 : GV2;
const Value *UV = GV1 ? UV2 : UV1;
if (isNonEscapingGlobalNoAlias(GV, UV))
if (isNonEscapingGlobalNoAlias(GV, UV, CtxI))
return AliasResult::NoAlias;
}
@ -920,7 +935,7 @@ ModRefInfo GlobalsAAResult::getModRefInfoForArgument(const CallBase *Call,
!all_of(Objects, [&](const Value *V) {
return this->alias(MemoryLocation::getBeforeOrAfter(V),
MemoryLocation::getBeforeOrAfter(GV), AAQI,
nullptr) == AliasResult::NoAlias;
Call) == AliasResult::NoAlias;
}))
return ConservativeResult;

View File

@ -175,3 +175,24 @@ entry:
%v = load i32, ptr @g1
ret i32 %v
}
define i32 @test6(ptr %param) {
; Ensure that we can fold a store to a load of a global across a set of
; calls that cannot use in any way a non-escaping global.
;
; CHECK-LABEL: @test6(
; CHECK: store i32 42, ptr @g1
; CHECK-NOT: load i32
; CHECK: ret i32 42
entry:
store i32 42, ptr @g1
%1 = call ptr @_FortranAioBeginExternalFormattedOutput(ptr null, i64 3, ptr null, i32 6, ptr null, i32 2)
%2 = call i1 @_FortranAioOutputAscii(ptr %1, ptr null, i64 4)
%3 = call i32 @_FortranAioEndIoStatement(ptr %1)
%v = load i32, ptr @g1
ret i32 %v
}
declare ptr @_FortranAioBeginExternalFormattedOutput(ptr, i64, ptr, i32, ptr, i32) #0
declare zeroext i1 @_FortranAioOutputAscii(ptr, ptr, i64) #0
declare i32 @_FortranAioEndIoStatement(ptr) #0
attributes #0 = { nocallback nosync }