Skip to content

Commit efaeaac

Browse files
committed
[ArgPromotion] Perform alias analysis on actual arguments of Calls
Teach Argument Promotion to perform alias analysis on actual arguments of Calls to a Function, to try to prove that all Calls to the Function do not modify the memory pointed to by an argument. This surfaces more opportunities to perform Argument Promotion in cases where simply looking at a Function's instructions is insufficient to prove that the pointer argument is not invalidated before all loads from it.
1 parent 974d8f6 commit efaeaac

File tree

2 files changed

+60
-23
lines changed

2 files changed

+60
-23
lines changed

llvm/lib/Transforms/IPO/ArgumentPromotion.cpp

Lines changed: 48 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -474,7 +474,8 @@ static bool allCallersPassValidPointerForArgument(
474474
/// parts it can be promoted into.
475475
static bool findArgParts(Argument *Arg, const DataLayout &DL, AAResults &AAR,
476476
unsigned MaxElements, bool IsRecursive,
477-
SmallVectorImpl<OffsetAndArgPart> &ArgPartsVec) {
477+
SmallVectorImpl<OffsetAndArgPart> &ArgPartsVec,
478+
bool ArgNotModified) {
478479
// Quick exit for unused arguments
479480
if (Arg->use_empty())
480481
return true;
@@ -696,8 +697,10 @@ static bool findArgParts(Argument *Arg, const DataLayout &DL, AAResults &AAR,
696697

697698
// If store instructions are allowed, the path from the entry of the function
698699
// to each load may be not free of instructions that potentially invalidate
699-
// the load, and this is an admissible situation.
700-
if (AreStoresAllowed)
700+
// the load, and this is an admissible situation. If we have already
701+
// determined that the pointer Arg is not modified in the function (for all
702+
// Calls) then we can similarly conclude analysis here.
703+
if (AreStoresAllowed || ArgNotModified)
701704
return true;
702705

703706
// Okay, now we know that the argument is only used by load instructions, and
@@ -745,6 +748,33 @@ static bool areTypesABICompatible(ArrayRef<Type *> Types, const Function &F,
745748
});
746749
}
747750

751+
// Try to prove that all Calls to F do not modify the memory pointed to by Arg.
752+
// This can provide us with more opportunities to perform Argument Promotion in
753+
// cases where simply looking at a Function's instructions is insufficient to
754+
// prove that the pointer argument is not invalidated before all loads from it.
755+
static bool callDoesNotModifyArg(Function *F, unsigned ArgNo,
756+
FunctionAnalysisManager &FAM) {
757+
// Find all Users of F that are Calls, and see if they may modify Arg.
758+
for (User *U : F->users()) {
759+
auto *Call = dyn_cast<CallInst>(U);
760+
if (!Call)
761+
continue;
762+
763+
Value *ArgOp = Call->getArgOperand(ArgNo);
764+
assert(ArgOp->getType()->isPointerTy() && "Argument must be Pointer Type!");
765+
766+
MemoryLocation Loc = MemoryLocation::getForArgument(Call, ArgNo, nullptr);
767+
768+
AAResults &AAR = FAM.getResult<AAManager>(*Call->getFunction());
769+
// Bail out as soon as we find a Call where Arg may be modified.
770+
if (isModSet(AAR.getModRefInfo(Call, Loc)))
771+
return false;
772+
}
773+
774+
// All Calls do not modify the Arg.
775+
return true;
776+
}
777+
748778
/// PromoteArguments - This method checks the specified function to see if there
749779
/// are any promotable arguments and if it is safe to promote the function (for
750780
/// example, all callers are direct). If safe to promote some arguments, it
@@ -775,11 +805,13 @@ static Function *promoteArguments(Function *F, FunctionAnalysisManager &FAM,
775805
return nullptr;
776806

777807
// First check: see if there are any pointer arguments! If not, quick exit.
778-
SmallVector<Argument *, 16> PointerArgs;
779-
for (Argument &I : F->args())
780-
if (I.getType()->isPointerTy())
781-
PointerArgs.push_back(&I);
782-
if (PointerArgs.empty())
808+
SmallVector<unsigned, 16> PointerArgNos;
809+
for (unsigned I = 0; I < F->arg_size(); ++I) {
810+
Argument *Arg = F->getArg(I);
811+
if (Arg->getType()->isPointerTy())
812+
PointerArgNos.push_back(I);
813+
}
814+
if (PointerArgNos.empty())
783815
return nullptr;
784816

785817
// Second check: make sure that all callers are direct callers. We can't
@@ -814,7 +846,8 @@ static Function *promoteArguments(Function *F, FunctionAnalysisManager &FAM,
814846
// add it to ArgsToPromote.
815847
DenseMap<Argument *, SmallVector<OffsetAndArgPart, 4>> ArgsToPromote;
816848
unsigned NumArgsAfterPromote = F->getFunctionType()->getNumParams();
817-
for (Argument *PtrArg : PointerArgs) {
849+
for (const auto &ArgIdx : PointerArgNos) {
850+
Argument *PtrArg = F->getArg(ArgIdx);
818851
// Replace sret attribute with noalias. This reduces register pressure by
819852
// avoiding a register copy.
820853
if (PtrArg->hasStructRetAttr()) {
@@ -828,10 +861,15 @@ static Function *promoteArguments(Function *F, FunctionAnalysisManager &FAM,
828861
}
829862
}
830863

864+
// Check if we can determine ahead of time that the argument is never
865+
// modified by a call to this function.
866+
bool ArgNotModified = callDoesNotModifyArg(F, ArgIdx, FAM);
867+
831868
// If we can promote the pointer to its value.
832869
SmallVector<OffsetAndArgPart, 4> ArgParts;
833870

834-
if (findArgParts(PtrArg, DL, AAR, MaxElements, IsRecursive, ArgParts)) {
871+
if (findArgParts(PtrArg, DL, AAR, MaxElements, IsRecursive, ArgParts,
872+
ArgNotModified)) {
835873
SmallVector<Type *, 4> Types;
836874
for (const auto &Pair : ArgParts)
837875
Types.push_back(Pair.second.Ty);

llvm/test/Transforms/ArgumentPromotion/actual-arguments.ll

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -75,11 +75,9 @@ define internal i32 @test_cannot_promote_3(ptr %p, ptr nocapture readonly %test_
7575
;
7676
define internal i32 @test_can_promote_1(ptr %p, ptr nocapture readonly %test_c) {
7777
; CHECK-LABEL: define {{[^@]+}}@test_can_promote_1
78-
; CHECK-SAME: (ptr [[P:%.*]], ptr nocapture readonly [[TEST_C:%.*]]) {
79-
; CHECK-NEXT: [[TEST_C_VAL:%.*]] = load i32, ptr [[TEST_C]], align 4
80-
; CHECK-NEXT: [[RES:%.*]] = call i32 @callee(ptr [[P]], i32 [[TEST_C_VAL]])
81-
; CHECK-NEXT: [[LTEST_C:%.*]] = load i32, ptr [[TEST_C]], align 4
82-
; CHECK-NEXT: [[SUM:%.*]] = add i32 [[LTEST_C]], [[RES]]
78+
; CHECK-SAME: (ptr [[P:%.*]], i32 [[TEST_C_0_VAL:%.*]]) {
79+
; CHECK-NEXT: [[RES:%.*]] = call i32 @callee(ptr [[P]], i32 [[TEST_C_0_VAL]])
80+
; CHECK-NEXT: [[SUM:%.*]] = add i32 [[TEST_C_0_VAL]], [[RES]]
8381
; CHECK-NEXT: ret i32 [[SUM]]
8482
;
8583
%res = call i32 @callee(ptr %p, ptr %test_c)
@@ -99,11 +97,9 @@ define internal i32 @test_can_promote_1(ptr %p, ptr nocapture readonly %test_c)
9997
;
10098
define internal i32 @test_can_promote_2(ptr %p, ptr nocapture readonly %test_c) {
10199
; CHECK-LABEL: define {{[^@]+}}@test_can_promote_2
102-
; CHECK-SAME: (ptr [[P:%.*]], ptr nocapture readonly [[TEST_C:%.*]]) {
103-
; CHECK-NEXT: [[TEST_C_VAL:%.*]] = load i32, ptr [[TEST_C]], align 4
104-
; CHECK-NEXT: [[RES:%.*]] = call i32 @callee(ptr [[P]], i32 [[TEST_C_VAL]])
105-
; CHECK-NEXT: [[LTEST_C:%.*]] = load i32, ptr [[TEST_C]], align 4
106-
; CHECK-NEXT: [[SUM:%.*]] = add i32 [[LTEST_C]], [[RES]]
100+
; CHECK-SAME: (ptr [[P:%.*]], i32 [[TEST_C_0_VAL:%.*]]) {
101+
; CHECK-NEXT: [[RES:%.*]] = call i32 @callee(ptr [[P]], i32 [[TEST_C_0_VAL]])
102+
; CHECK-NEXT: [[SUM:%.*]] = add i32 [[TEST_C_0_VAL]], [[RES]]
107103
; CHECK-NEXT: ret i32 [[SUM]]
108104
;
109105
%res = call i32 @callee(ptr %p, ptr %test_c)
@@ -186,8 +182,10 @@ define i32 @caller_safe_args_1(i64 %n) {
186182
; CHECK-NEXT: [[CALLER_C:%.*]] = alloca i32, align 4
187183
; CHECK-NEXT: store i32 5, ptr [[CALLER_C]], align 4
188184
; CHECK-NEXT: [[RES1:%.*]] = call i32 @test_cannot_promote_3(ptr [[P]], ptr [[CALLER_C]])
189-
; CHECK-NEXT: [[RES2:%.*]] = call i32 @test_can_promote_1(ptr [[P]], ptr [[CALLER_C]])
190-
; CHECK-NEXT: [[RES3:%.*]] = call i32 @test_can_promote_2(ptr [[P]], ptr [[CALLER_C]])
185+
; CHECK-NEXT: [[CALLER_C_VAL:%.*]] = load i32, ptr [[CALLER_C]], align 4
186+
; CHECK-NEXT: [[RES2:%.*]] = call i32 @test_can_promote_1(ptr [[P]], i32 [[CALLER_C_VAL]])
187+
; CHECK-NEXT: [[CALLER_C_VAL1:%.*]] = load i32, ptr [[CALLER_C]], align 4
188+
; CHECK-NEXT: [[RES3:%.*]] = call i32 @test_can_promote_2(ptr [[P]], i32 [[CALLER_C_VAL1]])
191189
; CHECK-NEXT: [[RES12:%.*]] = add i32 [[RES1]], [[RES2]]
192190
; CHECK-NEXT: [[RES:%.*]] = add i32 [[RES12]], [[RES3]]
193191
; CHECK-NEXT: ret i32 [[RES]]
@@ -215,7 +213,8 @@ define i32 @caller_safe_args_2(i64 %n, ptr %p) {
215213
; CHECK-NEXT: call void @memset(ptr [[P]], i64 0, i64 [[N]])
216214
; CHECK-NEXT: [[CALLER_C:%.*]] = alloca i32, align 4
217215
; CHECK-NEXT: store i32 5, ptr [[CALLER_C]], align 4
218-
; CHECK-NEXT: [[RES:%.*]] = call i32 @test_can_promote_2(ptr [[P]], ptr [[CALLER_C]])
216+
; CHECK-NEXT: [[CALLER_C_VAL:%.*]] = load i32, ptr [[CALLER_C]], align 4
217+
; CHECK-NEXT: [[RES:%.*]] = call i32 @test_can_promote_2(ptr [[P]], i32 [[CALLER_C_VAL]])
219218
; CHECK-NEXT: ret i32 [[RES]]
220219
;
221220
call void @memset(ptr %p, i64 0, i64 %n)

0 commit comments

Comments
 (0)