[llvm] ab25ea6 - [AA] Model operand bundles more precisely
Nikita Popov via llvm-commits
llvm-commits at lists.llvm.org
Thu Sep 22 02:15:33 PDT 2022
Author: Nikita Popov
Date: 2022-09-22T11:15:20+02:00
New Revision: ab25ea6d357e0446bc53cbc6a7372fc79f24740d
URL: https://github.com/llvm/llvm-project/commit/ab25ea6d357e0446bc53cbc6a7372fc79f24740d
DIFF: https://github.com/llvm/llvm-project/commit/ab25ea6d357e0446bc53cbc6a7372fc79f24740d.diff
LOG: [AA] Model operand bundles more precisely
Based on D130896, we can model operand bundles more precisely. In
addition to the baseline ModRefBehavior, a reading/clobbering operand
bundle may also read/write all locations. For example, a memcpy with
deopt bundle can read any memory, but only write argument memory.
This means that getModRefInfo() for memcpy with a pointer that does
not alias the arguments results in Ref, rather than ModRef, without
the need to implement any special handling.
Differential Revision: https://reviews.llvm.org/D130980
Added:
Modified:
llvm/lib/Analysis/AliasAnalysis.cpp
llvm/lib/Analysis/BasicAliasAnalysis.cpp
llvm/test/Feature/OperandBundles/basic-aa-argmemonly.ll
Removed:
################################################################################
diff --git a/llvm/lib/Analysis/AliasAnalysis.cpp b/llvm/lib/Analysis/AliasAnalysis.cpp
index 85d17d0ba3a67..2a2b49fdf7e42 100644
--- a/llvm/lib/Analysis/AliasAnalysis.cpp
+++ b/llvm/lib/Analysis/AliasAnalysis.cpp
@@ -235,35 +235,37 @@ ModRefInfo AAResults::getModRefInfo(const CallBase *Call,
// Try to refine the mod-ref info further using other API entry points to the
// aggregate set of AA results.
- auto MRB = getModRefBehavior(Call);
- if (MRB.onlyAccessesInaccessibleMem())
- return ModRefInfo::NoModRef;
- // TODO: Exclude inaccessible memory location here.
- Result &= MRB.getModRef();
+ // We can completely ignore inaccessible memory here, because MemoryLocations
+ // can only reference accessible memory.
+ auto MRB = getModRefBehavior(Call).getWithoutLoc(
+ FunctionModRefBehavior::InaccessibleMem);
+ if (MRB.doesNotAccessMemory())
+ return ModRefInfo::NoModRef;
- if (MRB.onlyAccessesArgPointees() || MRB.onlyAccessesInaccessibleOrArgMem()) {
+ ModRefInfo ArgMR = MRB.getModRef(FunctionModRefBehavior::ArgMem);
+ ModRefInfo OtherMR =
+ MRB.getWithoutLoc(FunctionModRefBehavior::ArgMem).getModRef();
+ if ((ArgMR | OtherMR) != OtherMR) {
+ // Refine the modref info for argument memory. We only bother to do this
+ // if ArgMR is not a subset of OtherMR, otherwise this won't have an impact
+ // on the final result.
ModRefInfo AllArgsMask = ModRefInfo::NoModRef;
- if (MRB.doesAccessArgPointees()) {
- for (const auto &I : llvm::enumerate(Call->args())) {
- const Value *Arg = I.value();
- if (!Arg->getType()->isPointerTy())
- continue;
- unsigned ArgIdx = I.index();
- MemoryLocation ArgLoc =
- MemoryLocation::getForArgument(Call, ArgIdx, TLI);
- AliasResult ArgAlias = alias(ArgLoc, Loc, AAQI);
- if (ArgAlias != AliasResult::NoAlias)
- AllArgsMask |= getArgModRefInfo(Call, ArgIdx);
- }
+ for (const auto &I : llvm::enumerate(Call->args())) {
+ const Value *Arg = I.value();
+ if (!Arg->getType()->isPointerTy())
+ continue;
+ unsigned ArgIdx = I.index();
+ MemoryLocation ArgLoc = MemoryLocation::getForArgument(Call, ArgIdx, TLI);
+ AliasResult ArgAlias = alias(ArgLoc, Loc, AAQI);
+ if (ArgAlias != AliasResult::NoAlias)
+ AllArgsMask |= getArgModRefInfo(Call, ArgIdx);
}
- // Return NoModRef if no alias found with any argument.
- if (isNoModRef(AllArgsMask))
- return ModRefInfo::NoModRef;
- // Logical & between other AA analyses and argument analysis.
- Result &= AllArgsMask;
+ ArgMR &= AllArgsMask;
}
+ Result &= ArgMR | OtherMR;
+
// If Loc is a constant memory location, the call definitely could not
// modify the memory location.
if (isModSet(Result) && pointsToConstantMemory(Loc, AAQI, /*OrLocal*/ false))
diff --git a/llvm/lib/Analysis/BasicAliasAnalysis.cpp b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
index 965a1faf85be2..c0e373f38b429 100644
--- a/llvm/lib/Analysis/BasicAliasAnalysis.cpp
+++ b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
@@ -769,12 +769,16 @@ FunctionModRefBehavior BasicAAResult::getModRefBehavior(const CallBase *Call) {
else if (Call->onlyAccessesInaccessibleMemOrArgMem())
Min = FunctionModRefBehavior::inaccessibleOrArgMemOnly(MR);
- // If the call has operand bundles then aliasing attributes from the function
- // it calls do not directly apply to the call. This can be made more precise
- // in the future.
- if (!Call->hasOperandBundles())
- if (const Function *F = Call->getCalledFunction())
- Min &= getBestAAResults().getModRefBehavior(F);
+ if (const Function *F = Call->getCalledFunction()) {
+ FunctionModRefBehavior FMRB = getBestAAResults().getModRefBehavior(F);
+ // Operand bundles on the call may also read or write memory, in addition
+ // to the behavior of the called function.
+ if (Call->hasReadingOperandBundles())
+ FMRB |= FunctionModRefBehavior::readOnly();
+ if (Call->hasClobberingOperandBundles())
+ FMRB |= FunctionModRefBehavior::writeOnly();
+ Min &= FMRB;
+ }
return Min;
}
@@ -976,26 +980,6 @@ ModRefInfo BasicAAResult::getModRefInfo(const CallBase *Call,
return ModRefInfo::NoModRef;
}
- // Ideally, there should be no need to special case for memcpy/memove
- // intrinsics here since general machinery (based on memory attributes) should
- // already handle it just fine. Unfortunately, it doesn't due to deficiency in
- // operand bundles support. At the moment it's not clear if complexity behind
- // enhancing general mechanism worths it.
- // TODO: Consider improving operand bundles support in general mechanism.
- if (auto *Inst = dyn_cast<AnyMemTransferInst>(Call)) {
- AliasResult SrcAA =
- getBestAAResults().alias(MemoryLocation::getForSource(Inst), Loc, AAQI);
- AliasResult DestAA =
- getBestAAResults().alias(MemoryLocation::getForDest(Inst), Loc, AAQI);
- // It's also possible for Loc to alias both src and dest, or neither.
- ModRefInfo rv = ModRefInfo::NoModRef;
- if (SrcAA != AliasResult::NoAlias || Call->hasReadingOperandBundles())
- rv |= ModRefInfo::Ref;
- if (DestAA != AliasResult::NoAlias || Call->hasClobberingOperandBundles())
- rv |= ModRefInfo::Mod;
- return rv;
- }
-
// Guard intrinsics are marked as arbitrarily writing so that proper control
// dependencies are maintained but they never mods any particular memory
// location.
diff --git a/llvm/test/Feature/OperandBundles/basic-aa-argmemonly.ll b/llvm/test/Feature/OperandBundles/basic-aa-argmemonly.ll
index 7b1ba1fd79c75..1c58838ade33e 100644
--- a/llvm/test/Feature/OperandBundles/basic-aa-argmemonly.ll
+++ b/llvm/test/Feature/OperandBundles/basic-aa-argmemonly.ll
@@ -33,19 +33,14 @@ define i32 @test2(i32* %P, i32* noalias %P2) {
; heap, but they don't write to any location in the heap if the callee does not
; deoptimize the caller. This fact, combined with the fact that
; @argmemonly_function is, well, an argmemonly function, can be used to conclude
-; that %P is not written to at the callsite. However LLVM currently cannot
-; describe the "does not write to non-args, and reads the entire heap" effect on
-; a callsite.
+; that %P is not written to at the callsite.
; CHECK-LABEL: @test2(
%v1 = load i32, i32* %P
-; CHECK: %v1 = load i32, i32* %P
call void @argmemonly_function(i32* %P2) [ "deopt"() ]
; CHECK: call void @argmemonly_function(
%v2 = load i32, i32* %P
-; CHECK: %v2 = load i32, i32* %P
%
diff = sub i32 %v1, %v2
-; CHECK: %
diff = sub i32 %v1, %v2
ret i32 %
diff
-; CHECK: ret i32 %
diff
+; CHECK: ret i32 0
}
More information about the llvm-commits
mailing list