[llvm] [LoopIdiom] Fix and improve undef handling in store chains that become memsets (PR #230863)

Ömer Sinan Ağacan via llvm-commits llvm-commits at lists.llvm.org
Sat Oct 10 14:27:46 PDT 2026


https://github.com/osa1 created https://github.com/llvm/llvm-project/pull/230863

This fixes the miscompile in a chain of stores like

    %a = getelementptr inbounds [2 x i8], ptr %p, i64 %i, i64 0
    %b = getelementptr inbounds [2 x i8], ptr %p, i64 %i, i64 1
    store i8 poison, ptr %a
    store i8 1, ptr %b

Which is currently transformed into a memset of poison:

    call void @llvm.memset.p0.i64(ptr align 1 %p, i8 poison, i64 %0, i1 false)

Which is a miscompile: https://alive2.llvm.org/ce/z/5X7QLM

With this patch we use the defined value in the chain as the memset value:

    call void @llvm.memset.p0.i64(ptr align 1 %p, i8 1, i64 %0, i1 false)

This is allowed, as the program becomes more defined: https://alive2.llvm.org/ce/z/lJE20Y

As a new transformation, we also recognize the other order

    store i8 1, ptr %a
    store i8 poison, ptr %b

This also allows chaining more stores with undef/poisons in between.

Also added a test with a missed optimization in the PR base and also with the
PR:

    store i8 1, ptr %i0
    store i8 1, ptr %i1
    store i8 undef, ptr %i2
    store i8 2, ptr %i3
    store i8 2, ptr %i4

This could be turned into two `memset`s.

>From a265e887cfd1f9a1c5afa03234f6273953e90bed Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C3=96mer=20Sinan=20A=C4=9Facan?= <omer at osa1.net>
Date: Sat, 10 Oct 2026 21:54:22 +0100
Subject: [PATCH 1/2] Add tests

---
 .../LoopIdiom/memset-undef-stores.ll          | 269 ++++++++++++++++++
 1 file changed, 269 insertions(+)
 create mode 100644 llvm/test/Transforms/LoopIdiom/memset-undef-stores.ll

diff --git a/llvm/test/Transforms/LoopIdiom/memset-undef-stores.ll b/llvm/test/Transforms/LoopIdiom/memset-undef-stores.ll
new file mode 100644
index 0000000000000..538df3abeee1c
--- /dev/null
+++ b/llvm/test/Transforms/LoopIdiom/memset-undef-stores.ll
@@ -0,0 +1,269 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -passes=loop-idiom -S < %s | FileCheck %s
+
+; With a poison or undef in the chain, use the non-{poison,undef} value in
+; the chain as the memset value.
+
+define void @poison_head(ptr %p, i64 %n) {
+; CHECK-LABEL: define void @poison_head(
+; CHECK-SAME: ptr [[P:%.*]], i64 [[N:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[TMP0:%.*]] = shl nuw i64 [[N]], 1
+; CHECK-NEXT:    call void @llvm.memset.p0.i64(ptr align 1 [[P]], i8 poison, i64 [[TMP0]], i1 false)
+; CHECK-NEXT:    br label %[[LOOP:.*]]
+; CHECK:       [[LOOP]]:
+; CHECK-NEXT:    [[I:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[I_NEXT:%.*]], %[[LOOP]] ]
+; CHECK-NEXT:    [[A:%.*]] = getelementptr inbounds [2 x i8], ptr [[P]], i64 [[I]], i64 0
+; CHECK-NEXT:    [[B:%.*]] = getelementptr inbounds [2 x i8], ptr [[P]], i64 [[I]], i64 1
+; CHECK-NEXT:    [[I_NEXT]] = add nuw nsw i64 [[I]], 1
+; CHECK-NEXT:    [[C:%.*]] = icmp ne i64 [[I_NEXT]], [[N]]
+; CHECK-NEXT:    br i1 [[C]], label %[[LOOP]], label %[[EXIT:.*]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %loop
+
+loop:
+  %i = phi i64 [ 0, %entry ], [ %i.next, %loop ]
+  %a = getelementptr inbounds [2 x i8], ptr %p, i64 %i, i64 0
+  %b = getelementptr inbounds [2 x i8], ptr %p, i64 %i, i64 1
+  store i8 poison, ptr %a
+  store i8 1, ptr %b
+  %i.next = add nuw nsw i64 %i, 1
+  %c = icmp ne i64 %i.next, %n
+  br i1 %c, label %loop, label %exit
+
+exit:
+  ret void
+}
+
+define void @poison_tail(ptr %p, i64 %n) {
+; CHECK-LABEL: define void @poison_tail(
+; CHECK-SAME: ptr [[P:%.*]], i64 [[N:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    br label %[[LOOP:.*]]
+; CHECK:       [[LOOP]]:
+; CHECK-NEXT:    [[I:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[I_NEXT:%.*]], %[[LOOP]] ]
+; CHECK-NEXT:    [[A:%.*]] = getelementptr inbounds [2 x i8], ptr [[P]], i64 [[I]], i64 0
+; CHECK-NEXT:    [[B:%.*]] = getelementptr inbounds [2 x i8], ptr [[P]], i64 [[I]], i64 1
+; CHECK-NEXT:    store i8 1, ptr [[A]], align 1
+; CHECK-NEXT:    store i8 poison, ptr [[B]], align 1
+; CHECK-NEXT:    [[I_NEXT]] = add nuw nsw i64 [[I]], 1
+; CHECK-NEXT:    [[C:%.*]] = icmp ne i64 [[I_NEXT]], [[N]]
+; CHECK-NEXT:    br i1 [[C]], label %[[LOOP]], label %[[EXIT:.*]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %loop
+
+loop:
+  %i = phi i64 [ 0, %entry ], [ %i.next, %loop ]
+  %a = getelementptr inbounds [2 x i8], ptr %p, i64 %i, i64 0
+  %b = getelementptr inbounds [2 x i8], ptr %p, i64 %i, i64 1
+  store i8 1, ptr %a
+  store i8 poison, ptr %b
+  %i.next = add nuw nsw i64 %i, 1
+  %c = icmp ne i64 %i.next, %n
+  br i1 %c, label %loop, label %exit
+
+exit:
+  ret void
+}
+
+define void @undef_head(ptr %p, i64 %n) {
+; CHECK-LABEL: define void @undef_head(
+; CHECK-SAME: ptr [[P:%.*]], i64 [[N:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[TMP0:%.*]] = shl nuw i64 [[N]], 1
+; CHECK-NEXT:    call void @llvm.memset.p0.i64(ptr align 1 [[P]], i8 undef, i64 [[TMP0]], i1 false)
+; CHECK-NEXT:    br label %[[LOOP:.*]]
+; CHECK:       [[LOOP]]:
+; CHECK-NEXT:    [[I:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[I_NEXT:%.*]], %[[LOOP]] ]
+; CHECK-NEXT:    [[A:%.*]] = getelementptr inbounds [2 x i8], ptr [[P]], i64 [[I]], i64 0
+; CHECK-NEXT:    [[B:%.*]] = getelementptr inbounds [2 x i8], ptr [[P]], i64 [[I]], i64 1
+; CHECK-NEXT:    [[I_NEXT]] = add nuw nsw i64 [[I]], 1
+; CHECK-NEXT:    [[C:%.*]] = icmp ne i64 [[I_NEXT]], [[N]]
+; CHECK-NEXT:    br i1 [[C]], label %[[LOOP]], label %[[EXIT:.*]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %loop
+
+loop:
+  %i = phi i64 [ 0, %entry ], [ %i.next, %loop ]
+  %a = getelementptr inbounds [2 x i8], ptr %p, i64 %i, i64 0
+  %b = getelementptr inbounds [2 x i8], ptr %p, i64 %i, i64 1
+  store i8 undef, ptr %a
+  store i8 1, ptr %b
+  %i.next = add nuw nsw i64 %i, 1
+  %c = icmp ne i64 %i.next, %n
+  br i1 %c, label %loop, label %exit
+
+exit:
+  ret void
+}
+
+define void @undef_tail(ptr %p, i64 %n) {
+; CHECK-LABEL: define void @undef_tail(
+; CHECK-SAME: ptr [[P:%.*]], i64 [[N:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    br label %[[LOOP:.*]]
+; CHECK:       [[LOOP]]:
+; CHECK-NEXT:    [[I:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[I_NEXT:%.*]], %[[LOOP]] ]
+; CHECK-NEXT:    [[A:%.*]] = getelementptr inbounds [2 x i8], ptr [[P]], i64 [[I]], i64 0
+; CHECK-NEXT:    [[B:%.*]] = getelementptr inbounds [2 x i8], ptr [[P]], i64 [[I]], i64 1
+; CHECK-NEXT:    store i8 1, ptr [[A]], align 1
+; CHECK-NEXT:    store i8 undef, ptr [[B]], align 1
+; CHECK-NEXT:    [[I_NEXT]] = add nuw nsw i64 [[I]], 1
+; CHECK-NEXT:    [[C:%.*]] = icmp ne i64 [[I_NEXT]], [[N]]
+; CHECK-NEXT:    br i1 [[C]], label %[[LOOP]], label %[[EXIT:.*]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %loop
+
+loop:
+  %i = phi i64 [ 0, %entry ], [ %i.next, %loop ]
+  %a = getelementptr inbounds [2 x i8], ptr %p, i64 %i, i64 0
+  %b = getelementptr inbounds [2 x i8], ptr %p, i64 %i, i64 1
+  store i8 1, ptr %a
+  store i8 undef, ptr %b
+  %i.next = add nuw nsw i64 %i, 1
+  %c = icmp ne i64 %i.next, %n
+  br i1 %c, label %loop, label %exit
+
+exit:
+  ret void
+}
+
+define void @undef_mid(ptr %p, i64 %n) {
+; CHECK-LABEL: define void @undef_mid(
+; CHECK-SAME: ptr [[P:%.*]], i64 [[N:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    br label %[[LOOP:.*]]
+; CHECK:       [[LOOP]]:
+; CHECK-NEXT:    [[I:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[I_NEXT:%.*]], %[[LOOP]] ]
+; CHECK-NEXT:    [[A:%.*]] = getelementptr inbounds [3 x i8], ptr [[P]], i64 [[I]], i64 0
+; CHECK-NEXT:    [[B:%.*]] = getelementptr inbounds [3 x i8], ptr [[P]], i64 [[I]], i64 1
+; CHECK-NEXT:    [[C:%.*]] = getelementptr inbounds [3 x i8], ptr [[P]], i64 [[I]], i64 2
+; CHECK-NEXT:    store i8 1, ptr [[A]], align 1
+; CHECK-NEXT:    store i8 undef, ptr [[B]], align 1
+; CHECK-NEXT:    store i8 1, ptr [[C]], align 1
+; CHECK-NEXT:    [[I_NEXT]] = add nuw nsw i64 [[I]], 1
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i64 [[I_NEXT]], [[N]]
+; CHECK-NEXT:    br i1 [[CMP]], label %[[LOOP]], label %[[EXIT:.*]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %loop
+
+loop:
+  %i = phi i64 [ 0, %entry ], [ %i.next, %loop ]
+  %a = getelementptr inbounds [3 x i8], ptr %p, i64 %i, i64 0
+  %b = getelementptr inbounds [3 x i8], ptr %p, i64 %i, i64 1
+  %c = getelementptr inbounds [3 x i8], ptr %p, i64 %i, i64 2
+  store i8 1, ptr %a
+  store i8 undef, ptr %b
+  store i8 1, ptr %c
+  %i.next = add nuw nsw i64 %i, 1
+  %cmp = icmp ne i64 %i.next, %n
+  br i1 %cmp, label %loop, label %exit
+
+exit:
+  ret void
+}
+
+define void @undef_mid_different(ptr %p, i64 %n) {
+; CHECK-LABEL: define void @undef_mid_different(
+; CHECK-SAME: ptr [[P:%.*]], i64 [[N:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    br label %[[LOOP:.*]]
+; CHECK:       [[LOOP]]:
+; CHECK-NEXT:    [[I:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[I_NEXT:%.*]], %[[LOOP]] ]
+; CHECK-NEXT:    [[A:%.*]] = getelementptr inbounds [3 x i8], ptr [[P]], i64 [[I]], i64 0
+; CHECK-NEXT:    [[B:%.*]] = getelementptr inbounds [3 x i8], ptr [[P]], i64 [[I]], i64 1
+; CHECK-NEXT:    [[C:%.*]] = getelementptr inbounds [3 x i8], ptr [[P]], i64 [[I]], i64 2
+; CHECK-NEXT:    store i8 1, ptr [[A]], align 1
+; CHECK-NEXT:    store i8 undef, ptr [[B]], align 1
+; CHECK-NEXT:    store i8 2, ptr [[C]], align 1
+; CHECK-NEXT:    [[I_NEXT]] = add nuw nsw i64 [[I]], 1
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i64 [[I_NEXT]], [[N]]
+; CHECK-NEXT:    br i1 [[CMP]], label %[[LOOP]], label %[[EXIT:.*]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %loop
+
+loop:
+  %i = phi i64 [ 0, %entry ], [ %i.next, %loop ]
+  %a = getelementptr inbounds [3 x i8], ptr %p, i64 %i, i64 0
+  %b = getelementptr inbounds [3 x i8], ptr %p, i64 %i, i64 1
+  %c = getelementptr inbounds [3 x i8], ptr %p, i64 %i, i64 2
+  store i8 1, ptr %a
+  store i8 undef, ptr %b
+  store i8 2, ptr %c
+  %i.next = add nuw nsw i64 %i, 1
+  %cmp = icmp ne i64 %i.next, %n
+  br i1 %cmp, label %loop, label %exit
+
+exit:
+  ret void
+}
+
+; Missed optimization: we could emit two memsets here.
+;
+; The first loop in `LoopIdiomRecognize::processLoopStores` only considers
+; stores pair-wise, and so when it sees `(1, undef)` and then `(undef, 2)` it
+; links both and creates a chain of `(1, 1, undef, 2, 2)`. The second loop
+; avoid generating a memset for it, but it could create two memsets.
+define void @undef_mid_missed_optimization(ptr %p, i64 %n) {
+; CHECK-LABEL: define void @undef_mid_missed_optimization(
+; CHECK-SAME: ptr [[P:%.*]], i64 [[N:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    br label %[[LOOP:.*]]
+; CHECK:       [[LOOP]]:
+; CHECK-NEXT:    [[I:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[I_NEXT:%.*]], %[[LOOP]] ]
+; CHECK-NEXT:    [[I0:%.*]] = getelementptr inbounds [5 x i8], ptr [[P]], i64 [[I]], i64 0
+; CHECK-NEXT:    [[I1:%.*]] = getelementptr inbounds [5 x i8], ptr [[P]], i64 [[I]], i64 1
+; CHECK-NEXT:    [[I2:%.*]] = getelementptr inbounds [5 x i8], ptr [[P]], i64 [[I]], i64 2
+; CHECK-NEXT:    [[I3:%.*]] = getelementptr inbounds [5 x i8], ptr [[P]], i64 [[I]], i64 3
+; CHECK-NEXT:    [[I4:%.*]] = getelementptr inbounds [5 x i8], ptr [[P]], i64 [[I]], i64 4
+; CHECK-NEXT:    store i8 1, ptr [[I0]], align 1
+; CHECK-NEXT:    store i8 1, ptr [[I1]], align 1
+; CHECK-NEXT:    store i8 undef, ptr [[I2]], align 1
+; CHECK-NEXT:    store i8 2, ptr [[I3]], align 1
+; CHECK-NEXT:    store i8 2, ptr [[I4]], align 1
+; CHECK-NEXT:    [[I_NEXT]] = add nuw nsw i64 [[I]], 1
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i64 [[I_NEXT]], [[N]]
+; CHECK-NEXT:    br i1 [[CMP]], label %[[LOOP]], label %[[EXIT:.*]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %loop
+
+loop:
+  %i = phi i64 [ 0, %entry ], [ %i.next, %loop ]
+  %i0 = getelementptr inbounds [5 x i8], ptr %p, i64 %i, i64 0
+  %i1 = getelementptr inbounds [5 x i8], ptr %p, i64 %i, i64 1
+  %i2 = getelementptr inbounds [5 x i8], ptr %p, i64 %i, i64 2
+  %i3 = getelementptr inbounds [5 x i8], ptr %p, i64 %i, i64 3
+  %i4 = getelementptr inbounds [5 x i8], ptr %p, i64 %i, i64 4
+  store i8 1, ptr %i0
+  store i8 1, ptr %i1
+  store i8 undef, ptr %i2
+  store i8 2, ptr %i3
+  store i8 2, ptr %i4
+  %i.next = add nuw nsw i64 %i, 1
+  %cmp = icmp ne i64 %i.next, %n
+  br i1 %cmp, label %loop, label %exit
+
+exit:
+  ret void
+}

>From ebbcf67259a0321b425c329e7f1f272b95575d6b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C3=96mer=20Sinan=20A=C4=9Facan?= <omer at osa1.net>
Date: Sat, 10 Oct 2026 21:55:11 +0100
Subject: [PATCH 2/2] Fix and update tests

---
 .../Transforms/Scalar/LoopIdiomRecognize.cpp  | 52 ++++++++++++++++---
 .../LoopIdiom/memset-undef-stores.ll          | 17 +++---
 2 files changed, 53 insertions(+), 16 deletions(-)

diff --git a/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp b/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp
index 72c4208adaf33..f6f83548a9d09 100644
--- a/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp
@@ -405,7 +405,7 @@ static APInt getStoreStride(const SCEVAddRecExpr *StoreEv) {
 }
 
 /// getMemSetPatternValue - If a strided store of the specified value is safe to
-/// turn into a memset.patternn intrinsic, return the Constant that should
+/// turn into a memset.pattern intrinsic, return the Constant that should
 /// be passed in. Otherwise, return null.
 ///
 /// TODO this function could allow more constants than it does today (e.g.
@@ -643,8 +643,12 @@ bool LoopIdiomRecognize::processLoopStores(SmallVectorImpl<StoreInst *> &SL,
   SetVector<StoreInst *> Heads, Tails;
   SmallDenseMap<StoreInst *, StoreInst *> ConsecutiveChain;
 
-  // Do a quadratic search on all of the given stores and find
-  // all of the pairs of stores that follow each other.
+  // Do a quadratic search on all of the given stores and find all of the pairs
+  // of stores that follow each other.
+  //
+  // This only considers pairs and chains stores of values like 1, undef, 2, in
+  // a single chain. The next loop considers stored values and avoids turning
+  // those chains into memsets.
   SmallVector<unsigned, 16> IndexQueue;
   for (unsigned i = 0, e = SL.size(); i < e; ++i) {
     assert(SL[i]->isSimple() && "Expected only non-volatile stores.");
@@ -654,7 +658,8 @@ bool LoopIdiomRecognize::processLoopStores(SmallVectorImpl<StoreInst *> &SL,
     const SCEVAddRecExpr *FirstStoreEv =
         cast<SCEVAddRecExpr>(SE->getSCEV(FirstStorePtr));
     APInt FirstStride = getStoreStride(FirstStoreEv);
-    unsigned FirstStoreSize = DL->getTypeStoreSize(SL[i]->getValueOperand()->getType());
+    unsigned FirstStoreSize =
+        DL->getTypeStoreSize(SL[i]->getValueOperand()->getType());
 
     // See if we can optimize just this store in isolation.
     if (FirstStride == FirstStoreSize || -FirstStride == FirstStoreSize) {
@@ -710,12 +715,14 @@ bool LoopIdiomRecognize::processLoopStores(SmallVectorImpl<StoreInst *> &SL,
         if (For == ForMemset::Yes) {
           if (isa<UndefValue>(FirstSplatValue))
             FirstSplatValue = SecondSplatValue;
-          if (FirstSplatValue != SecondSplatValue)
+          if (!isa<UndefValue>(SecondSplatValue) &&
+              FirstSplatValue != SecondSplatValue)
             continue;
         } else {
           if (isa<UndefValue>(FirstPatternValue))
             FirstPatternValue = SecondPatternValue;
-          if (FirstPatternValue != SecondPatternValue)
+          if (!isa<UndefValue>(SecondPatternValue) &&
+              FirstPatternValue != SecondPatternValue)
             continue;
         }
         Tails.insert(SL[k]);
@@ -741,6 +748,11 @@ bool LoopIdiomRecognize::processLoopStores(SmallVectorImpl<StoreInst *> &SL,
     SmallPtrSet<Instruction *, 8> AdjacentStores;
     StoreInst *HeadStore = I;
     unsigned StoreSize = 0;
+    Value *StoredVal = HeadStore->getValueOperand();
+    Value *StoredBytewiseOrPatternVal =
+        For == ForMemset::Yes ? isBytewiseValue(StoredVal, *DL)
+                              : getMemSetPatternValue(StoredVal, DL);
+    bool ValueMismatch = false;
 
     // Collect the chain into a list.
     while (Tails.count(I) || Heads.count(I)) {
@@ -748,12 +760,38 @@ bool LoopIdiomRecognize::processLoopStores(SmallVectorImpl<StoreInst *> &SL,
         break;
       AdjacentStores.insert(I);
 
+      Value *NextVal = I->getValueOperand();
+      Value *NextBytewiseOrPatternVal =
+          For == ForMemset::Yes ? isBytewiseValue(NextVal, *DL)
+                                : getMemSetPatternValue(NextVal, DL);
+
+      // Use the first non-undef value as the chain's value.
+      if (isa<UndefValue>(StoredBytewiseOrPatternVal)) {
+        StoredVal = NextVal;
+        StoredBytewiseOrPatternVal = NextBytewiseOrPatternVal;
+      }
+
+      // The first loop considers the stores pair-wise, and can chain stores
+      // with different values with `undef`s in between. Check for those cases
+      // here and avoid creating a memset for such chains.
+      //
+      // TODO: We could break the chain into two smaller ones here. See the test
+      // `undef_mid_missed_optimization`.
+      if (!isa<UndefValue>(StoredBytewiseOrPatternVal) &&
+          !isa<UndefValue>(NextBytewiseOrPatternVal) &&
+          StoredBytewiseOrPatternVal != NextBytewiseOrPatternVal) {
+        ValueMismatch = true;
+        break;
+      }
+
       StoreSize += DL->getTypeStoreSize(I->getValueOperand()->getType());
       // Move to the next value in the chain.
       I = ConsecutiveChain[I];
     }
 
-    Value *StoredVal = HeadStore->getValueOperand();
+    if (ValueMismatch)
+      continue;
+
     Value *StorePtr = HeadStore->getPointerOperand();
     const SCEVAddRecExpr *StoreEv = cast<SCEVAddRecExpr>(SE->getSCEV(StorePtr));
     APInt Stride = getStoreStride(StoreEv);
diff --git a/llvm/test/Transforms/LoopIdiom/memset-undef-stores.ll b/llvm/test/Transforms/LoopIdiom/memset-undef-stores.ll
index 538df3abeee1c..259968431357a 100644
--- a/llvm/test/Transforms/LoopIdiom/memset-undef-stores.ll
+++ b/llvm/test/Transforms/LoopIdiom/memset-undef-stores.ll
@@ -9,7 +9,7 @@ define void @poison_head(ptr %p, i64 %n) {
 ; CHECK-SAME: ptr [[P:%.*]], i64 [[N:%.*]]) {
 ; CHECK-NEXT:  [[ENTRY:.*]]:
 ; CHECK-NEXT:    [[TMP0:%.*]] = shl nuw i64 [[N]], 1
-; CHECK-NEXT:    call void @llvm.memset.p0.i64(ptr align 1 [[P]], i8 poison, i64 [[TMP0]], i1 false)
+; CHECK-NEXT:    call void @llvm.memset.p0.i64(ptr align 1 [[P]], i8 1, i64 [[TMP0]], i1 false)
 ; CHECK-NEXT:    br label %[[LOOP:.*]]
 ; CHECK:       [[LOOP]]:
 ; CHECK-NEXT:    [[I:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[I_NEXT:%.*]], %[[LOOP]] ]
@@ -42,13 +42,13 @@ define void @poison_tail(ptr %p, i64 %n) {
 ; CHECK-LABEL: define void @poison_tail(
 ; CHECK-SAME: ptr [[P:%.*]], i64 [[N:%.*]]) {
 ; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[TMP0:%.*]] = shl nuw i64 [[N]], 1
+; CHECK-NEXT:    call void @llvm.memset.p0.i64(ptr align 1 [[P]], i8 1, i64 [[TMP0]], i1 false)
 ; CHECK-NEXT:    br label %[[LOOP:.*]]
 ; CHECK:       [[LOOP]]:
 ; CHECK-NEXT:    [[I:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[I_NEXT:%.*]], %[[LOOP]] ]
 ; CHECK-NEXT:    [[A:%.*]] = getelementptr inbounds [2 x i8], ptr [[P]], i64 [[I]], i64 0
 ; CHECK-NEXT:    [[B:%.*]] = getelementptr inbounds [2 x i8], ptr [[P]], i64 [[I]], i64 1
-; CHECK-NEXT:    store i8 1, ptr [[A]], align 1
-; CHECK-NEXT:    store i8 poison, ptr [[B]], align 1
 ; CHECK-NEXT:    [[I_NEXT]] = add nuw nsw i64 [[I]], 1
 ; CHECK-NEXT:    [[C:%.*]] = icmp ne i64 [[I_NEXT]], [[N]]
 ; CHECK-NEXT:    br i1 [[C]], label %[[LOOP]], label %[[EXIT:.*]]
@@ -77,7 +77,7 @@ define void @undef_head(ptr %p, i64 %n) {
 ; CHECK-SAME: ptr [[P:%.*]], i64 [[N:%.*]]) {
 ; CHECK-NEXT:  [[ENTRY:.*]]:
 ; CHECK-NEXT:    [[TMP0:%.*]] = shl nuw i64 [[N]], 1
-; CHECK-NEXT:    call void @llvm.memset.p0.i64(ptr align 1 [[P]], i8 undef, i64 [[TMP0]], i1 false)
+; CHECK-NEXT:    call void @llvm.memset.p0.i64(ptr align 1 [[P]], i8 1, i64 [[TMP0]], i1 false)
 ; CHECK-NEXT:    br label %[[LOOP:.*]]
 ; CHECK:       [[LOOP]]:
 ; CHECK-NEXT:    [[I:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[I_NEXT:%.*]], %[[LOOP]] ]
@@ -110,13 +110,13 @@ define void @undef_tail(ptr %p, i64 %n) {
 ; CHECK-LABEL: define void @undef_tail(
 ; CHECK-SAME: ptr [[P:%.*]], i64 [[N:%.*]]) {
 ; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[TMP0:%.*]] = shl nuw i64 [[N]], 1
+; CHECK-NEXT:    call void @llvm.memset.p0.i64(ptr align 1 [[P]], i8 1, i64 [[TMP0]], i1 false)
 ; CHECK-NEXT:    br label %[[LOOP:.*]]
 ; CHECK:       [[LOOP]]:
 ; CHECK-NEXT:    [[I:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[I_NEXT:%.*]], %[[LOOP]] ]
 ; CHECK-NEXT:    [[A:%.*]] = getelementptr inbounds [2 x i8], ptr [[P]], i64 [[I]], i64 0
 ; CHECK-NEXT:    [[B:%.*]] = getelementptr inbounds [2 x i8], ptr [[P]], i64 [[I]], i64 1
-; CHECK-NEXT:    store i8 1, ptr [[A]], align 1
-; CHECK-NEXT:    store i8 undef, ptr [[B]], align 1
 ; CHECK-NEXT:    [[I_NEXT]] = add nuw nsw i64 [[I]], 1
 ; CHECK-NEXT:    [[C:%.*]] = icmp ne i64 [[I_NEXT]], [[N]]
 ; CHECK-NEXT:    br i1 [[C]], label %[[LOOP]], label %[[EXIT:.*]]
@@ -144,15 +144,14 @@ define void @undef_mid(ptr %p, i64 %n) {
 ; CHECK-LABEL: define void @undef_mid(
 ; CHECK-SAME: ptr [[P:%.*]], i64 [[N:%.*]]) {
 ; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[TMP0:%.*]] = mul nuw i64 [[N]], 3
+; CHECK-NEXT:    call void @llvm.memset.p0.i64(ptr align 1 [[P]], i8 1, i64 [[TMP0]], i1 false)
 ; CHECK-NEXT:    br label %[[LOOP:.*]]
 ; CHECK:       [[LOOP]]:
 ; CHECK-NEXT:    [[I:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[I_NEXT:%.*]], %[[LOOP]] ]
 ; CHECK-NEXT:    [[A:%.*]] = getelementptr inbounds [3 x i8], ptr [[P]], i64 [[I]], i64 0
 ; CHECK-NEXT:    [[B:%.*]] = getelementptr inbounds [3 x i8], ptr [[P]], i64 [[I]], i64 1
 ; CHECK-NEXT:    [[C:%.*]] = getelementptr inbounds [3 x i8], ptr [[P]], i64 [[I]], i64 2
-; CHECK-NEXT:    store i8 1, ptr [[A]], align 1
-; CHECK-NEXT:    store i8 undef, ptr [[B]], align 1
-; CHECK-NEXT:    store i8 1, ptr [[C]], align 1
 ; CHECK-NEXT:    [[I_NEXT]] = add nuw nsw i64 [[I]], 1
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i64 [[I_NEXT]], [[N]]
 ; CHECK-NEXT:    br i1 [[CMP]], label %[[LOOP]], label %[[EXIT:.*]]



More information about the llvm-commits mailing list