[llvm] [VectorUtils] Pad concatenateVectors with poison instead of undef (PR #225598)
Le Gia Bao via llvm-commits
llvm-commits at lists.llvm.org
Sun Oct 4 07:01:30 PDT 2026
https://github.com/L3GiaBao updated https://github.com/llvm/llvm-project/pull/225598
>From b337318234db2550d090703181e7bd4b3f4ec44e Mon Sep 17 00:00:00 2001
From: Le Gia Bao <legiabao7300 at gmail.com>
Date: Sun, 4 Oct 2026 20:19:10 +0700
Subject: [PATCH 1/2] add tests
---
.../interleaved-store-concat-poison-pad.ll | 127 ++++++++++++++++++
1 file changed, 127 insertions(+)
create mode 100644 llvm/test/Transforms/LoopVectorize/X86/interleaved-store-concat-poison-pad.ll
diff --git a/llvm/test/Transforms/LoopVectorize/X86/interleaved-store-concat-poison-pad.ll b/llvm/test/Transforms/LoopVectorize/X86/interleaved-store-concat-poison-pad.ll
new file mode 100644
index 0000000000000..60ecbed24176b
--- /dev/null
+++ b/llvm/test/Transforms/LoopVectorize/X86/interleaved-store-concat-poison-pad.ll
@@ -0,0 +1,127 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -passes=loop-vectorize -mcpu=skx -enable-interleaved-mem-accesses -enable-masked-interleaved-mem-accesses=1 -force-vector-width=8 -force-vector-interleave=1 -S < %s | FileCheck %s
+
+target triple = "x86_64-unknown-linux-gnu"
+
+%triple.i32 = type { i32, i32, i32 }
+
+define void @concat_pad_poison_splat(ptr %a, i64 %n) {
+; CHECK-LABEL: define void @concat_pad_poison_splat(
+; CHECK-SAME: ptr [[A:%.*]], i64 [[N:%.*]]) #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: [[MIN_ITERS_CHECK:%.*]] = icmp ult i64 [[N]], 8
+; CHECK-NEXT: br i1 [[MIN_ITERS_CHECK]], label %[[SCALAR_PH:.*]], label %[[VECTOR_PH:.*]]
+; CHECK: [[VECTOR_PH]]:
+; CHECK-NEXT: [[TMP0:%.*]] = and i64 [[N]], 7
+; CHECK-NEXT: [[N_VEC:%.*]] = sub i64 [[N]], [[TMP0]]
+; CHECK-NEXT: br label %[[VECTOR_BODY:.*]]
+; CHECK: [[VECTOR_BODY]]:
+; CHECK-NEXT: [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[VECTOR_BODY]] ]
+; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[TRIPLE_I32:%.*]], ptr [[A]], i64 [[INDEX]], i32 0
+; CHECK-NEXT: call void @llvm.masked.store.v24i32.p0(<24 x i32> <i32 0, i32 1, i32 poison, i32 0, i32 1, i32 poison, i32 0, i32 1, i32 poison, i32 0, i32 1, i32 poison, i32 0, i32 1, i32 poison, i32 0, i32 1, i32 poison, i32 0, i32 1, i32 poison, i32 0, i32 1, i32 poison>, ptr align 4 [[TMP1]], <24 x i1> <i1 true, i1 true, i1 false, i1 true, i1 true, i1 false, i1 true, i1 true, i1 false, i1 true, i1 true, i1 false, i1 true, i1 true, i1 false, i1 true, i1 true, i1 false, i1 true, i1 true, i1 false, i1 true, i1 true, i1 false>)
+; CHECK-NEXT: [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 8
+; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]]
+; CHECK-NEXT: br i1 [[TMP2]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP0:![0-9]+]]
+; CHECK: [[MIDDLE_BLOCK]]:
+; CHECK-NEXT: [[CMP_N:%.*]] = icmp eq i64 [[N]], [[N_VEC]]
+; CHECK-NEXT: br i1 [[CMP_N]], label %[[EXIT:.*]], label %[[SCALAR_PH]]
+; CHECK: [[SCALAR_PH]]:
+; CHECK-NEXT: [[BC_RESUME_VAL:%.*]] = phi i64 [ [[N_VEC]], %[[MIDDLE_BLOCK]] ], [ 0, %[[ENTRY]] ]
+; CHECK-NEXT: br label %[[FOR_BODY:.*]]
+; CHECK: [[FOR_BODY]]:
+; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[BC_RESUME_VAL]], %[[SCALAR_PH]] ], [ [[IV_NEXT:%.*]], %[[FOR_BODY]] ]
+; CHECK-NEXT: [[GEP_A0:%.*]] = getelementptr inbounds [[TRIPLE_I32]], ptr [[A]], i64 [[IV]], i32 0
+; CHECK-NEXT: store i32 0, ptr [[GEP_A0]], align 4
+; CHECK-NEXT: [[GEP_A1:%.*]] = getelementptr inbounds [[TRIPLE_I32]], ptr [[A]], i64 [[IV]], i32 1
+; CHECK-NEXT: store i32 1, ptr [[GEP_A1]], align 4
+; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
+; CHECK-NEXT: [[EC:%.*]] = icmp eq i64 [[IV_NEXT]], [[N]]
+; CHECK-NEXT: br i1 [[EC]], label %[[EXIT]], label %[[FOR_BODY]], !llvm.loop [[LOOP3:![0-9]+]]
+; CHECK: [[EXIT]]:
+; CHECK-NEXT: ret void
+;
+entry:
+ br label %for.body
+
+for.body:
+ %iv = phi i64 [ 0, %entry ], [ %iv.next, %for.body ]
+ %gep.a0 = getelementptr inbounds %triple.i32, ptr %a, i64 %iv, i32 0
+ store i32 0, ptr %gep.a0, align 4
+ %gep.a1 = getelementptr inbounds %triple.i32, ptr %a, i64 %iv, i32 1
+ store i32 1, ptr %gep.a1, align 4
+ %iv.next = add nuw nsw i64 %iv, 1
+ %ec = icmp eq i64 %iv.next, %n
+ br i1 %ec, label %exit, label %for.body
+
+exit:
+ ret void
+}
+
+define void @concat_pad_poison_loaded_value(ptr noalias %a, ptr noalias %b, i64 %n) {
+; CHECK-LABEL: define void @concat_pad_poison_loaded_value(
+; CHECK-SAME: ptr noalias [[A:%.*]], ptr noalias [[B:%.*]], i64 [[N:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: [[MIN_ITERS_CHECK:%.*]] = icmp ult i64 [[N]], 8
+; CHECK-NEXT: br i1 [[MIN_ITERS_CHECK]], label %[[SCALAR_PH:.*]], label %[[VECTOR_PH:.*]]
+; CHECK: [[VECTOR_PH]]:
+; CHECK-NEXT: [[TMP0:%.*]] = and i64 [[N]], 7
+; CHECK-NEXT: [[N_VEC:%.*]] = sub i64 [[N]], [[TMP0]]
+; CHECK-NEXT: br label %[[VECTOR_BODY:.*]]
+; CHECK: [[VECTOR_BODY]]:
+; CHECK-NEXT: [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[VECTOR_BODY]] ]
+; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[B]], i64 [[INDEX]]
+; CHECK-NEXT: [[WIDE_LOAD:%.*]] = load <8 x i32>, ptr [[TMP1]], align 4
+; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds [[TRIPLE_I32:%.*]], ptr [[A]], i64 [[INDEX]], i32 0
+; CHECK-NEXT: [[TMP3:%.*]] = shufflevector <8 x i32> [[WIDE_LOAD]], <8 x i32> [[WIDE_LOAD]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
+; CHECK-NEXT: [[TMP4:%.*]] = shufflevector <16 x i32> [[TMP3]], <16 x i32> <i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>, <24 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15, i32 16, i32 17, i32 18, i32 19, i32 20, i32 21, i32 22, i32 23>
+; CHECK-NEXT: [[INTERLEAVED_VEC:%.*]] = shufflevector <24 x i32> [[TMP4]], <24 x i32> poison, <24 x i32> <i32 0, i32 8, i32 16, i32 1, i32 9, i32 17, i32 2, i32 10, i32 18, i32 3, i32 11, i32 19, i32 4, i32 12, i32 20, i32 5, i32 13, i32 21, i32 6, i32 14, i32 22, i32 7, i32 15, i32 23>
+; CHECK-NEXT: call void @llvm.masked.store.v24i32.p0(<24 x i32> [[INTERLEAVED_VEC]], ptr align 4 [[TMP2]], <24 x i1> <i1 true, i1 true, i1 false, i1 true, i1 true, i1 false, i1 true, i1 true, i1 false, i1 true, i1 true, i1 false, i1 true, i1 true, i1 false, i1 true, i1 true, i1 false, i1 true, i1 true, i1 false, i1 true, i1 true, i1 false>)
+; CHECK-NEXT: [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 8
+; CHECK-NEXT: [[TMP5:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]]
+; CHECK-NEXT: br i1 [[TMP5]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP4:![0-9]+]]
+; CHECK: [[MIDDLE_BLOCK]]:
+; CHECK-NEXT: [[CMP_N:%.*]] = icmp eq i64 [[N]], [[N_VEC]]
+; CHECK-NEXT: br i1 [[CMP_N]], label %[[EXIT:.*]], label %[[SCALAR_PH]]
+; CHECK: [[SCALAR_PH]]:
+; CHECK-NEXT: [[BC_RESUME_VAL:%.*]] = phi i64 [ [[N_VEC]], %[[MIDDLE_BLOCK]] ], [ 0, %[[ENTRY]] ]
+; CHECK-NEXT: br label %[[FOR_BODY:.*]]
+; CHECK: [[FOR_BODY]]:
+; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[BC_RESUME_VAL]], %[[SCALAR_PH]] ], [ [[IV_NEXT:%.*]], %[[FOR_BODY]] ]
+; CHECK-NEXT: [[GEP_B:%.*]] = getelementptr inbounds i32, ptr [[B]], i64 [[IV]]
+; CHECK-NEXT: [[L:%.*]] = load i32, ptr [[GEP_B]], align 4
+; CHECK-NEXT: [[GEP_A0:%.*]] = getelementptr inbounds [[TRIPLE_I32]], ptr [[A]], i64 [[IV]], i32 0
+; CHECK-NEXT: store i32 [[L]], ptr [[GEP_A0]], align 4
+; CHECK-NEXT: [[GEP_A1:%.*]] = getelementptr inbounds [[TRIPLE_I32]], ptr [[A]], i64 [[IV]], i32 1
+; CHECK-NEXT: store i32 [[L]], ptr [[GEP_A1]], align 4
+; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
+; CHECK-NEXT: [[EC:%.*]] = icmp eq i64 [[IV_NEXT]], [[N]]
+; CHECK-NEXT: br i1 [[EC]], label %[[EXIT]], label %[[FOR_BODY]], !llvm.loop [[LOOP5:![0-9]+]]
+; CHECK: [[EXIT]]:
+; CHECK-NEXT: ret void
+;
+entry:
+ br label %for.body
+
+for.body:
+ %iv = phi i64 [ 0, %entry ], [ %iv.next, %for.body ]
+ %gep.b = getelementptr inbounds i32, ptr %b, i64 %iv
+ %l = load i32, ptr %gep.b, align 4
+ %gep.a0 = getelementptr inbounds %triple.i32, ptr %a, i64 %iv, i32 0
+ store i32 %l, ptr %gep.a0, align 4
+ %gep.a1 = getelementptr inbounds %triple.i32, ptr %a, i64 %iv, i32 1
+ store i32 %l, ptr %gep.a1, align 4
+ %iv.next = add nuw nsw i64 %iv, 1
+ %ec = icmp eq i64 %iv.next, %n
+ br i1 %ec, label %exit, label %for.body
+
+exit:
+ ret void
+}
+;.
+; CHECK: [[LOOP0]] = distinct !{[[LOOP0]], [[META1:![0-9]+]], [[META2:![0-9]+]]}
+; CHECK: [[META1]] = !{!"llvm.loop.isvectorized", i32 1}
+; CHECK: [[META2]] = !{!"llvm.loop.unroll.runtime.disable"}
+; CHECK: [[LOOP3]] = distinct !{[[LOOP3]], [[META2]], [[META1]]}
+; CHECK: [[LOOP4]] = distinct !{[[LOOP4]], [[META1]], [[META2]]}
+; CHECK: [[LOOP5]] = distinct !{[[LOOP5]], [[META2]], [[META1]]}
+;.
>From a109dd3ee1761e9931f4368a903f6ba3a23ed139 Mon Sep 17 00:00:00 2001
From: Le Gia Bao <legiabao7300 at gmail.com>
Date: Sun, 4 Oct 2026 20:19:39 +0700
Subject: [PATCH 2/2] [VectorUtils] Pad concatenateVectors with poison instead
of undef
undef is now deprecated, so pad with poison instead.
---
llvm/lib/Analysis/VectorUtils.cpp | 11 +++++++----
.../X86/interleaved-store-concat-poison-pad.ll | 2 +-
2 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/llvm/lib/Analysis/VectorUtils.cpp b/llvm/lib/Analysis/VectorUtils.cpp
index c1d6f725dbdef..42ce9417a8b54 100644
--- a/llvm/lib/Analysis/VectorUtils.cpp
+++ b/llvm/lib/Analysis/VectorUtils.cpp
@@ -1205,7 +1205,7 @@ llvm::SmallVector<int, 16> llvm::createUnaryMask(ArrayRef<int> Mask,
/// A helper function for concatenating vectors. This function concatenates two
/// vectors having the same element type. If the second vector has fewer
-/// elements than the first, it is padded with undefs.
+/// elements than the first, it is padded with poison.
static Value *concatenateTwoVectors(IRBuilderBase &Builder, Value *V1,
Value *V2) {
VectorType *VecTy1 = dyn_cast<VectorType>(V1->getType());
@@ -1219,9 +1219,12 @@ static Value *concatenateTwoVectors(IRBuilderBase &Builder, Value *V1,
assert(NumElts1 >= NumElts2 && "Unexpect the first vector has less elements");
if (NumElts1 > NumElts2) {
- // Extend with UNDEFs.
- V2 = Builder.CreateShuffleVector(
- V2, createSequentialMask(0, NumElts2, NumElts1 - NumElts2));
+ // Extend with poison.
+ if (isa<PoisonValue>(V2))
+ V2 = PoisonValue::get(VecTy1);
+ else
+ V2 = Builder.CreateShuffleVector(
+ V2, createSequentialMask(0, NumElts2, NumElts1 - NumElts2));
}
return Builder.CreateShuffleVector(
diff --git a/llvm/test/Transforms/LoopVectorize/X86/interleaved-store-concat-poison-pad.ll b/llvm/test/Transforms/LoopVectorize/X86/interleaved-store-concat-poison-pad.ll
index 60ecbed24176b..c06f154d8cc52 100644
--- a/llvm/test/Transforms/LoopVectorize/X86/interleaved-store-concat-poison-pad.ll
+++ b/llvm/test/Transforms/LoopVectorize/X86/interleaved-store-concat-poison-pad.ll
@@ -73,7 +73,7 @@ define void @concat_pad_poison_loaded_value(ptr noalias %a, ptr noalias %b, i64
; CHECK-NEXT: [[WIDE_LOAD:%.*]] = load <8 x i32>, ptr [[TMP1]], align 4
; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds [[TRIPLE_I32:%.*]], ptr [[A]], i64 [[INDEX]], i32 0
; CHECK-NEXT: [[TMP3:%.*]] = shufflevector <8 x i32> [[WIDE_LOAD]], <8 x i32> [[WIDE_LOAD]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
-; CHECK-NEXT: [[TMP4:%.*]] = shufflevector <16 x i32> [[TMP3]], <16 x i32> <i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>, <24 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15, i32 16, i32 17, i32 18, i32 19, i32 20, i32 21, i32 22, i32 23>
+; CHECK-NEXT: [[TMP4:%.*]] = shufflevector <16 x i32> [[TMP3]], <16 x i32> poison, <24 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15, i32 16, i32 17, i32 18, i32 19, i32 20, i32 21, i32 22, i32 23>
; CHECK-NEXT: [[INTERLEAVED_VEC:%.*]] = shufflevector <24 x i32> [[TMP4]], <24 x i32> poison, <24 x i32> <i32 0, i32 8, i32 16, i32 1, i32 9, i32 17, i32 2, i32 10, i32 18, i32 3, i32 11, i32 19, i32 4, i32 12, i32 20, i32 5, i32 13, i32 21, i32 6, i32 14, i32 22, i32 7, i32 15, i32 23>
; CHECK-NEXT: call void @llvm.masked.store.v24i32.p0(<24 x i32> [[INTERLEAVED_VEC]], ptr align 4 [[TMP2]], <24 x i1> <i1 true, i1 true, i1 false, i1 true, i1 true, i1 false, i1 true, i1 true, i1 false, i1 true, i1 true, i1 false, i1 true, i1 true, i1 false, i1 true, i1 true, i1 false, i1 true, i1 true, i1 false, i1 true, i1 true, i1 false>)
; CHECK-NEXT: [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 8
More information about the llvm-commits
mailing list