[llvm] [MemCpyOptimizer] Prevent Merging a Store Into Memset of an `undef` (PR #181609)

via llvm-commits llvm-commits at lists.llvm.org
Sun Feb 15 23:57:57 PST 2026


https://github.com/veera-sivarajan created https://github.com/llvm/llvm-project/pull/181609

MemCopyOptimizer was merging a store instruction into a memset of an
`undef` value and emitted a large memset for the memset and store combined.

This PR prevents MemCopyOptimizer from merging a store instruction into a
memset of an `undef` value since it can be removed by subsequent cleanup
passes.

Helps fix https://github.com/rust-lang/rust/issues/152541

>From 2e38fce0871ba537dda176f3404ae7a1288d0e6e Mon Sep 17 00:00:00 2001
From: Veera <sveera.2001 at gmail.com>
Date: Mon, 16 Feb 2026 07:24:43 +0000
Subject: [PATCH 1/2] Add Test

---
 llvm/test/Transforms/MemCpyOpt/memcpy.ll | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/llvm/test/Transforms/MemCpyOpt/memcpy.ll b/llvm/test/Transforms/MemCpyOpt/memcpy.ll
index 89d8eb1ee6711..39f83fd2826fa 100644
--- a/llvm/test/Transforms/MemCpyOpt/memcpy.ll
+++ b/llvm/test/Transforms/MemCpyOpt/memcpy.ll
@@ -8,6 +8,7 @@ target triple = "i686-apple-darwin9"
 %1 = type { i32, i32 }
 
 @C = external constant [0 x i8]
+ at undef = private constant [4000 x i8] undef, align 4
 
 declare void @llvm.memcpy.p1.p0.i64(ptr addrspace(1) nocapture, ptr nocapture, i64, i1) nounwind
 declare void @llvm.memcpy.p0.p1.i64(ptr nocapture, ptr addrspace(1) nocapture, i64, i1) nounwind
@@ -924,6 +925,22 @@ define void @test(ptr noalias writable dereferenceable(4) %p) {
   ret void
 }
 
+; MemCpyOptimizer need not merge a store into a memset of undef value since
+; it will be removed by subsequent passes.
+define void @prevent_memsetting_a_undef_store(ptr %result) {
+; CHECK-LABEL: @prevent_memsetting_a_undef_store(
+; CHECK-NEXT:    [[RESULT_4000:%.*]] = getelementptr inbounds nuw i8, ptr [[RESULT:%.*]], i64 4000
+; CHECK-NEXT:    call void @llvm.memset.p0.i64(ptr [[RESULT]], i8 0, i64 4008, i1 false)
+; CHECK-NEXT:    ret void
+;
+  call void @llvm.memcpy.p0.p0.i64(ptr %result, ptr @undef, i64 4000, i1 false)
+  %result.4000 = getelementptr inbounds nuw i8, ptr %result, i64 4000
+  store i64 0, ptr %result.4000, align 8
+  ret void
+}
+
+
+
 !0 = !{!0}
 !1 = !{!1, !0}
 !2 = !{!1}

>From f7f424c95d1196c9f6b3d7a29765e539cbf9f6c4 Mon Sep 17 00:00:00 2001
From: Veera <sveera.2001 at gmail.com>
Date: Mon, 16 Feb 2026 07:49:02 +0000
Subject: [PATCH 2/2] [MemCpyOptimizer] Prevent Merging a Store Into Memset of
 an `undef`

MemCopyOptimizer was merging a store instruction into a memset of an
`undef` value and emitted a large memset for the memset and store combined.

This PR prevents MemCopyOptimizer from merging a store instruction into a
memset of an `undef` value since it can be removed by subsequent cleanup
passes.
---
 llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp | 6 ++++--
 llvm/test/Transforms/MemCpyOpt/memcpy.ll       | 5 +++--
 2 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp b/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp
index 0f75e53cb9998..a8531397e1310 100644
--- a/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp
+++ b/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp
@@ -411,8 +411,10 @@ Instruction *MemCpyOptPass::tryMergingIntoMemset(Instruction *StartInst,
 
       // Check to see if this stored value is of the same byte-splattable value.
       Value *StoredByte = isBytewiseValue(StoredVal, DL);
-      if (isa<UndefValue>(ByteVal) && StoredByte)
-        ByteVal = StoredByte;
+      // We can blindly merge this store into `StartInst` if it's being filled
+      // with an undef value but we don't because:
+      // 1. `StartInst` can be removed since it's storing an `undef`.
+      // 2. The resulting memset will be much larger than it needs to be.
       if (ByteVal != StoredByte)
         break;
 
diff --git a/llvm/test/Transforms/MemCpyOpt/memcpy.ll b/llvm/test/Transforms/MemCpyOpt/memcpy.ll
index 39f83fd2826fa..571f5dc5fcfe9 100644
--- a/llvm/test/Transforms/MemCpyOpt/memcpy.ll
+++ b/llvm/test/Transforms/MemCpyOpt/memcpy.ll
@@ -929,8 +929,9 @@ define void @test(ptr noalias writable dereferenceable(4) %p) {
 ; it will be removed by subsequent passes.
 define void @prevent_memsetting_a_undef_store(ptr %result) {
 ; CHECK-LABEL: @prevent_memsetting_a_undef_store(
-; CHECK-NEXT:    [[RESULT_4000:%.*]] = getelementptr inbounds nuw i8, ptr [[RESULT:%.*]], i64 4000
-; CHECK-NEXT:    call void @llvm.memset.p0.i64(ptr [[RESULT]], i8 0, i64 4008, i1 false)
+; CHECK-NEXT:    call void @llvm.memset.p0.i64(ptr [[RESULT:%.*]], i8 undef, i64 4000, i1 false)
+; CHECK-NEXT:    [[RESULT_4000:%.*]] = getelementptr inbounds nuw i8, ptr [[RESULT]], i64 4000
+; CHECK-NEXT:    store i64 0, ptr [[RESULT_4000]], align 8
 ; CHECK-NEXT:    ret void
 ;
   call void @llvm.memcpy.p0.p0.i64(ptr %result, ptr @undef, i64 4000, i1 false)



More information about the llvm-commits mailing list