[llvm] [MemCpyOpt] Use EarliestEscapeInfo (PR #110280)
Nikita Popov via llvm-commits
llvm-commits at lists.llvm.org
Sat Sep 28 00:58:23 PDT 2024
https://github.com/nikic updated https://github.com/llvm/llvm-project/pull/110280
>From 9736bcf546005645d7f6d2e2e2492abd8521a0af Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Fri, 27 Sep 2024 16:12:50 +0200
Subject: [PATCH 1/2] [MemCpyOpt] Use EarliestEscapeInfo
Pass EarliestEscapeInfo to BatchAA in MemCpyOpt. This allows
memcpy elimination in cases where one of the involved pointers
is captured after the relevant memcpy/call.
---
.../llvm/Transforms/Scalar/MemCpyOptimizer.h | 2 ++
llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp | 11 +++++++----
llvm/test/Transforms/MemCpyOpt/memcpy.ll | 14 ++++----------
3 files changed, 13 insertions(+), 14 deletions(-)
diff --git a/llvm/include/llvm/Transforms/Scalar/MemCpyOptimizer.h b/llvm/include/llvm/Transforms/Scalar/MemCpyOptimizer.h
index 8ed03d7f3ddbff..e5f78ac2286833 100644
--- a/llvm/include/llvm/Transforms/Scalar/MemCpyOptimizer.h
+++ b/llvm/include/llvm/Transforms/Scalar/MemCpyOptimizer.h
@@ -26,6 +26,7 @@ class AssumptionCache;
class CallBase;
class CallInst;
class DominatorTree;
+class EarliestEscapeInfo;
class Function;
class Instruction;
class LoadInst;
@@ -48,6 +49,7 @@ class MemCpyOptPass : public PassInfoMixin<MemCpyOptPass> {
PostDominatorTree *PDT = nullptr;
MemorySSA *MSSA = nullptr;
MemorySSAUpdater *MSSAU = nullptr;
+ EarliestEscapeInfo *EEI = nullptr;
public:
MemCpyOptPass() = default;
diff --git a/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp b/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp
index e9f212fb482c39..5f7dac14c1deeb 100644
--- a/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp
+++ b/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp
@@ -284,6 +284,7 @@ static bool mayBeVisibleThroughUnwinding(Value *V, Instruction *Start,
void MemCpyOptPass::eraseInstruction(Instruction *I) {
MSSAU->removeMemoryAccess(I);
+ EEI->removeInstruction(I);
I->eraseFromParent();
}
@@ -638,7 +639,7 @@ bool MemCpyOptPass::processStoreOfLoad(StoreInst *SI, LoadInst *LI,
if (!LI->isSimple() || !LI->hasOneUse() || LI->getParent() != SI->getParent())
return false;
- BatchAAResults BAA(*AA);
+ BatchAAResults BAA(*AA, EEI);
auto *T = LI->getType();
// Don't introduce calls to memcpy/memmove intrinsics out of thin air if
// the corresponding libcalls are not available.
@@ -1751,7 +1752,7 @@ bool MemCpyOptPass::processMemCpy(MemCpyInst *M, BasicBlock::iterator &BBI) {
return true;
}
- BatchAAResults BAA(*AA);
+ BatchAAResults BAA(*AA, EEI);
// FIXME: Not using getClobberingMemoryAccess() here due to PR54682.
MemoryAccess *AnyClobber = MA->getDefiningAccess();
MemoryLocation DestLoc = MemoryLocation::getForDest(M);
@@ -1876,7 +1877,7 @@ bool MemCpyOptPass::processByValArgument(CallBase &CB, unsigned ArgNo) {
if (!CallAccess)
return false;
MemCpyInst *MDep = nullptr;
- BatchAAResults BAA(*AA);
+ BatchAAResults BAA(*AA, EEI);
MemoryAccess *Clobber = MSSA->getWalker()->getClobberingMemoryAccess(
CallAccess->getDefiningAccess(), Loc, BAA);
if (auto *MD = dyn_cast<MemoryDef>(Clobber))
@@ -1949,7 +1950,7 @@ bool MemCpyOptPass::processByValArgument(CallBase &CB, unsigned ArgNo) {
/// 4. The memcpy src is not modified during the call. (ModRef check shows no
/// Mod.)
bool MemCpyOptPass::processImmutArgument(CallBase &CB, unsigned ArgNo) {
- BatchAAResults BAA(*AA);
+ BatchAAResults BAA(*AA, EEI);
Value *ImmutArg = CB.getArgOperand(ArgNo);
// 1. Ensure passed argument is immutable during call.
@@ -2117,6 +2118,8 @@ bool MemCpyOptPass::runImpl(Function &F, TargetLibraryInfo *TLI_,
MSSA = MSSA_;
MemorySSAUpdater MSSAU_(MSSA_);
MSSAU = &MSSAU_;
+ EarliestEscapeInfo EEI_(*DT);
+ EEI = &EEI_;
while (true) {
if (!iterateOnFunction(F))
diff --git a/llvm/test/Transforms/MemCpyOpt/memcpy.ll b/llvm/test/Transforms/MemCpyOpt/memcpy.ll
index 0114b9c2443582..39b90adc74ef38 100644
--- a/llvm/test/Transforms/MemCpyOpt/memcpy.ll
+++ b/llvm/test/Transforms/MemCpyOpt/memcpy.ll
@@ -837,7 +837,7 @@ define void @memcpy_memcpy_escape_after1(ptr noalias %P, ptr noalias %Q) {
; CHECK-NEXT: [[MEMTMP:%.*]] = alloca [32 x i8], align 16
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 16 [[MEMTMP]], ptr align 16 [[P:%.*]], i32 32, i1 false)
; CHECK-NEXT: call void @do_something()
-; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 16 [[Q:%.*]], ptr align 16 [[MEMTMP]], i32 32, i1 false)
+; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 16 [[Q:%.*]], ptr align 16 [[P]], i32 32, i1 false)
; CHECK-NEXT: call void @capture(ptr [[MEMTMP]])
; CHECK-NEXT: ret void
;
@@ -851,10 +851,8 @@ define void @memcpy_memcpy_escape_after1(ptr noalias %P, ptr noalias %Q) {
define void @memcpy_memcpy_escape_after2(ptr noalias %P, ptr noalias %Q) {
; CHECK-LABEL: @memcpy_memcpy_escape_after2(
-; CHECK-NEXT: [[MEMTMP:%.*]] = alloca [32 x i8], align 16
-; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 16 [[MEMTMP]], ptr align 16 [[P:%.*]], i32 32, i1 false)
; CHECK-NEXT: call void @do_something()
-; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 16 [[Q:%.*]], ptr align 16 [[MEMTMP]], i32 32, i1 false)
+; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 16 [[Q:%.*]], ptr align 16 [[P:%.*]], i32 32, i1 false)
; CHECK-NEXT: call void @capture(ptr [[P]])
; CHECK-NEXT: ret void
;
@@ -868,10 +866,8 @@ define void @memcpy_memcpy_escape_after2(ptr noalias %P, ptr noalias %Q) {
define void @memcpy_byval_escape_after(ptr noalias %P) {
; CHECK-LABEL: @memcpy_byval_escape_after(
-; CHECK-NEXT: [[A:%.*]] = alloca [8 x i8], align 1
-; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[A]], ptr align 4 [[P:%.*]], i64 8, i1 false)
; CHECK-NEXT: call void @do_something()
-; CHECK-NEXT: call void @test4a(ptr byval(i8) align 1 [[A]])
+; CHECK-NEXT: call void @test4a(ptr byval(i8) align 1 [[P:%.*]])
; CHECK-NEXT: call void @capture(ptr [[P]])
; CHECK-NEXT: ret void
;
@@ -885,10 +881,8 @@ define void @memcpy_byval_escape_after(ptr noalias %P) {
define void @memcpy_immut_escape_after(ptr align 4 noalias %val) {
; CHECK-LABEL: @memcpy_immut_escape_after(
-; CHECK-NEXT: [[VAL1:%.*]] = alloca i8, align 4
-; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[VAL1]], ptr align 4 [[VAL:%.*]], i64 1, i1 false)
; CHECK-NEXT: call void @do_something()
-; CHECK-NEXT: call void @f(ptr noalias nocapture readonly align 4 [[VAL1]])
+; CHECK-NEXT: call void @f(ptr noalias nocapture readonly align 4 [[VAL:%.*]])
; CHECK-NEXT: call void @capture(ptr [[VAL]])
; CHECK-NEXT: ret void
;
>From f398017d218e6c0e861e2be75267751a4b1a58fc Mon Sep 17 00:00:00 2001
From: Nikita Popov <nikita.ppv at gmail.com>
Date: Sat, 28 Sep 2024 09:39:53 +0200
Subject: [PATCH 2/2] Use eraseInstruction()
---
llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp b/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp
index 5f7dac14c1deeb..b568811dcdbcac 100644
--- a/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp
+++ b/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp
@@ -1148,14 +1148,14 @@ bool MemCpyOptPass::processMemCpyMemCpyDependence(MemCpyInst *M,
IRBuilder<> Builder(M);
auto *CopySource = MDep->getSource();
Instruction *NewCopySource = nullptr;
- auto CleanupOnRet = llvm::make_scope_exit([&NewCopySource] {
+ auto CleanupOnRet = llvm::make_scope_exit([&] {
if (NewCopySource && NewCopySource->use_empty())
// Safety: It's safe here because we will only allocate more instructions
// after finishing all BatchAA queries, but we have to be careful if we
// want to do something like this in another place. Then we'd probably
// have to delay instruction removal until all transforms on an
// instruction finished.
- NewCopySource->eraseFromParent();
+ eraseInstruction(NewCopySource);
});
MaybeAlign CopySourceAlign = MDep->getSourceAlign();
// We just need to calculate the actual size of the copy.
More information about the llvm-commits
mailing list