Skip to content

Commit a13b7cc

Browse files
authored
[LICM] Support hoisting of non-argmemonly readonly calls (#144497)
The code checking whether a readonly call is safe to hoist is currently limited to only argmemonly calls. However, the actual implementation does not depend on this in any way. It either does an MSSA clobber walk on the memory access (which will take all locations accessed by the call into account), or it will look at all MemoryDefs in an entirely location-independent manner. The current restriction dates back to the time when LICM still supported AST, in which case this code *did* reason about the individual pointer arguments.
1 parent 5a9cc93 commit a13b7cc

File tree

3 files changed

+38
-26
lines changed

3 files changed

+38
-26
lines changed

llvm/lib/Transforms/Scalar/LICM.cpp

Lines changed: 5 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1117,13 +1117,6 @@ bool isHoistableAndSinkableInst(Instruction &I) {
11171117
isa<ShuffleVectorInst>(I) || isa<ExtractValueInst>(I) ||
11181118
isa<InsertValueInst>(I) || isa<FreezeInst>(I));
11191119
}
1120-
/// Return true if MSSA knows there are no MemoryDefs in the loop.
1121-
bool isReadOnly(const MemorySSAUpdater &MSSAU, const Loop *L) {
1122-
for (auto *BB : L->getBlocks())
1123-
if (MSSAU.getMemorySSA()->getBlockDefs(BB))
1124-
return false;
1125-
return true;
1126-
}
11271120

11281121
/// Return true if I is the only Instruction with a MemoryAccess in L.
11291122
bool isOnlyMemoryAccess(const Instruction *I, const Loop *L,
@@ -1234,24 +1227,11 @@ bool llvm::canSinkOrHoistInst(Instruction &I, AAResults *AA, DominatorTree *DT,
12341227
if (Behavior.doesNotAccessMemory())
12351228
return true;
12361229
if (Behavior.onlyReadsMemory()) {
1237-
// A readonly argmemonly function only reads from memory pointed to by
1238-
// it's arguments with arbitrary offsets. If we can prove there are no
1239-
// writes to this memory in the loop, we can hoist or sink.
1240-
if (Behavior.onlyAccessesArgPointees()) {
1241-
// TODO: expand to writeable arguments
1242-
for (Value *Op : CI->args())
1243-
if (Op->getType()->isPointerTy() &&
1244-
pointerInvalidatedByLoop(
1245-
MSSA, cast<MemoryUse>(MSSA->getMemoryAccess(CI)), CurLoop, I,
1246-
Flags, /*InvariantGroup=*/false))
1247-
return false;
1248-
return true;
1249-
}
1250-
1251-
// If this call only reads from memory and there are no writes to memory
1252-
// in the loop, we can hoist or sink the call as appropriate.
1253-
if (isReadOnly(MSSAU, CurLoop))
1254-
return true;
1230+
// If we can prove there are no writes to the memory read by the call, we
1231+
// can hoist or sink.
1232+
return !pointerInvalidatedByLoop(
1233+
MSSA, cast<MemoryUse>(MSSA->getMemoryAccess(CI)), CurLoop, I, Flags,
1234+
/*InvariantGroup=*/false);
12551235
}
12561236

12571237
// FIXME: This should use mod/ref information to see if we can hoist or

llvm/test/Transforms/LICM/call-hoisting.ll

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,38 @@ exit:
8484
ret void
8585
}
8686

87+
declare i32 @load_not_argmemonly() readonly nounwind willreturn
88+
89+
define void @test_load_not_argmemonly(ptr noalias %sink) {
90+
; CHECK-LABEL: define void @test_load_not_argmemonly(
91+
; CHECK-SAME: ptr noalias [[SINK:%.*]]) {
92+
; CHECK-NEXT: [[ENTRY:.*]]:
93+
; CHECK-NEXT: [[RET:%.*]] = call i32 @load_not_argmemonly()
94+
; CHECK-NEXT: store i32 [[RET]], ptr [[SINK]], align 4
95+
; CHECK-NEXT: br label %[[LOOP:.*]]
96+
; CHECK: [[LOOP]]:
97+
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
98+
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
99+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[IV]], 200
100+
; CHECK-NEXT: br i1 [[CMP]], label %[[LOOP]], label %[[EXIT:.*]]
101+
; CHECK: [[EXIT]]:
102+
; CHECK-NEXT: ret void
103+
;
104+
entry:
105+
br label %loop
106+
107+
loop:
108+
%iv = phi i32 [0, %entry], [%iv.next, %loop]
109+
%ret = call i32 @load_not_argmemonly()
110+
store i32 %ret, ptr %sink
111+
%iv.next = add i32 %iv, 1
112+
%cmp = icmp slt i32 %iv, 200
113+
br i1 %cmp, label %loop, label %exit
114+
115+
exit:
116+
ret void
117+
}
118+
87119
declare void @store(i32 %val, ptr %p) argmemonly writeonly nounwind
88120

89121
define void @test(ptr %loc) {

llvm/test/Transforms/LICM/funclet.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,6 @@ else: ; preds = %postinvoke
153153

154154
declare void @may_throw()
155155

156-
declare i32 @pure_computation() nounwind argmemonly readonly willreturn
156+
declare i32 @pure_computation() nounwind willreturn memory(none)
157157

158158
declare i32 @__CxxFrameHandler3(...)

0 commit comments

Comments
 (0)