Skip to content

Commit cbd3863

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 (cherry-picked from 7662d16)
1 parent 55f2b33 commit cbd3863

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
@@ -345,9 +345,25 @@ static bool accessedBetween(AliasAnalysis &AA, MemoryLocation Loc,
345345

346346
// Check for mod of Loc between Start and End, excluding both boundaries.
347347
// Start and End can be in different blocks.
348-
static bool writtenBetween(MemorySSA *MSSA, MemoryLocation Loc,
349-
const MemoryUseOrDef *Start,
348+
static bool writtenBetween(MemorySSA *MSSA, AliasAnalysis &AA,
349+
MemoryLocation Loc, const MemoryUseOrDef *Start,
350350
const MemoryUseOrDef *End) {
351+
if (isa<MemoryUse>(End)) {
352+
// For MemoryUses, getClobberingMemoryAccess may skip non-clobbering writes.
353+
// Manually check read accesses between Start and End, if they are in the
354+
// same block, for clobbers. Otherwise assume Loc is clobbered.
355+
return Start->getBlock() != End->getBlock() ||
356+
any_of(
357+
make_range(std::next(Start->getIterator()), End->getIterator()),
358+
[&AA, Loc](const MemoryAccess &Acc) {
359+
if (isa<MemoryUse>(&Acc))
360+
return false;
361+
Instruction *AccInst =
362+
cast<MemoryUseOrDef>(&Acc)->getMemoryInst();
363+
return isModSet(AA.getModRefInfo(AccInst, Loc));
364+
});
365+
}
366+
351367
// TODO: Only walk until we hit Start.
352368
MemoryAccess *Clobber = MSSA->getWalker()->getClobberingMemoryAccess(
353369
End->getDefiningAccess(), Loc);
@@ -1060,7 +1076,7 @@ bool MemCpyOptPass::processMemCpyMemCpyDependence(MemCpyInst *M,
10601076
// then we could still perform the xform by moving M up to the first memcpy.
10611077
// TODO: It would be sufficient to check the MDep source up to the memcpy
10621078
// size of M, rather than MDep.
1063-
if (writtenBetween(MSSA, MemoryLocation::getForSource(MDep),
1079+
if (writtenBetween(MSSA, *AA, MemoryLocation::getForSource(MDep),
10641080
MSSA->getMemoryAccess(MDep), MSSA->getMemoryAccess(M)))
10651081
return false;
10661082

@@ -1498,7 +1514,7 @@ bool MemCpyOptPass::processByValArgument(CallBase &CB, unsigned ArgNo) {
14981514
// *b = 42;
14991515
// foo(*a)
15001516
// It would be invalid to transform the second memcpy into foo(*b).
1501-
if (writtenBetween(MSSA, MemoryLocation::getForSource(MDep),
1517+
if (writtenBetween(MSSA, *AA, MemoryLocation::getForSource(MDep),
15021518
MSSA->getMemoryAccess(MDep), MSSA->getMemoryAccess(&CB)))
15031519
return false;
15041520

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)