[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