Skip to content

Commit 9a45e4b

Browse files
committed
[MemCpyOpt] Move lifetime marker before call to enable call slot optimization
Currently call slot optimization may be prevented because the lifetime markers for the destination only start after the call. In this case, rather than aborting the transform, we should move the lifetime.start before the call to enable the transform. Differential Revision: https://reviews.llvm.org/D135886
1 parent bada353 commit 9a45e4b

File tree

2 files changed

+24
-7
lines changed

2 files changed

+24
-7
lines changed

llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -331,16 +331,27 @@ void MemCpyOptPass::eraseInstruction(Instruction *I) {
331331
}
332332

333333
// Check for mod or ref of Loc between Start and End, excluding both boundaries.
334-
// Start and End must be in the same block
334+
// Start and End must be in the same block.
335+
// If SkippedLifetimeStart is provided, skip over one clobbering lifetime.start
336+
// intrinsic and store it inside SkippedLifetimeStart.
335337
static bool accessedBetween(AliasAnalysis &AA, MemoryLocation Loc,
336338
const MemoryUseOrDef *Start,
337-
const MemoryUseOrDef *End) {
339+
const MemoryUseOrDef *End,
340+
Instruction **SkippedLifetimeStart = nullptr) {
338341
assert(Start->getBlock() == End->getBlock() && "Only local supported");
339342
for (const MemoryAccess &MA :
340343
make_range(++Start->getIterator(), End->getIterator())) {
341-
if (isModOrRefSet(AA.getModRefInfo(cast<MemoryUseOrDef>(MA).getMemoryInst(),
342-
Loc)))
344+
Instruction *I = cast<MemoryUseOrDef>(MA).getMemoryInst();
345+
if (isModOrRefSet(AA.getModRefInfo(I, Loc))) {
346+
auto *II = dyn_cast<IntrinsicInst>(I);
347+
if (II && II->getIntrinsicID() == Intrinsic::lifetime_start &&
348+
SkippedLifetimeStart && !*SkippedLifetimeStart) {
349+
*SkippedLifetimeStart = I;
350+
continue;
351+
}
352+
343353
return true;
354+
}
344355
}
345356
return false;
346357
}
@@ -913,8 +924,9 @@ bool MemCpyOptPass::performCallSlotOptzn(Instruction *cpyLoad,
913924

914925
// Check that nothing touches the dest of the copy between
915926
// the call and the store/memcpy.
927+
Instruction *SkippedLifetimeStart = nullptr;
916928
if (accessedBetween(*AA, DestLoc, MSSA->getMemoryAccess(C),
917-
MSSA->getMemoryAccess(cpyStore))) {
929+
MSSA->getMemoryAccess(cpyStore), &SkippedLifetimeStart)) {
918930
LLVM_DEBUG(dbgs() << "Call Slot: Dest pointer modified after call\n");
919931
return false;
920932
}
@@ -1094,6 +1106,12 @@ bool MemCpyOptPass::performCallSlotOptzn(Instruction *cpyLoad,
10941106
cast<AllocaInst>(cpyDest)->setAlignment(srcAlign);
10951107
}
10961108

1109+
if (SkippedLifetimeStart) {
1110+
SkippedLifetimeStart->moveBefore(C);
1111+
MSSAU->moveBefore(MSSA->getMemoryAccess(SkippedLifetimeStart),
1112+
MSSA->getMemoryAccess(C));
1113+
}
1114+
10971115
// Update AA metadata
10981116
// FIXME: MD_tbaa_struct and MD_mem_parallel_loop_access should also be
10991117
// handled here, but combineMetadata doesn't support them yet

llvm/test/Transforms/MemCpyOpt/lifetime.ll

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,8 @@ define i32 @call_slot_move_lifetime_start() {
5555
; CHECK-LABEL: @call_slot_move_lifetime_start(
5656
; CHECK-NEXT: [[TMP:%.*]] = alloca i32, align 4
5757
; CHECK-NEXT: [[DST:%.*]] = alloca i32, align 4
58-
; CHECK-NEXT: call void @call(ptr [[TMP]])
5958
; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[DST]])
60-
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[DST]], ptr align 4 [[TMP]], i64 4, i1 false)
59+
; CHECK-NEXT: call void @call(ptr [[DST]])
6160
; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr [[DST]])
6261
; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[DST]], align 4
6362
; CHECK-NEXT: ret i32 [[V]]

0 commit comments

Comments
 (0)