Skip to content

Commit d10cb42

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 2e9b331 commit d10cb42

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
@@ -489,7 +489,8 @@ static bool allCallersPassValidPointerForArgument(
489489
/// parts it can be promoted into.
490490
static bool findArgParts(Argument *Arg, const DataLayout &DL, AAResults &AAR,
491491
unsigned MaxElements, bool IsRecursive,
492-
SmallVectorImpl<OffsetAndArgPart> &ArgPartsVec) {
492+
SmallVectorImpl<OffsetAndArgPart> &ArgPartsVec,
493+
bool ArgNotModified) {
493494
// Quick exit for unused arguments
494495
if (Arg->use_empty())
495496
return true;
@@ -711,8 +712,10 @@ static bool findArgParts(Argument *Arg, const DataLayout &DL, AAResults &AAR,
711712

712713
// If store instructions are allowed, the path from the entry of the function
713714
// to each load may be not free of instructions that potentially invalidate
714-
// the load, and this is an admissible situation.
715-
if (AreStoresAllowed)
715+
// the load, and this is an admissible situation. If we have already
716+
// determined that the pointer Arg is not modified in the function (for all
717+
// Calls) then we can similarly conclude analysis here.
718+
if (AreStoresAllowed || ArgNotModified)
716719
return true;
717720

718721
// Okay, now we know that the argument is only used by load instructions, and
@@ -760,6 +763,33 @@ static bool areTypesABICompatible(ArrayRef<Type *> Types, const Function &F,
760763
});
761764
}
762765

766+
// Try to prove that all Calls to F do not modify the memory pointed to by Arg.
767+
// This can provide us with more opportunities to perform Argument Promotion in
768+
// cases where simply looking at a Function's instructions is insufficient to
769+
// prove that the pointer argument is not invalidated before all loads from it.
770+
static bool callDoesNotModifyArg(Function *F, unsigned ArgNo,
771+
FunctionAnalysisManager &FAM) {
772+
// Find all Users of F that are Calls, and see if they may modify Arg.
773+
for (User *U : F->users()) {
774+
auto *Call = dyn_cast<CallInst>(U);
775+
if (!Call)
776+
continue;
777+
778+
Value *ArgOp = Call->getArgOperand(ArgNo);
779+
assert(ArgOp->getType()->isPointerTy() && "Argument must be Pointer Type!");
780+
781+
MemoryLocation Loc = MemoryLocation::getForArgument(Call, ArgNo, nullptr);
782+
783+
AAResults &AAR = FAM.getResult<AAManager>(*Call->getFunction());
784+
// Bail out as soon as we find a Call where Arg may be modified.
785+
if (isModSet(AAR.getModRefInfo(Call, Loc)))
786+
return false;
787+
}
788+
789+
// All Calls do not modify the Arg.
790+
return true;
791+
}
792+
763793
/// PromoteArguments - This method checks the specified function to see if there
764794
/// are any promotable arguments and if it is safe to promote the function (for
765795
/// example, all callers are direct). If safe to promote some arguments, it
@@ -790,11 +820,13 @@ static Function *promoteArguments(Function *F, FunctionAnalysisManager &FAM,
790820
return nullptr;
791821

792822
// First check: see if there are any pointer arguments! If not, quick exit.
793-
SmallVector<Argument *, 16> PointerArgs;
794-
for (Argument &I : F->args())
795-
if (I.getType()->isPointerTy())
796-
PointerArgs.push_back(&I);
797-
if (PointerArgs.empty())
823+
SmallVector<unsigned, 16> PointerArgNos;
824+
for (unsigned I = 0; I < F->arg_size(); ++I) {
825+
Argument *Arg = F->getArg(I);
826+
if (Arg->getType()->isPointerTy())
827+
PointerArgNos.push_back(I);
828+
}
829+
if (PointerArgNos.empty())
798830
return nullptr;
799831

800832
// Second check: make sure that all callers are direct callers. We can't
@@ -829,7 +861,8 @@ static Function *promoteArguments(Function *F, FunctionAnalysisManager &FAM,
829861
// add it to ArgsToPromote.
830862
DenseMap<Argument *, SmallVector<OffsetAndArgPart, 4>> ArgsToPromote;
831863
unsigned NumArgsAfterPromote = F->getFunctionType()->getNumParams();
832-
for (Argument *PtrArg : PointerArgs) {
864+
for (const auto &ArgIdx : PointerArgNos) {
865+
Argument *PtrArg = F->getArg(ArgIdx);
833866
// Replace sret attribute with noalias. This reduces register pressure by
834867
// avoiding a register copy.
835868
if (PtrArg->hasStructRetAttr()) {
@@ -843,10 +876,15 @@ static Function *promoteArguments(Function *F, FunctionAnalysisManager &FAM,
843876
}
844877
}
845878

879+
// Check if we can determine ahead of time that the argument is never
880+
// modified by a call to this function.
881+
bool ArgNotModified = callDoesNotModifyArg(F, ArgIdx, FAM);
882+
846883
// If we can promote the pointer to its value.
847884
SmallVector<OffsetAndArgPart, 4> ArgParts;
848885

849-
if (findArgParts(PtrArg, DL, AAR, MaxElements, IsRecursive, ArgParts)) {
886+
if (findArgParts(PtrArg, DL, AAR, MaxElements, IsRecursive, ArgParts,
887+
ArgNotModified)) {
850888
SmallVector<Type *, 4> Types;
851889
for (const auto &Pair : ArgParts)
852890
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)