[MemCpyOpt] Fix MemorySSA preservation

moveUp() moves instructions, so we should move the corresponding
memory accesses as well. We should also move the store instruction
itself: Even though we'll end up removing it later, this gives us
a correct MemoryDef to replace.

The implementation is somewhat more complicated than it should be,
because we also handle the case where P does not have a memory
access due to a degnerate AA pipeline. Hopefully, the need for this
will go away in the future, when the rest of the pass is based on
MSSA.

Differential Revision: https://reviews.llvm.org/D88778
This commit is contained in:
Nikita Popov 2020-10-03 11:26:13 +02:00
parent 0ec1cf13f2
commit e79ca751fc
2 changed files with 48 additions and 4 deletions

View File

@ -478,7 +478,7 @@ bool MemCpyOptPass::moveUp(StoreInst *SI, Instruction *P, const LoadInst *LI) {
Args.insert(Ptr);
// Instruction to lift before P.
SmallVector<Instruction*, 8> ToLift;
SmallVector<Instruction *, 8> ToLift{SI};
// Memory locations of lifted instructions.
SmallVector<MemoryLocation, 8> MemLocs{StoreLoc};
@ -549,10 +549,40 @@ bool MemCpyOptPass::moveUp(StoreInst *SI, Instruction *P, const LoadInst *LI) {
}
}
// We made it, we need to lift
// Find MSSA insertion point. Normally P will always have a corresponding
// memory access before which we can insert. However, with non-standard AA
// pipelines, there may be a mismatch between AA and MSSA, in which case we
// will scan for a memory access before P. In either case, we know for sure
// that at least the load will have a memory access.
// TODO: Simplify this once P will be determined by MSSA, in which case the
// discrepancy can no longer occur.
MemoryUseOrDef *MemInsertPoint = nullptr;
if (MSSAU) {
if (MemoryUseOrDef *MA = MSSAU->getMemorySSA()->getMemoryAccess(P)) {
MemInsertPoint = cast<MemoryUseOrDef>(--MA->getIterator());
} else {
const Instruction *ConstP = P;
for (const Instruction &I : make_range(++ConstP->getReverseIterator(),
++LI->getReverseIterator())) {
if (MemoryUseOrDef *MA = MSSAU->getMemorySSA()->getMemoryAccess(&I)) {
MemInsertPoint = MA;
break;
}
}
}
}
// We made it, we need to lift.
for (auto *I : llvm::reverse(ToLift)) {
LLVM_DEBUG(dbgs() << "Lifting " << *I << " before " << *P << "\n");
I->moveBefore(P);
if (MSSAU) {
assert(MemInsertPoint && "Must have found insert point");
if (MemoryUseOrDef *MA = MSSAU->getMemorySSA()->getMemoryAccess(I)) {
MSSAU->moveAfter(MA, MemInsertPoint);
MemInsertPoint = MA;
}
}
}
return true;
@ -636,9 +666,8 @@ bool MemCpyOptPass::processStore(StoreInst *SI, BasicBlock::iterator &BBI) {
<< *M << "\n");
if (MSSAU) {
assert(isa<MemoryDef>(MSSAU->getMemorySSA()->getMemoryAccess(P)));
auto *LastDef =
cast<MemoryDef>(MSSAU->getMemorySSA()->getMemoryAccess(P));
cast<MemoryDef>(MSSAU->getMemorySSA()->getMemoryAccess(SI));
auto *NewAccess =
MSSAU->createMemoryAccessAfter(M, LastDef, LastDef);
MSSAU->insertDef(cast<MemoryDef>(NewAccess), /*RenameUses=*/true);

View File

@ -148,6 +148,21 @@ entry:
ret void
}
define void @test8(%t* noalias %src, %t* %dst) {
; CHECK-LABEL: @test8(
; CHECK-NEXT: [[TMP1:%.*]] = bitcast %t* [[SRC:%.*]] to i8*
; CHECK-NEXT: [[TMP2:%.*]] = bitcast %t* [[DST:%.*]] to i8*
; CHECK-NEXT: [[TMP3:%.*]] = bitcast %t* [[SRC]] to i8*
; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 [[TMP2]], i8* align 1 [[TMP3]], i64 8224, i1 false)
; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* align 1 [[TMP1]], i8 0, i64 8224, i1 false)
; CHECK-NEXT: ret void
;
%1 = load %t, %t* %src
store %t zeroinitializer, %t* %src
store %t %1, %t* %dst
ret void
}
declare void @clobber()
; Function Attrs: argmemonly nounwind willreturn