Skip to content

Commit 7662d16

Browse files
committed
[MemCpyOpt] Check all access for MemoryUses in writtenBetween.
Currently writtenBetween can miss clobbers of Loc between End and Start, if End is a MemoryUse. To guarantee we see all write clobbers of Loc between Start and End for MemoryUses, restrict to Start and End being in the same block and check all accesses between them. This fixes 2 mis-compiles illustrated in llvm/test/Transforms/MemCpyOpt/memcpy-byval-forwarding-clobbers.ll Reviewed By: nikic Differential Revision: https://reviews.llvm.org/D119929
1 parent 3a3d9ae commit 7662d16

File tree

2 files changed

+22
-8
lines changed

2 files changed

+22
-8
lines changed

llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -352,9 +352,25 @@ static bool accessedBetween(AliasAnalysis &AA, MemoryLocation Loc,
352352

353353
// Check for mod of Loc between Start and End, excluding both boundaries.
354354
// Start and End can be in different blocks.
355-
static bool writtenBetween(MemorySSA *MSSA, MemoryLocation Loc,
356-
const MemoryUseOrDef *Start,
355+
static bool writtenBetween(MemorySSA *MSSA, AliasAnalysis &AA,
356+
MemoryLocation Loc, const MemoryUseOrDef *Start,
357357
const MemoryUseOrDef *End) {
358+
if (isa<MemoryUse>(End)) {
359+
// For MemoryUses, getClobberingMemoryAccess may skip non-clobbering writes.
360+
// Manually check read accesses between Start and End, if they are in the
361+
// same block, for clobbers. Otherwise assume Loc is clobbered.
362+
return Start->getBlock() != End->getBlock() ||
363+
any_of(
364+
make_range(std::next(Start->getIterator()), End->getIterator()),
365+
[&AA, Loc](const MemoryAccess &Acc) {
366+
if (isa<MemoryUse>(&Acc))
367+
return false;
368+
Instruction *AccInst =
369+
cast<MemoryUseOrDef>(&Acc)->getMemoryInst();
370+
return isModSet(AA.getModRefInfo(AccInst, Loc));
371+
});
372+
}
373+
358374
// TODO: Only walk until we hit Start.
359375
MemoryAccess *Clobber = MSSA->getWalker()->getClobberingMemoryAccess(
360376
End->getDefiningAccess(), Loc);
@@ -1118,7 +1134,7 @@ bool MemCpyOptPass::processMemCpyMemCpyDependence(MemCpyInst *M,
11181134
// then we could still perform the xform by moving M up to the first memcpy.
11191135
// TODO: It would be sufficient to check the MDep source up to the memcpy
11201136
// size of M, rather than MDep.
1121-
if (writtenBetween(MSSA, MemoryLocation::getForSource(MDep),
1137+
if (writtenBetween(MSSA, *AA, MemoryLocation::getForSource(MDep),
11221138
MSSA->getMemoryAccess(MDep), MSSA->getMemoryAccess(M)))
11231139
return false;
11241140

@@ -1557,7 +1573,7 @@ bool MemCpyOptPass::processByValArgument(CallBase &CB, unsigned ArgNo) {
15571573
// *b = 42;
15581574
// foo(*a)
15591575
// It would be invalid to transform the second memcpy into foo(*b).
1560-
if (writtenBetween(MSSA, MemoryLocation::getForSource(MDep),
1576+
if (writtenBetween(MSSA, *AA, MemoryLocation::getForSource(MDep),
15611577
MSSA->getMemoryAccess(MDep), MSSA->getMemoryAccess(&CB)))
15621578
return false;
15631579

llvm/test/Transforms/MemCpyOpt/memcpy-byval-forwarding-clobbers.ll

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ declare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noa
1313

1414
; %a.2's lifetime ends before the call to @check. Cannot replace
1515
; %a.1 with %a.2 in the call to @check.
16-
; FIXME: Find lifetime.end, prevent optimization.
1716
define i1 @alloca_forwarding_lifetime_end_clobber() {
1817
; CHECK-LABEL: @alloca_forwarding_lifetime_end_clobber(
1918
; CHECK-NEXT: entry:
@@ -26,7 +25,7 @@ define i1 @alloca_forwarding_lifetime_end_clobber() {
2625
; CHECK-NEXT: store i8 0, i8* [[BC_A_2]], align 1
2726
; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[BC_A_1]], i8* [[BC_A_2]], i64 8, i1 false)
2827
; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[BC_A_2]])
29-
; CHECK-NEXT: [[CALL:%.*]] = call i1 @check(i64* byval(i64) align 8 [[A_2]])
28+
; CHECK-NEXT: [[CALL:%.*]] = call i1 @check(i64* byval(i64) align 8 [[A_1]])
3029
; CHECK-NEXT: ret i1 [[CALL]]
3130
;
3231
entry:
@@ -46,7 +45,6 @@ entry:
4645

4746
; There is a call clobbering %a.2 before the call to @check. Cannot replace
4847
; %a.1 with %a.2 in the call to @check.
49-
; FIXME: Find clobber, prevent optimization.
5048
define i1 @alloca_forwarding_call_clobber() {
5149
; CHECK-LABEL: @alloca_forwarding_call_clobber(
5250
; CHECK-NEXT: entry:
@@ -59,7 +57,7 @@ define i1 @alloca_forwarding_call_clobber() {
5957
; CHECK-NEXT: store i8 0, i8* [[BC_A_2]], align 1
6058
; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[BC_A_1]], i8* [[BC_A_2]], i64 8, i1 false)
6159
; CHECK-NEXT: call void @clobber(i8* [[BC_A_2]])
62-
; CHECK-NEXT: [[CALL:%.*]] = call i1 @check(i64* byval(i64) align 8 [[A_2]])
60+
; CHECK-NEXT: [[CALL:%.*]] = call i1 @check(i64* byval(i64) align 8 [[A_1]])
6361
; CHECK-NEXT: ret i1 [[CALL]]
6462
;
6563
entry:

0 commit comments

Comments
 (0)