Skip to content

Commit 38e8dff

Browse files
authored
[AA][BasicAA] Move more call logic to BasicAA (#131144)
Currently, the handling for calls is split between AA and BasicAA in an awkward way. BasicAA does argument alias analysis for non-escaping objects (but without considering MemoryEffects), while AA handles the generic case using MemoryEffects. However, fundamentally, both of these are really trying to do the same thing. The new merged logic first tries to remove the OtherMR component of the memory effects, which includes accesses to escaped memory. If a function-local object does not escape, OtherMR can be set to NoModRef. Then we perform the argument scan in basically the same way as AA previously did. However, we also need to look at the operand bundles. To support that, I've adjusted getArgModRefInfo to accept operand bundle arguments.
1 parent 67a0113 commit 38e8dff

File tree

3 files changed

+49
-89
lines changed

3 files changed

+49
-89
lines changed

llvm/lib/Analysis/AliasAnalysis.cpp

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -220,38 +220,6 @@ ModRefInfo AAResults::getModRefInfo(const CallBase *Call,
220220
return ModRefInfo::NoModRef;
221221
}
222222

223-
// Try to refine the mod-ref info further using other API entry points to the
224-
// aggregate set of AA results.
225-
226-
// We can completely ignore inaccessible memory here, because MemoryLocations
227-
// can only reference accessible memory.
228-
auto ME = getMemoryEffects(Call, AAQI)
229-
.getWithoutLoc(IRMemLocation::InaccessibleMem);
230-
if (ME.doesNotAccessMemory())
231-
return ModRefInfo::NoModRef;
232-
233-
ModRefInfo ArgMR = ME.getModRef(IRMemLocation::ArgMem);
234-
ModRefInfo OtherMR = ME.getWithoutLoc(IRMemLocation::ArgMem).getModRef();
235-
if ((ArgMR | OtherMR) != OtherMR) {
236-
// Refine the modref info for argument memory. We only bother to do this
237-
// if ArgMR is not a subset of OtherMR, otherwise this won't have an impact
238-
// on the final result.
239-
ModRefInfo AllArgsMask = ModRefInfo::NoModRef;
240-
for (const auto &I : llvm::enumerate(Call->args())) {
241-
const Value *Arg = I.value();
242-
if (!Arg->getType()->isPointerTy())
243-
continue;
244-
unsigned ArgIdx = I.index();
245-
MemoryLocation ArgLoc = MemoryLocation::getForArgument(Call, ArgIdx, TLI);
246-
AliasResult ArgAlias = alias(ArgLoc, Loc, AAQI, Call);
247-
if (ArgAlias != AliasResult::NoAlias)
248-
AllArgsMask |= getArgModRefInfo(Call, ArgIdx);
249-
}
250-
ArgMR &= AllArgsMask;
251-
}
252-
253-
Result &= ArgMR | OtherMR;
254-
255223
// Apply the ModRef mask. This ensures that if Loc is a constant memory
256224
// location, we take into account the fact that the call definitely could not
257225
// modify the memory location.

llvm/lib/Analysis/BasicAliasAnalysis.cpp

Lines changed: 48 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -847,15 +847,15 @@ MemoryEffects BasicAAResult::getMemoryEffects(const Function *F) {
847847

848848
ModRefInfo BasicAAResult::getArgModRefInfo(const CallBase *Call,
849849
unsigned ArgIdx) {
850-
if (Call->paramHasAttr(ArgIdx, Attribute::WriteOnly))
850+
if (Call->doesNotAccessMemory(ArgIdx))
851+
return ModRefInfo::NoModRef;
852+
853+
if (Call->onlyWritesMemory(ArgIdx))
851854
return ModRefInfo::Mod;
852855

853-
if (Call->paramHasAttr(ArgIdx, Attribute::ReadOnly))
856+
if (Call->onlyReadsMemory(ArgIdx))
854857
return ModRefInfo::Ref;
855858

856-
if (Call->paramHasAttr(ArgIdx, Attribute::ReadNone))
857-
return ModRefInfo::NoModRef;
858-
859859
return ModRefInfo::ModRef;
860860
}
861861

@@ -921,66 +921,58 @@ ModRefInfo BasicAAResult::getModRefInfo(const CallBase *Call,
921921
if (!AI->isStaticAlloca() && isIntrinsicCall(Call, Intrinsic::stackrestore))
922922
return ModRefInfo::Mod;
923923

924-
// A call can access a locally allocated object either because it is passed as
925-
// an argument to the call, or because it has escaped prior to the call.
926-
//
927-
// Make sure the object has not escaped here, and then check that none of the
928-
// call arguments alias the object below.
924+
// We can completely ignore inaccessible memory here, because MemoryLocations
925+
// can only reference accessible memory.
926+
auto ME = AAQI.AAR.getMemoryEffects(Call, AAQI)
927+
.getWithoutLoc(IRMemLocation::InaccessibleMem);
928+
if (ME.doesNotAccessMemory())
929+
return ModRefInfo::NoModRef;
930+
931+
ModRefInfo ArgMR = ME.getModRef(IRMemLocation::ArgMem);
932+
ModRefInfo OtherMR = ME.getWithoutLoc(IRMemLocation::ArgMem).getModRef();
933+
934+
// An identified function-local object that does not escape can only be
935+
// accessed via call arguments. Reduce OtherMR (which includes accesses to
936+
// escaped memory) based on that.
929937
//
930938
// We model calls that can return twice (setjmp) as clobbering non-escaping
931939
// objects, to model any accesses that may occur prior to the second return.
932940
// As an exception, ignore allocas, as setjmp is not required to preserve
933941
// non-volatile stores for them.
934-
if (!isa<Constant>(Object) && Call != Object &&
935-
AAQI.CA->isNotCapturedBefore(Object, Call, /*OrAt*/ false) &&
936-
(isa<AllocaInst>(Object) || !Call->hasFnAttr(Attribute::ReturnsTwice))) {
937-
938-
// Optimistically assume that call doesn't touch Object and check this
939-
// assumption in the following loop.
940-
ModRefInfo Result = ModRefInfo::NoModRef;
941-
942-
unsigned OperandNo = 0;
943-
for (auto CI = Call->data_operands_begin(), CE = Call->data_operands_end();
944-
CI != CE; ++CI, ++OperandNo) {
945-
if (!(*CI)->getType()->isPointerTy())
946-
continue;
947-
948-
// Call doesn't access memory through this operand, so we don't care
949-
// if it aliases with Object.
950-
if (Call->doesNotAccessMemory(OperandNo))
951-
continue;
952-
953-
// If this is a no-capture pointer argument, see if we can tell that it
954-
// is impossible to alias the pointer we're checking.
955-
AliasResult AR =
956-
AAQI.AAR.alias(MemoryLocation::getBeforeOrAfter(*CI),
957-
MemoryLocation::getBeforeOrAfter(Object), AAQI);
958-
// Operand doesn't alias 'Object', continue looking for other aliases
959-
if (AR == AliasResult::NoAlias)
942+
if (isModOrRefSet(OtherMR) && !isa<Constant>(Object) && Call != Object &&
943+
AAQI.CA->isNotCapturedBefore(Object, Call, /*OrAt=*/false) &&
944+
(isa<AllocaInst>(Object) || !Call->hasFnAttr(Attribute::ReturnsTwice)))
945+
OtherMR = ModRefInfo::NoModRef;
946+
947+
// Refine the modref info for argument memory. We only bother to do this
948+
// if ArgMR is not a subset of OtherMR, otherwise this won't have an impact
949+
// on the final result.
950+
if ((ArgMR | OtherMR) != OtherMR) {
951+
ModRefInfo NewArgMR = ModRefInfo::NoModRef;
952+
for (const Use &U : Call->data_ops()) {
953+
const Value *Arg = U;
954+
if (!Arg->getType()->isPointerTy())
960955
continue;
961-
// Operand aliases 'Object', but call doesn't modify it. Strengthen
962-
// initial assumption and keep looking in case if there are more aliases.
963-
if (Call->onlyReadsMemory(OperandNo)) {
964-
Result |= ModRefInfo::Ref;
965-
continue;
966-
}
967-
// Operand aliases 'Object' but call only writes into it.
968-
if (Call->onlyWritesMemory(OperandNo)) {
969-
Result |= ModRefInfo::Mod;
970-
continue;
971-
}
972-
// This operand aliases 'Object' and call reads and writes into it.
973-
// Setting ModRef will not yield an early return below, MustAlias is not
974-
// used further.
975-
Result = ModRefInfo::ModRef;
976-
break;
956+
unsigned ArgIdx = Call->getDataOperandNo(&U);
957+
MemoryLocation ArgLoc =
958+
Call->isArgOperand(&U)
959+
? MemoryLocation::getForArgument(Call, ArgIdx, TLI)
960+
: MemoryLocation::getBeforeOrAfter(Arg);
961+
AliasResult ArgAlias = AAQI.AAR.alias(ArgLoc, Loc, AAQI, Call);
962+
if (ArgAlias != AliasResult::NoAlias)
963+
NewArgMR |= ArgMR & AAQI.AAR.getArgModRefInfo(Call, ArgIdx);
964+
965+
// Exit early if we cannot improve over the original ArgMR.
966+
if (NewArgMR == ArgMR)
967+
break;
977968
}
978-
979-
// Early return if we improved mod ref information
980-
if (!isModAndRefSet(Result))
981-
return Result;
969+
ArgMR = NewArgMR;
982970
}
983971

972+
ModRefInfo Result = ArgMR | OtherMR;
973+
if (!isModAndRefSet(Result))
974+
return Result;
975+
984976
// If the call is malloc/calloc like, we can assume that it doesn't
985977
// modify any IR visible value. This is only valid because we assume these
986978
// routines do not read values visible in the IR. TODO: Consider special

llvm/test/Analysis/BasicAA/call.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
declare void @callee(ptr)
44

55
; CHECK-LABEL: Function: test
6-
; CHECK: Both ModRef: Ptr: i32* %a.gep <-> call void @callee(ptr %gep)
6+
; CHECK: NoModRef: Ptr: i32* %a.gep <-> call void @callee(ptr %gep)
77
define void @test(i1 %c, ptr %arg) {
88
%a = alloca [2 x i32]
99
%a.gep = getelementptr i8, ptr %a, i64 4

0 commit comments

Comments
 (0)