[llvm] [InstCombine] Bubble splices of binop operands to their result (PR #179432)
Luke Lau via llvm-commits
llvm-commits at lists.llvm.org
Tue Feb 3 07:28:20 PST 2026
https://github.com/lukel97 updated https://github.com/llvm/llvm-project/pull/179432
>From 2271280cd7d9f6c3c111d98c281fe719d3f01c61 Mon Sep 17 00:00:00 2001
From: Luke Lau <luke at igalia.com>
Date: Tue, 3 Feb 2026 18:16:58 +0800
Subject: [PATCH 1/6] Precommit tests
---
.../Transforms/InstCombine/vector-reverse.ll | 89 +++++++++++++++++++
1 file changed, 89 insertions(+)
diff --git a/llvm/test/Transforms/InstCombine/vector-reverse.ll b/llvm/test/Transforms/InstCombine/vector-reverse.ll
index ee60d31d1ddbe..33802be40d5d9 100644
--- a/llvm/test/Transforms/InstCombine/vector-reverse.ll
+++ b/llvm/test/Transforms/InstCombine/vector-reverse.ll
@@ -843,6 +843,95 @@ define <vscale x 4 x float> @reverse_unop_intrinsic_reverse_scalar_arg(<vscale x
ret <vscale x 4 x float> %powi.rev
}
+define <vscale x 4 x i32> @binop_reverse_splice(<vscale x 4 x i32> %a, <vscale x 4 x i32> %b, i32 %offset) {
+; CHECK-LABEL: @binop_reverse_splice(
+; CHECK-NEXT: [[A_REV:%.*]] = tail call <vscale x 4 x i32> @llvm.vector.reverse.nxv4i32(<vscale x 4 x i32> [[A1:%.*]])
+; CHECK-NEXT: [[A:%.*]] = tail call <vscale x 4 x i32> @llvm.vector.splice.right.nxv4i32(<vscale x 4 x i32> [[A_REV]], <vscale x 4 x i32> poison, i32 [[OFFSET:%.*]])
+; CHECK-NEXT: [[B_REV:%.*]] = tail call <vscale x 4 x i32> @llvm.vector.reverse.nxv4i32(<vscale x 4 x i32> [[B1:%.*]])
+; CHECK-NEXT: [[B:%.*]] = tail call <vscale x 4 x i32> @llvm.vector.splice.right.nxv4i32(<vscale x 4 x i32> [[B_REV]], <vscale x 4 x i32> poison, i32 [[OFFSET]])
+; CHECK-NEXT: [[ADD1:%.*]] = add <vscale x 4 x i32> [[A]], [[B]]
+; CHECK-NEXT: ret <vscale x 4 x i32> [[ADD1]]
+;
+ %a.rev = tail call <vscale x 4 x i32> @llvm.vector.reverse(<vscale x 4 x i32> %a)
+ %a.splice = tail call <vscale x 4 x i32> @llvm.vector.splice.right(<vscale x 4 x i32> %a.rev, <vscale x 4 x i32> poison, i32 %offset)
+ %b.rev = tail call <vscale x 4 x i32> @llvm.vector.reverse(<vscale x 4 x i32> %b)
+ %b.splice = tail call <vscale x 4 x i32> @llvm.vector.splice.right(<vscale x 4 x i32> %b.rev, <vscale x 4 x i32> poison, i32 %offset)
+ %add = add <vscale x 4 x i32> %a.splice, %b.splice
+ ret <vscale x 4 x i32> %add
+}
+
+; Negative test - splices have different offsets
+define <vscale x 4 x i32> @binop_reverse_splice_mismatched_offset(<vscale x 4 x i32> %a, <vscale x 4 x i32> %b, i32 %offset1, i32 %offset2) {
+; CHECK-LABEL: @binop_reverse_splice_mismatched_offset(
+; CHECK-NEXT: [[A_REV:%.*]] = tail call <vscale x 4 x i32> @llvm.vector.reverse.nxv4i32(<vscale x 4 x i32> [[A:%.*]])
+; CHECK-NEXT: [[A_SPLICE:%.*]] = tail call <vscale x 4 x i32> @llvm.vector.splice.right.nxv4i32(<vscale x 4 x i32> [[A_REV]], <vscale x 4 x i32> poison, i32 [[OFFSET1:%.*]])
+; CHECK-NEXT: [[B_REV:%.*]] = tail call <vscale x 4 x i32> @llvm.vector.reverse.nxv4i32(<vscale x 4 x i32> [[B:%.*]])
+; CHECK-NEXT: [[B_SPLICE:%.*]] = tail call <vscale x 4 x i32> @llvm.vector.splice.right.nxv4i32(<vscale x 4 x i32> [[B_REV]], <vscale x 4 x i32> poison, i32 [[OFFSET2:%.*]])
+; CHECK-NEXT: [[ADD:%.*]] = add <vscale x 4 x i32> [[A_SPLICE]], [[B_SPLICE]]
+; CHECK-NEXT: ret <vscale x 4 x i32> [[ADD]]
+;
+ %a.rev = tail call <vscale x 4 x i32> @llvm.vector.reverse(<vscale x 4 x i32> %a)
+ %a.splice = tail call <vscale x 4 x i32> @llvm.vector.splice.right(<vscale x 4 x i32> %a.rev, <vscale x 4 x i32> poison, i32 %offset1)
+ %b.rev = tail call <vscale x 4 x i32> @llvm.vector.reverse(<vscale x 4 x i32> %b)
+ %b.splice = tail call <vscale x 4 x i32> @llvm.vector.splice.right(<vscale x 4 x i32> %b.rev, <vscale x 4 x i32> poison, i32 %offset2)
+ %add = add <vscale x 4 x i32> %a.splice, %b.splice
+ ret <vscale x 4 x i32> %add
+}
+
+; Negative test - %a.rev has multiple uses
+define <vscale x 4 x i32> @binop_reverse_splice_multiuse(<vscale x 4 x i32> %a, <vscale x 4 x i32> %b, i32 %offset) {
+; CHECK-LABEL: @binop_reverse_splice_multiuse(
+; CHECK-NEXT: [[A_REV:%.*]] = tail call <vscale x 4 x i32> @llvm.vector.reverse.nxv4i32(<vscale x 4 x i32> [[A:%.*]])
+; CHECK-NEXT: [[A_SPLICE:%.*]] = tail call <vscale x 4 x i32> @llvm.vector.splice.right.nxv4i32(<vscale x 4 x i32> [[A_REV]], <vscale x 4 x i32> poison, i32 [[OFFSET:%.*]])
+; CHECK-NEXT: [[B_REV:%.*]] = tail call <vscale x 4 x i32> @llvm.vector.reverse.nxv4i32(<vscale x 4 x i32> [[B:%.*]])
+; CHECK-NEXT: [[B_SPLICE:%.*]] = tail call <vscale x 4 x i32> @llvm.vector.splice.right.nxv4i32(<vscale x 4 x i32> [[B_REV]], <vscale x 4 x i32> poison, i32 [[OFFSET]])
+; CHECK-NEXT: [[ADD:%.*]] = add <vscale x 4 x i32> [[A_SPLICE]], [[B_SPLICE]]
+; CHECK-NEXT: [[ADD2:%.*]] = add <vscale x 4 x i32> [[ADD]], [[A_REV]]
+; CHECK-NEXT: ret <vscale x 4 x i32> [[ADD2]]
+;
+ %a.rev = tail call <vscale x 4 x i32> @llvm.vector.reverse(<vscale x 4 x i32> %a)
+ %a.splice = tail call <vscale x 4 x i32> @llvm.vector.splice.right(<vscale x 4 x i32> %a.rev, <vscale x 4 x i32> poison, i32 %offset)
+ %b.rev = tail call <vscale x 4 x i32> @llvm.vector.reverse(<vscale x 4 x i32> %b)
+ %b.splice = tail call <vscale x 4 x i32> @llvm.vector.splice.right(<vscale x 4 x i32> %b.rev, <vscale x 4 x i32> poison, i32 %offset)
+ %add = add <vscale x 4 x i32> %a.splice, %b.splice
+ %add2 = add <vscale x 4 x i32> %add, %a.rev
+ ret <vscale x 4 x i32> %add2
+}
+
+define <vscale x 4 x i32> @binop_reverse_splice_rhs_splat(<vscale x 4 x i32> %a, i32 %b, i32 %offset) {
+; CHECK-LABEL: @binop_reverse_splice_rhs_splat(
+; CHECK-NEXT: [[A_REV:%.*]] = tail call <vscale x 4 x i32> @llvm.vector.reverse.nxv4i32(<vscale x 4 x i32> [[A1:%.*]])
+; CHECK-NEXT: [[A:%.*]] = tail call <vscale x 4 x i32> @llvm.vector.splice.right.nxv4i32(<vscale x 4 x i32> [[A_REV]], <vscale x 4 x i32> poison, i32 [[OFFSET:%.*]])
+; CHECK-NEXT: [[B_INSERT:%.*]] = insertelement <vscale x 4 x i32> poison, i32 [[B:%.*]], i64 0
+; CHECK-NEXT: [[B_SPLAT:%.*]] = shufflevector <vscale x 4 x i32> [[B_INSERT]], <vscale x 4 x i32> poison, <vscale x 4 x i32> zeroinitializer
+; CHECK-NEXT: [[ADD1:%.*]] = add <vscale x 4 x i32> [[A]], [[B_SPLAT]]
+; CHECK-NEXT: ret <vscale x 4 x i32> [[ADD1]]
+;
+ %a.rev = tail call <vscale x 4 x i32> @llvm.vector.reverse(<vscale x 4 x i32> %a)
+ %a.splice = tail call <vscale x 4 x i32> @llvm.vector.splice.right(<vscale x 4 x i32> %a.rev, <vscale x 4 x i32> poison, i32 %offset)
+ %b.insert = insertelement <vscale x 4 x i32> poison, i32 %b, i32 0
+ %b.splat = shufflevector <vscale x 4 x i32> %b.insert, <vscale x 4 x i32> poison, <vscale x 4 x i32> zeroinitializer
+ %add = add <vscale x 4 x i32> %a.splice, %b.splat
+ ret <vscale x 4 x i32> %add
+}
+
+define <vscale x 4 x i32> @binop_reverse_splice_lhs_splat(<vscale x 4 x i32> %a, i32 %b, i32 %offset) {
+; CHECK-LABEL: @binop_reverse_splice_lhs_splat(
+; CHECK-NEXT: [[A_REV:%.*]] = tail call <vscale x 4 x i32> @llvm.vector.reverse.nxv4i32(<vscale x 4 x i32> [[A1:%.*]])
+; CHECK-NEXT: [[A:%.*]] = tail call <vscale x 4 x i32> @llvm.vector.splice.right.nxv4i32(<vscale x 4 x i32> [[A_REV]], <vscale x 4 x i32> poison, i32 [[OFFSET:%.*]])
+; CHECK-NEXT: [[B_INSERT:%.*]] = insertelement <vscale x 4 x i32> poison, i32 [[B:%.*]], i64 0
+; CHECK-NEXT: [[B_SPLAT:%.*]] = shufflevector <vscale x 4 x i32> [[B_INSERT]], <vscale x 4 x i32> poison, <vscale x 4 x i32> zeroinitializer
+; CHECK-NEXT: [[ADD1:%.*]] = add <vscale x 4 x i32> [[B_SPLAT]], [[A]]
+; CHECK-NEXT: ret <vscale x 4 x i32> [[ADD1]]
+;
+ %a.rev = tail call <vscale x 4 x i32> @llvm.vector.reverse(<vscale x 4 x i32> %a)
+ %a.splice = tail call <vscale x 4 x i32> @llvm.vector.splice.right(<vscale x 4 x i32> %a.rev, <vscale x 4 x i32> poison, i32 %offset)
+ %b.insert = insertelement <vscale x 4 x i32> poison, i32 %b, i32 0
+ %b.splat = shufflevector <vscale x 4 x i32> %b.insert, <vscale x 4 x i32> poison, <vscale x 4 x i32> zeroinitializer
+ %add = add <vscale x 4 x i32> %b.splat, %a.splice
+ ret <vscale x 4 x i32> %add
+}
+
declare void @use_nxv4i1(<vscale x 4 x i1>)
declare void @use_nxv4i32(<vscale x 4 x i32>)
declare void @use_nxv4f32(<vscale x 4 x float>)
>From bfd6f9630d307ebdcc49575f6ed2098dd8e1a0f0 Mon Sep 17 00:00:00 2001
From: Luke Lau <luke at igalia.com>
Date: Tue, 3 Feb 2026 18:18:20 +0800
Subject: [PATCH 2/6] [InstCombine] Bubble left spliced reverses of binop
operands to their result
In #172961 we are trying to remove llvm.experimental.vp.reverse now that llvm.vector.splice.right supports variable offsets.
A VP reverse reverses the first EVL elements of the vector, e.g. 01234567 -> 210xxxxx when EVL=3, where x=poison.
This can now be represented by splice.right(reverse(V), poison, EVL):
01234567
-> 76543210 (reverse)
-> 210xxxxx (splice.right)
This PR implements the vp.reverse combines that pull through binops, but on vector.splice.right. We can then remove the vp.reverse intrinsic and its related combines soon after, once we migrate the loop vectorizer over.
---
.../InstCombine/InstructionCombining.cpp | 34 +++++++++++++++++++
.../Transforms/InstCombine/vector-reverse.ll | 26 +++++++-------
2 files changed, 46 insertions(+), 14 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
index a9904f7867e94..39ca23796cfe6 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -2487,6 +2487,40 @@ Instruction *InstCombinerImpl::foldVectorBinop(BinaryOperator &Inst) {
else if (isSplatValue(LHS) && match(RHS, m_OneUse(m_VecReverse(m_Value(V2)))))
return createBinOpReverse(LHS, V2);
+ auto createBinOpSpliceReverse = [&](Value *X, Value *Y, Value *Offset) {
+ Value *V = Builder.CreateBinOp(Opcode, X, Y, Inst.getName());
+ if (auto *BO = dyn_cast<BinaryOperator>(V))
+ BO->copyIRFlags(&Inst);
+ Module *M = Inst.getModule();
+ Function *F = Intrinsic::getOrInsertDeclaration(
+ M, Intrinsic::vector_splice_right, V->getType());
+ return CallInst::Create(F, {Builder.CreateVectorReverse(V),
+ PoisonValue::get(X->getType()), Offset});
+ };
+ auto m_SpliceReverse = [](auto V, auto Offset) {
+ return m_Intrinsic<Intrinsic::vector_splice_right>(m_OneUse(m_VecReverse(V)),
+ m_Poison(), Offset);
+ };
+ Value *Offset;
+ if (match(LHS, m_SpliceReverse(m_Value(V1), m_Value(Offset)))) {
+ // Op(splice.right(rev(V1),poison,offset),splice.right(rev(V2),poison,offset))
+ // -> splice.right(rev(Op(V1, V2)), poison, offset)
+ if (match(RHS, m_SpliceReverse(m_Value(V2), m_Specific(Offset))) &&
+ (LHS->hasOneUse() || RHS->hasOneUse() ||
+ (LHS == RHS && LHS->hasNUses(2))))
+ return createBinOpSpliceReverse(V1, V2, Offset);
+
+ // Op(splice.right(rev(V1) poison, offset), RHSSplat))
+ // -> splice.right(rev(Op(V1, RHSSplat)), poison, offset)
+ if (LHS->hasOneUse() && isSplatValue(RHS))
+ return createBinOpSpliceReverse(V1, RHS, Offset);
+ }
+ // Op(LHSSplat, splice.right(rev(V2), poison, offset))
+ // -> splice.right(rev(Op(LHSSplat, V2)), poison, offset)
+ else if (isSplatValue(LHS) &&
+ match(RHS, m_OneUse(m_SpliceReverse(m_Value(V2), m_Value(Offset)))))
+ return createBinOpSpliceReverse(LHS, V2, Offset);
+
auto createBinOpVPReverse = [&](Value *X, Value *Y, Value *EVL) {
Value *V = Builder.CreateBinOp(Opcode, X, Y, Inst.getName());
if (auto *BO = dyn_cast<BinaryOperator>(V))
diff --git a/llvm/test/Transforms/InstCombine/vector-reverse.ll b/llvm/test/Transforms/InstCombine/vector-reverse.ll
index 33802be40d5d9..ba35e7a2437f1 100644
--- a/llvm/test/Transforms/InstCombine/vector-reverse.ll
+++ b/llvm/test/Transforms/InstCombine/vector-reverse.ll
@@ -845,12 +845,10 @@ define <vscale x 4 x float> @reverse_unop_intrinsic_reverse_scalar_arg(<vscale x
define <vscale x 4 x i32> @binop_reverse_splice(<vscale x 4 x i32> %a, <vscale x 4 x i32> %b, i32 %offset) {
; CHECK-LABEL: @binop_reverse_splice(
-; CHECK-NEXT: [[A_REV:%.*]] = tail call <vscale x 4 x i32> @llvm.vector.reverse.nxv4i32(<vscale x 4 x i32> [[A1:%.*]])
-; CHECK-NEXT: [[A:%.*]] = tail call <vscale x 4 x i32> @llvm.vector.splice.right.nxv4i32(<vscale x 4 x i32> [[A_REV]], <vscale x 4 x i32> poison, i32 [[OFFSET:%.*]])
-; CHECK-NEXT: [[B_REV:%.*]] = tail call <vscale x 4 x i32> @llvm.vector.reverse.nxv4i32(<vscale x 4 x i32> [[B1:%.*]])
-; CHECK-NEXT: [[B:%.*]] = tail call <vscale x 4 x i32> @llvm.vector.splice.right.nxv4i32(<vscale x 4 x i32> [[B_REV]], <vscale x 4 x i32> poison, i32 [[OFFSET]])
-; CHECK-NEXT: [[ADD1:%.*]] = add <vscale x 4 x i32> [[A]], [[B]]
-; CHECK-NEXT: ret <vscale x 4 x i32> [[ADD1]]
+; CHECK-NEXT: [[ADD1:%.*]] = add <vscale x 4 x i32> [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT: [[TMP1:%.*]] = call <vscale x 4 x i32> @llvm.vector.reverse.nxv4i32(<vscale x 4 x i32> [[ADD1]])
+; CHECK-NEXT: [[ADD:%.*]] = call <vscale x 4 x i32> @llvm.vector.splice.right.nxv4i32(<vscale x 4 x i32> [[TMP1]], <vscale x 4 x i32> poison, i32 [[OFFSET:%.*]])
+; CHECK-NEXT: ret <vscale x 4 x i32> [[ADD]]
;
%a.rev = tail call <vscale x 4 x i32> @llvm.vector.reverse(<vscale x 4 x i32> %a)
%a.splice = tail call <vscale x 4 x i32> @llvm.vector.splice.right(<vscale x 4 x i32> %a.rev, <vscale x 4 x i32> poison, i32 %offset)
@@ -900,12 +898,12 @@ define <vscale x 4 x i32> @binop_reverse_splice_multiuse(<vscale x 4 x i32> %a,
define <vscale x 4 x i32> @binop_reverse_splice_rhs_splat(<vscale x 4 x i32> %a, i32 %b, i32 %offset) {
; CHECK-LABEL: @binop_reverse_splice_rhs_splat(
-; CHECK-NEXT: [[A_REV:%.*]] = tail call <vscale x 4 x i32> @llvm.vector.reverse.nxv4i32(<vscale x 4 x i32> [[A1:%.*]])
-; CHECK-NEXT: [[A:%.*]] = tail call <vscale x 4 x i32> @llvm.vector.splice.right.nxv4i32(<vscale x 4 x i32> [[A_REV]], <vscale x 4 x i32> poison, i32 [[OFFSET:%.*]])
; CHECK-NEXT: [[B_INSERT:%.*]] = insertelement <vscale x 4 x i32> poison, i32 [[B:%.*]], i64 0
; CHECK-NEXT: [[B_SPLAT:%.*]] = shufflevector <vscale x 4 x i32> [[B_INSERT]], <vscale x 4 x i32> poison, <vscale x 4 x i32> zeroinitializer
-; CHECK-NEXT: [[ADD1:%.*]] = add <vscale x 4 x i32> [[A]], [[B_SPLAT]]
-; CHECK-NEXT: ret <vscale x 4 x i32> [[ADD1]]
+; CHECK-NEXT: [[ADD1:%.*]] = add <vscale x 4 x i32> [[A:%.*]], [[B_SPLAT]]
+; CHECK-NEXT: [[TMP1:%.*]] = call <vscale x 4 x i32> @llvm.vector.reverse.nxv4i32(<vscale x 4 x i32> [[ADD1]])
+; CHECK-NEXT: [[ADD:%.*]] = call <vscale x 4 x i32> @llvm.vector.splice.right.nxv4i32(<vscale x 4 x i32> [[TMP1]], <vscale x 4 x i32> poison, i32 [[OFFSET:%.*]])
+; CHECK-NEXT: ret <vscale x 4 x i32> [[ADD]]
;
%a.rev = tail call <vscale x 4 x i32> @llvm.vector.reverse(<vscale x 4 x i32> %a)
%a.splice = tail call <vscale x 4 x i32> @llvm.vector.splice.right(<vscale x 4 x i32> %a.rev, <vscale x 4 x i32> poison, i32 %offset)
@@ -917,12 +915,12 @@ define <vscale x 4 x i32> @binop_reverse_splice_rhs_splat(<vscale x 4 x i32> %a,
define <vscale x 4 x i32> @binop_reverse_splice_lhs_splat(<vscale x 4 x i32> %a, i32 %b, i32 %offset) {
; CHECK-LABEL: @binop_reverse_splice_lhs_splat(
-; CHECK-NEXT: [[A_REV:%.*]] = tail call <vscale x 4 x i32> @llvm.vector.reverse.nxv4i32(<vscale x 4 x i32> [[A1:%.*]])
-; CHECK-NEXT: [[A:%.*]] = tail call <vscale x 4 x i32> @llvm.vector.splice.right.nxv4i32(<vscale x 4 x i32> [[A_REV]], <vscale x 4 x i32> poison, i32 [[OFFSET:%.*]])
; CHECK-NEXT: [[B_INSERT:%.*]] = insertelement <vscale x 4 x i32> poison, i32 [[B:%.*]], i64 0
; CHECK-NEXT: [[B_SPLAT:%.*]] = shufflevector <vscale x 4 x i32> [[B_INSERT]], <vscale x 4 x i32> poison, <vscale x 4 x i32> zeroinitializer
-; CHECK-NEXT: [[ADD1:%.*]] = add <vscale x 4 x i32> [[B_SPLAT]], [[A]]
-; CHECK-NEXT: ret <vscale x 4 x i32> [[ADD1]]
+; CHECK-NEXT: [[ADD1:%.*]] = add <vscale x 4 x i32> [[B_SPLAT]], [[A:%.*]]
+; CHECK-NEXT: [[TMP1:%.*]] = call <vscale x 4 x i32> @llvm.vector.reverse.nxv4i32(<vscale x 4 x i32> [[ADD1]])
+; CHECK-NEXT: [[ADD:%.*]] = call <vscale x 4 x i32> @llvm.vector.splice.right.nxv4i32(<vscale x 4 x i32> [[TMP1]], <vscale x 4 x i32> poison, i32 [[OFFSET:%.*]])
+; CHECK-NEXT: ret <vscale x 4 x i32> [[ADD]]
;
%a.rev = tail call <vscale x 4 x i32> @llvm.vector.reverse(<vscale x 4 x i32> %a)
%a.splice = tail call <vscale x 4 x i32> @llvm.vector.splice.right(<vscale x 4 x i32> %a.rev, <vscale x 4 x i32> poison, i32 %offset)
>From 1a92074c5a37c360a7f407588885a24d8e74ad62 Mon Sep 17 00:00:00 2001
From: Luke Lau <luke at igalia.com>
Date: Tue, 3 Feb 2026 19:19:26 +0800
Subject: [PATCH 3/6] clang-format
---
llvm/lib/Transforms/InstCombine/InstructionCombining.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
index 39ca23796cfe6..053fb7f62d268 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -2498,8 +2498,8 @@ Instruction *InstCombinerImpl::foldVectorBinop(BinaryOperator &Inst) {
PoisonValue::get(X->getType()), Offset});
};
auto m_SpliceReverse = [](auto V, auto Offset) {
- return m_Intrinsic<Intrinsic::vector_splice_right>(m_OneUse(m_VecReverse(V)),
- m_Poison(), Offset);
+ return m_Intrinsic<Intrinsic::vector_splice_right>(
+ m_OneUse(m_VecReverse(V)), m_Poison(), Offset);
};
Value *Offset;
if (match(LHS, m_SpliceReverse(m_Value(V1), m_Value(Offset)))) {
>From dde227191c9895039b842fe026ab7bf859ca80d3 Mon Sep 17 00:00:00 2001
From: Luke Lau <luke at igalia.com>
Date: Tue, 3 Feb 2026 22:25:36 +0800
Subject: [PATCH 4/6] Generalize to left and right splices
---
.../InstCombine/InstructionCombining.cpp | 84 +++++++-----
.../Transforms/InstCombine/vector-reverse.ll | 87 -------------
.../Transforms/InstCombine/vector-splice.ll | 122 ++++++++++++++++++
3 files changed, 172 insertions(+), 121 deletions(-)
create mode 100644 llvm/test/Transforms/InstCombine/vector-splice.ll
diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
index 053fb7f62d268..82a26eda440dc 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -2392,6 +2392,49 @@ static Constant *constantFoldBinOpWithSplat(unsigned Opcode, Constant *Vector,
return ConstantFoldBinaryOpOperands(Opcode, LHS, RHS, DL);
}
+template <Intrinsic::ID SpliceID>
+static Instruction *foldSpliceBinOp(BinaryOperator &Inst,
+ InstCombiner::BuilderTy &Builder) {
+ Value *LHS = Inst.getOperand(0), *RHS = Inst.getOperand(1);
+ auto CreateBinOpSplice = [&](Value *X, Value *Y, Value *Z, Value *Offset) {
+ Value *V = Builder.CreateBinOp(Inst.getOpcode(), X, Y, Inst.getName());
+ if (auto *BO = dyn_cast<BinaryOperator>(V))
+ BO->copyIRFlags(&Inst);
+ Module *M = Inst.getModule();
+ Function *F = Intrinsic::getOrInsertDeclaration(
+ M, Intrinsic::vector_splice_right, V->getType());
+ return CallInst::Create(F, {V, Z, Offset});
+ };
+ Value *V1, *V2, *V3, *Offset;
+ if (match(LHS,
+ m_Intrinsic<SpliceID>(m_Value(V1), m_Value(V3), m_Value(Offset)))) {
+ // Op(splice(V1, V3, offset), splice(V2, V3, offset))
+ // -> splice(Op(V1, V2), V3, offset)
+ if (match(RHS, m_Intrinsic<SpliceID>(m_Value(V2), m_Specific(V3),
+ m_Specific(Offset))) &&
+ (LHS->hasOneUse() || RHS->hasOneUse() ||
+ (LHS == RHS && LHS->hasNUses(2))))
+ return CreateBinOpSplice(V1, V2, V3, Offset);
+
+ // Op(splice(V1, V3, offset), RHSSplat)
+ // -> splice(Op(V1, RHSSplat), V3, offset)
+ if (LHS->hasOneUse() && isSplatValue(RHS))
+ return CreateBinOpSplice(V1, RHS, V3, Offset);
+ }
+ // Op(LHSSplat, splice(V2, V3, offset))
+ // -> splice(Op(LHSSplat, V2), V3, offset)
+ else if (isSplatValue(LHS) &&
+ match(RHS, m_OneUse(m_Intrinsic<SpliceID>(m_Value(V2), m_Value(V3),
+ m_Value(Offset)))))
+ return CreateBinOpSplice(LHS, V2, V3, Offset);
+
+ // TODO: Fold binops of the form
+ // Op(splice(V3, V1, offset), splice(V3, V2, offset))
+ // -> splice(V3, Op(V1, V2), offset)
+
+ return nullptr;
+}
+
Instruction *InstCombinerImpl::foldVectorBinop(BinaryOperator &Inst) {
if (!isa<VectorType>(Inst.getType()))
return nullptr;
@@ -2487,40 +2530,6 @@ Instruction *InstCombinerImpl::foldVectorBinop(BinaryOperator &Inst) {
else if (isSplatValue(LHS) && match(RHS, m_OneUse(m_VecReverse(m_Value(V2)))))
return createBinOpReverse(LHS, V2);
- auto createBinOpSpliceReverse = [&](Value *X, Value *Y, Value *Offset) {
- Value *V = Builder.CreateBinOp(Opcode, X, Y, Inst.getName());
- if (auto *BO = dyn_cast<BinaryOperator>(V))
- BO->copyIRFlags(&Inst);
- Module *M = Inst.getModule();
- Function *F = Intrinsic::getOrInsertDeclaration(
- M, Intrinsic::vector_splice_right, V->getType());
- return CallInst::Create(F, {Builder.CreateVectorReverse(V),
- PoisonValue::get(X->getType()), Offset});
- };
- auto m_SpliceReverse = [](auto V, auto Offset) {
- return m_Intrinsic<Intrinsic::vector_splice_right>(
- m_OneUse(m_VecReverse(V)), m_Poison(), Offset);
- };
- Value *Offset;
- if (match(LHS, m_SpliceReverse(m_Value(V1), m_Value(Offset)))) {
- // Op(splice.right(rev(V1),poison,offset),splice.right(rev(V2),poison,offset))
- // -> splice.right(rev(Op(V1, V2)), poison, offset)
- if (match(RHS, m_SpliceReverse(m_Value(V2), m_Specific(Offset))) &&
- (LHS->hasOneUse() || RHS->hasOneUse() ||
- (LHS == RHS && LHS->hasNUses(2))))
- return createBinOpSpliceReverse(V1, V2, Offset);
-
- // Op(splice.right(rev(V1) poison, offset), RHSSplat))
- // -> splice.right(rev(Op(V1, RHSSplat)), poison, offset)
- if (LHS->hasOneUse() && isSplatValue(RHS))
- return createBinOpSpliceReverse(V1, RHS, Offset);
- }
- // Op(LHSSplat, splice.right(rev(V2), poison, offset))
- // -> splice.right(rev(Op(LHSSplat, V2)), poison, offset)
- else if (isSplatValue(LHS) &&
- match(RHS, m_OneUse(m_SpliceReverse(m_Value(V2), m_Value(Offset)))))
- return createBinOpSpliceReverse(LHS, V2, Offset);
-
auto createBinOpVPReverse = [&](Value *X, Value *Y, Value *EVL) {
Value *V = Builder.CreateBinOp(Opcode, X, Y, Inst.getName());
if (auto *BO = dyn_cast<BinaryOperator>(V))
@@ -2554,6 +2563,13 @@ Instruction *InstCombinerImpl::foldVectorBinop(BinaryOperator &Inst) {
m_Value(V2), m_AllOnes(), m_Value(EVL))))
return createBinOpVPReverse(LHS, V2, EVL);
+ if (Instruction *Folded =
+ foldSpliceBinOp<Intrinsic::vector_splice_left>(Inst, Builder))
+ return Folded;
+ if (Instruction *Folded =
+ foldSpliceBinOp<Intrinsic::vector_splice_right>(Inst, Builder))
+ return Folded;
+
// It may not be safe to reorder shuffles and things like div, urem, etc.
// because we may trap when executing those ops on unknown vector elements.
// See PR20059.
diff --git a/llvm/test/Transforms/InstCombine/vector-reverse.ll b/llvm/test/Transforms/InstCombine/vector-reverse.ll
index ba35e7a2437f1..ee60d31d1ddbe 100644
--- a/llvm/test/Transforms/InstCombine/vector-reverse.ll
+++ b/llvm/test/Transforms/InstCombine/vector-reverse.ll
@@ -843,93 +843,6 @@ define <vscale x 4 x float> @reverse_unop_intrinsic_reverse_scalar_arg(<vscale x
ret <vscale x 4 x float> %powi.rev
}
-define <vscale x 4 x i32> @binop_reverse_splice(<vscale x 4 x i32> %a, <vscale x 4 x i32> %b, i32 %offset) {
-; CHECK-LABEL: @binop_reverse_splice(
-; CHECK-NEXT: [[ADD1:%.*]] = add <vscale x 4 x i32> [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT: [[TMP1:%.*]] = call <vscale x 4 x i32> @llvm.vector.reverse.nxv4i32(<vscale x 4 x i32> [[ADD1]])
-; CHECK-NEXT: [[ADD:%.*]] = call <vscale x 4 x i32> @llvm.vector.splice.right.nxv4i32(<vscale x 4 x i32> [[TMP1]], <vscale x 4 x i32> poison, i32 [[OFFSET:%.*]])
-; CHECK-NEXT: ret <vscale x 4 x i32> [[ADD]]
-;
- %a.rev = tail call <vscale x 4 x i32> @llvm.vector.reverse(<vscale x 4 x i32> %a)
- %a.splice = tail call <vscale x 4 x i32> @llvm.vector.splice.right(<vscale x 4 x i32> %a.rev, <vscale x 4 x i32> poison, i32 %offset)
- %b.rev = tail call <vscale x 4 x i32> @llvm.vector.reverse(<vscale x 4 x i32> %b)
- %b.splice = tail call <vscale x 4 x i32> @llvm.vector.splice.right(<vscale x 4 x i32> %b.rev, <vscale x 4 x i32> poison, i32 %offset)
- %add = add <vscale x 4 x i32> %a.splice, %b.splice
- ret <vscale x 4 x i32> %add
-}
-
-; Negative test - splices have different offsets
-define <vscale x 4 x i32> @binop_reverse_splice_mismatched_offset(<vscale x 4 x i32> %a, <vscale x 4 x i32> %b, i32 %offset1, i32 %offset2) {
-; CHECK-LABEL: @binop_reverse_splice_mismatched_offset(
-; CHECK-NEXT: [[A_REV:%.*]] = tail call <vscale x 4 x i32> @llvm.vector.reverse.nxv4i32(<vscale x 4 x i32> [[A:%.*]])
-; CHECK-NEXT: [[A_SPLICE:%.*]] = tail call <vscale x 4 x i32> @llvm.vector.splice.right.nxv4i32(<vscale x 4 x i32> [[A_REV]], <vscale x 4 x i32> poison, i32 [[OFFSET1:%.*]])
-; CHECK-NEXT: [[B_REV:%.*]] = tail call <vscale x 4 x i32> @llvm.vector.reverse.nxv4i32(<vscale x 4 x i32> [[B:%.*]])
-; CHECK-NEXT: [[B_SPLICE:%.*]] = tail call <vscale x 4 x i32> @llvm.vector.splice.right.nxv4i32(<vscale x 4 x i32> [[B_REV]], <vscale x 4 x i32> poison, i32 [[OFFSET2:%.*]])
-; CHECK-NEXT: [[ADD:%.*]] = add <vscale x 4 x i32> [[A_SPLICE]], [[B_SPLICE]]
-; CHECK-NEXT: ret <vscale x 4 x i32> [[ADD]]
-;
- %a.rev = tail call <vscale x 4 x i32> @llvm.vector.reverse(<vscale x 4 x i32> %a)
- %a.splice = tail call <vscale x 4 x i32> @llvm.vector.splice.right(<vscale x 4 x i32> %a.rev, <vscale x 4 x i32> poison, i32 %offset1)
- %b.rev = tail call <vscale x 4 x i32> @llvm.vector.reverse(<vscale x 4 x i32> %b)
- %b.splice = tail call <vscale x 4 x i32> @llvm.vector.splice.right(<vscale x 4 x i32> %b.rev, <vscale x 4 x i32> poison, i32 %offset2)
- %add = add <vscale x 4 x i32> %a.splice, %b.splice
- ret <vscale x 4 x i32> %add
-}
-
-; Negative test - %a.rev has multiple uses
-define <vscale x 4 x i32> @binop_reverse_splice_multiuse(<vscale x 4 x i32> %a, <vscale x 4 x i32> %b, i32 %offset) {
-; CHECK-LABEL: @binop_reverse_splice_multiuse(
-; CHECK-NEXT: [[A_REV:%.*]] = tail call <vscale x 4 x i32> @llvm.vector.reverse.nxv4i32(<vscale x 4 x i32> [[A:%.*]])
-; CHECK-NEXT: [[A_SPLICE:%.*]] = tail call <vscale x 4 x i32> @llvm.vector.splice.right.nxv4i32(<vscale x 4 x i32> [[A_REV]], <vscale x 4 x i32> poison, i32 [[OFFSET:%.*]])
-; CHECK-NEXT: [[B_REV:%.*]] = tail call <vscale x 4 x i32> @llvm.vector.reverse.nxv4i32(<vscale x 4 x i32> [[B:%.*]])
-; CHECK-NEXT: [[B_SPLICE:%.*]] = tail call <vscale x 4 x i32> @llvm.vector.splice.right.nxv4i32(<vscale x 4 x i32> [[B_REV]], <vscale x 4 x i32> poison, i32 [[OFFSET]])
-; CHECK-NEXT: [[ADD:%.*]] = add <vscale x 4 x i32> [[A_SPLICE]], [[B_SPLICE]]
-; CHECK-NEXT: [[ADD2:%.*]] = add <vscale x 4 x i32> [[ADD]], [[A_REV]]
-; CHECK-NEXT: ret <vscale x 4 x i32> [[ADD2]]
-;
- %a.rev = tail call <vscale x 4 x i32> @llvm.vector.reverse(<vscale x 4 x i32> %a)
- %a.splice = tail call <vscale x 4 x i32> @llvm.vector.splice.right(<vscale x 4 x i32> %a.rev, <vscale x 4 x i32> poison, i32 %offset)
- %b.rev = tail call <vscale x 4 x i32> @llvm.vector.reverse(<vscale x 4 x i32> %b)
- %b.splice = tail call <vscale x 4 x i32> @llvm.vector.splice.right(<vscale x 4 x i32> %b.rev, <vscale x 4 x i32> poison, i32 %offset)
- %add = add <vscale x 4 x i32> %a.splice, %b.splice
- %add2 = add <vscale x 4 x i32> %add, %a.rev
- ret <vscale x 4 x i32> %add2
-}
-
-define <vscale x 4 x i32> @binop_reverse_splice_rhs_splat(<vscale x 4 x i32> %a, i32 %b, i32 %offset) {
-; CHECK-LABEL: @binop_reverse_splice_rhs_splat(
-; CHECK-NEXT: [[B_INSERT:%.*]] = insertelement <vscale x 4 x i32> poison, i32 [[B:%.*]], i64 0
-; CHECK-NEXT: [[B_SPLAT:%.*]] = shufflevector <vscale x 4 x i32> [[B_INSERT]], <vscale x 4 x i32> poison, <vscale x 4 x i32> zeroinitializer
-; CHECK-NEXT: [[ADD1:%.*]] = add <vscale x 4 x i32> [[A:%.*]], [[B_SPLAT]]
-; CHECK-NEXT: [[TMP1:%.*]] = call <vscale x 4 x i32> @llvm.vector.reverse.nxv4i32(<vscale x 4 x i32> [[ADD1]])
-; CHECK-NEXT: [[ADD:%.*]] = call <vscale x 4 x i32> @llvm.vector.splice.right.nxv4i32(<vscale x 4 x i32> [[TMP1]], <vscale x 4 x i32> poison, i32 [[OFFSET:%.*]])
-; CHECK-NEXT: ret <vscale x 4 x i32> [[ADD]]
-;
- %a.rev = tail call <vscale x 4 x i32> @llvm.vector.reverse(<vscale x 4 x i32> %a)
- %a.splice = tail call <vscale x 4 x i32> @llvm.vector.splice.right(<vscale x 4 x i32> %a.rev, <vscale x 4 x i32> poison, i32 %offset)
- %b.insert = insertelement <vscale x 4 x i32> poison, i32 %b, i32 0
- %b.splat = shufflevector <vscale x 4 x i32> %b.insert, <vscale x 4 x i32> poison, <vscale x 4 x i32> zeroinitializer
- %add = add <vscale x 4 x i32> %a.splice, %b.splat
- ret <vscale x 4 x i32> %add
-}
-
-define <vscale x 4 x i32> @binop_reverse_splice_lhs_splat(<vscale x 4 x i32> %a, i32 %b, i32 %offset) {
-; CHECK-LABEL: @binop_reverse_splice_lhs_splat(
-; CHECK-NEXT: [[B_INSERT:%.*]] = insertelement <vscale x 4 x i32> poison, i32 [[B:%.*]], i64 0
-; CHECK-NEXT: [[B_SPLAT:%.*]] = shufflevector <vscale x 4 x i32> [[B_INSERT]], <vscale x 4 x i32> poison, <vscale x 4 x i32> zeroinitializer
-; CHECK-NEXT: [[ADD1:%.*]] = add <vscale x 4 x i32> [[B_SPLAT]], [[A:%.*]]
-; CHECK-NEXT: [[TMP1:%.*]] = call <vscale x 4 x i32> @llvm.vector.reverse.nxv4i32(<vscale x 4 x i32> [[ADD1]])
-; CHECK-NEXT: [[ADD:%.*]] = call <vscale x 4 x i32> @llvm.vector.splice.right.nxv4i32(<vscale x 4 x i32> [[TMP1]], <vscale x 4 x i32> poison, i32 [[OFFSET:%.*]])
-; CHECK-NEXT: ret <vscale x 4 x i32> [[ADD]]
-;
- %a.rev = tail call <vscale x 4 x i32> @llvm.vector.reverse(<vscale x 4 x i32> %a)
- %a.splice = tail call <vscale x 4 x i32> @llvm.vector.splice.right(<vscale x 4 x i32> %a.rev, <vscale x 4 x i32> poison, i32 %offset)
- %b.insert = insertelement <vscale x 4 x i32> poison, i32 %b, i32 0
- %b.splat = shufflevector <vscale x 4 x i32> %b.insert, <vscale x 4 x i32> poison, <vscale x 4 x i32> zeroinitializer
- %add = add <vscale x 4 x i32> %b.splat, %a.splice
- ret <vscale x 4 x i32> %add
-}
-
declare void @use_nxv4i1(<vscale x 4 x i1>)
declare void @use_nxv4i32(<vscale x 4 x i32>)
declare void @use_nxv4f32(<vscale x 4 x float>)
diff --git a/llvm/test/Transforms/InstCombine/vector-splice.ll b/llvm/test/Transforms/InstCombine/vector-splice.ll
new file mode 100644
index 0000000000000..b36c3e7e32fd5
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/vector-splice.ll
@@ -0,0 +1,122 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt < %s -p instcombine -S | FileCheck %s
+
+define <4 x i32> @binop_splice_left(<4 x i32> %v1, <4 x i32> %v2, <4 x i32> %v3, i32 %offset) {
+; CHECK-LABEL: define <4 x i32> @binop_splice_left(
+; CHECK-SAME: <4 x i32> [[V1:%.*]], <4 x i32> [[V2:%.*]], <4 x i32> [[V3:%.*]], i32 [[OFFSET:%.*]]) {
+; CHECK-NEXT: [[RES1:%.*]] = add <4 x i32> [[V1]], [[V2]]
+; CHECK-NEXT: [[RES:%.*]] = call <4 x i32> @llvm.vector.splice.right.v4i32(<4 x i32> [[RES1]], <4 x i32> [[V3]], i32 [[OFFSET]])
+; CHECK-NEXT: ret <4 x i32> [[RES]]
+;
+ %splice1 = call <4 x i32> @llvm.vector.splice.left(<4 x i32> %v1, <4 x i32> %v3, i32 %offset)
+ %splice2 = call <4 x i32> @llvm.vector.splice.left(<4 x i32> %v2, <4 x i32> %v3, i32 %offset)
+ %res = add <4 x i32> %splice1, %splice2
+ ret <4 x i32> %res
+}
+
+define <4 x i32> @binop_splice_left_rhs_splat(<4 x i32> %v1, i32 %x, <4 x i32> %v3, i32 %offset) {
+; CHECK-LABEL: define <4 x i32> @binop_splice_left_rhs_splat(
+; CHECK-SAME: <4 x i32> [[V1:%.*]], i32 [[X:%.*]], <4 x i32> [[V3:%.*]], i32 [[OFFSET:%.*]]) {
+; CHECK-NEXT: [[HEAD:%.*]] = insertelement <4 x i32> poison, i32 [[X]], i64 0
+; CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x i32> [[HEAD]], <4 x i32> poison, <4 x i32> zeroinitializer
+; CHECK-NEXT: [[RES1:%.*]] = add <4 x i32> [[V1]], [[SPLAT]]
+; CHECK-NEXT: [[RES:%.*]] = call <4 x i32> @llvm.vector.splice.right.v4i32(<4 x i32> [[RES1]], <4 x i32> [[V3]], i32 [[OFFSET]])
+; CHECK-NEXT: ret <4 x i32> [[RES]]
+;
+ %splice = call <4 x i32> @llvm.vector.splice.left(<4 x i32> %v1, <4 x i32> %v3, i32 %offset)
+ %head = insertelement <4 x i32> poison, i32 %x, i32 0
+ %splat = shufflevector <4 x i32> %head, <4 x i32> poison, <4 x i32> zeroinitializer
+ %res = add <4 x i32> %splice, %splat
+ ret <4 x i32> %res
+}
+
+define <4 x i32> @binop_splice_left_lhs_splat(<4 x i32> %v1, i32 %x, <4 x i32> %v3, i32 %offset) {
+; CHECK-LABEL: define <4 x i32> @binop_splice_left_lhs_splat(
+; CHECK-SAME: <4 x i32> [[V1:%.*]], i32 [[X:%.*]], <4 x i32> [[V3:%.*]], i32 [[OFFSET:%.*]]) {
+; CHECK-NEXT: [[HEAD:%.*]] = insertelement <4 x i32> poison, i32 [[X]], i64 0
+; CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x i32> [[HEAD]], <4 x i32> poison, <4 x i32> zeroinitializer
+; CHECK-NEXT: [[RES1:%.*]] = add <4 x i32> [[SPLAT]], [[V1]]
+; CHECK-NEXT: [[RES:%.*]] = call <4 x i32> @llvm.vector.splice.right.v4i32(<4 x i32> [[RES1]], <4 x i32> [[V3]], i32 [[OFFSET]])
+; CHECK-NEXT: ret <4 x i32> [[RES]]
+;
+ %splice = call <4 x i32> @llvm.vector.splice.left(<4 x i32> %v1, <4 x i32> %v3, i32 %offset)
+ %head = insertelement <4 x i32> poison, i32 %x, i32 0
+ %splat = shufflevector <4 x i32> %head, <4 x i32> poison, <4 x i32> zeroinitializer
+ %res = add <4 x i32> %splat, %splice
+ ret <4 x i32> %res
+}
+
+define <4 x i32> @binop_splice_right(<4 x i32> %v1, <4 x i32> %v2, <4 x i32> %v3, i32 %offset) {
+; CHECK-LABEL: define <4 x i32> @binop_splice_right(
+; CHECK-SAME: <4 x i32> [[V1:%.*]], <4 x i32> [[V2:%.*]], <4 x i32> [[V3:%.*]], i32 [[OFFSET:%.*]]) {
+; CHECK-NEXT: [[RES1:%.*]] = add <4 x i32> [[V1]], [[V2]]
+; CHECK-NEXT: [[RES:%.*]] = call <4 x i32> @llvm.vector.splice.right.v4i32(<4 x i32> [[RES1]], <4 x i32> [[V3]], i32 [[OFFSET]])
+; CHECK-NEXT: ret <4 x i32> [[RES]]
+;
+ %splice1 = call <4 x i32> @llvm.vector.splice.right(<4 x i32> %v1, <4 x i32> %v3, i32 %offset)
+ %splice2 = call <4 x i32> @llvm.vector.splice.right(<4 x i32> %v2, <4 x i32> %v3, i32 %offset)
+ %res = add <4 x i32> %splice1, %splice2
+ ret <4 x i32> %res
+}
+
+define <4 x i32> @binop_splice_right_rhs_splat(<4 x i32> %v1, i32 %x, <4 x i32> %v3, i32 %offset) {
+; CHECK-LABEL: define <4 x i32> @binop_splice_right_rhs_splat(
+; CHECK-SAME: <4 x i32> [[V1:%.*]], i32 [[X:%.*]], <4 x i32> [[V3:%.*]], i32 [[OFFSET:%.*]]) {
+; CHECK-NEXT: [[HEAD:%.*]] = insertelement <4 x i32> poison, i32 [[X]], i64 0
+; CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x i32> [[HEAD]], <4 x i32> poison, <4 x i32> zeroinitializer
+; CHECK-NEXT: [[RES1:%.*]] = add <4 x i32> [[V1]], [[SPLAT]]
+; CHECK-NEXT: [[RES:%.*]] = call <4 x i32> @llvm.vector.splice.right.v4i32(<4 x i32> [[RES1]], <4 x i32> [[V3]], i32 [[OFFSET]])
+; CHECK-NEXT: ret <4 x i32> [[RES]]
+;
+ %splice = call <4 x i32> @llvm.vector.splice.right(<4 x i32> %v1, <4 x i32> %v3, i32 %offset)
+ %head = insertelement <4 x i32> poison, i32 %x, i32 0
+ %splat = shufflevector <4 x i32> %head, <4 x i32> poison, <4 x i32> zeroinitializer
+ %res = add <4 x i32> %splice, %splat
+ ret <4 x i32> %res
+}
+
+define <4 x i32> @binop_splice_right_lhs_splat(<4 x i32> %v1, i32 %x, <4 x i32> %v3, i32 %offset) {
+; CHECK-LABEL: define <4 x i32> @binop_splice_right_lhs_splat(
+; CHECK-SAME: <4 x i32> [[V1:%.*]], i32 [[X:%.*]], <4 x i32> [[V3:%.*]], i32 [[OFFSET:%.*]]) {
+; CHECK-NEXT: [[HEAD:%.*]] = insertelement <4 x i32> poison, i32 [[X]], i64 0
+; CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x i32> [[HEAD]], <4 x i32> poison, <4 x i32> zeroinitializer
+; CHECK-NEXT: [[RES1:%.*]] = add <4 x i32> [[SPLAT]], [[V1]]
+; CHECK-NEXT: [[RES:%.*]] = call <4 x i32> @llvm.vector.splice.right.v4i32(<4 x i32> [[RES1]], <4 x i32> [[V3]], i32 [[OFFSET]])
+; CHECK-NEXT: ret <4 x i32> [[RES]]
+;
+ %splice = call <4 x i32> @llvm.vector.splice.right(<4 x i32> %v1, <4 x i32> %v3, i32 %offset)
+ %head = insertelement <4 x i32> poison, i32 %x, i32 0
+ %splat = shufflevector <4 x i32> %head, <4 x i32> poison, <4 x i32> zeroinitializer
+ %res = add <4 x i32> %splat, %splice
+ ret <4 x i32> %res
+}
+
+; Negative test, mismatched offset
+define <4 x i32> @binop_splice_mismatched_offset(<4 x i32> %v1, <4 x i32> %v2, <4 x i32> %v3, i32 %offset1, i32 %offset2) {
+; CHECK-LABEL: define <4 x i32> @binop_splice_mismatched_offset(
+; CHECK-SAME: <4 x i32> [[V1:%.*]], <4 x i32> [[V2:%.*]], <4 x i32> [[V3:%.*]], i32 [[OFFSET1:%.*]], i32 [[OFFSET2:%.*]]) {
+; CHECK-NEXT: [[SPLICE1:%.*]] = call <4 x i32> @llvm.vector.splice.right.v4i32(<4 x i32> [[V1]], <4 x i32> [[V3]], i32 [[OFFSET1]])
+; CHECK-NEXT: [[SPLICE2:%.*]] = call <4 x i32> @llvm.vector.splice.right.v4i32(<4 x i32> [[V2]], <4 x i32> [[V3]], i32 [[OFFSET2]])
+; CHECK-NEXT: [[RES:%.*]] = add <4 x i32> [[SPLICE1]], [[SPLICE2]]
+; CHECK-NEXT: ret <4 x i32> [[RES]]
+;
+ %splice1 = call <4 x i32> @llvm.vector.splice.right(<4 x i32> %v1, <4 x i32> %v3, i32 %offset1)
+ %splice2 = call <4 x i32> @llvm.vector.splice.right(<4 x i32> %v2, <4 x i32> %v3, i32 %offset2)
+ %res = add <4 x i32> %splice1, %splice2
+ ret <4 x i32> %res
+}
+
+; Negative test, mismatched vector operand
+define <4 x i32> @binop_splice_mismatched_vector(<4 x i32> %v1, <4 x i32> %v2, <4 x i32> %v3, <4 x i32> %v4, i32 %offset) {
+; CHECK-LABEL: define <4 x i32> @binop_splice_mismatched_vector(
+; CHECK-SAME: <4 x i32> [[V1:%.*]], <4 x i32> [[V2:%.*]], <4 x i32> [[V3:%.*]], <4 x i32> [[V4:%.*]], i32 [[OFFSET:%.*]]) {
+; CHECK-NEXT: [[SPLICE1:%.*]] = call <4 x i32> @llvm.vector.splice.right.v4i32(<4 x i32> [[V1]], <4 x i32> [[V3]], i32 [[OFFSET]])
+; CHECK-NEXT: [[SPLICE2:%.*]] = call <4 x i32> @llvm.vector.splice.right.v4i32(<4 x i32> [[V2]], <4 x i32> [[V4]], i32 [[OFFSET]])
+; CHECK-NEXT: [[RES:%.*]] = add <4 x i32> [[SPLICE1]], [[SPLICE2]]
+; CHECK-NEXT: ret <4 x i32> [[RES]]
+;
+ %splice1 = call <4 x i32> @llvm.vector.splice.right(<4 x i32> %v1, <4 x i32> %v3, i32 %offset)
+ %splice2 = call <4 x i32> @llvm.vector.splice.right(<4 x i32> %v2, <4 x i32> %v4, i32 %offset)
+ %res = add <4 x i32> %splice1, %splice2
+ ret <4 x i32> %res
+}
>From b0a18a0023f0c58c4b62e6e6269f4ac37c4d5211 Mon Sep 17 00:00:00 2001
From: Luke Lau <luke at igalia.com>
Date: Tue, 3 Feb 2026 22:42:30 +0800
Subject: [PATCH 5/6] Fix wrong intrinsic ID
---
llvm/lib/Transforms/InstCombine/InstructionCombining.cpp | 3 +--
llvm/test/Transforms/InstCombine/vector-splice.ll | 6 +++---
2 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
index 82a26eda440dc..37964a5429d54 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -2401,8 +2401,7 @@ static Instruction *foldSpliceBinOp(BinaryOperator &Inst,
if (auto *BO = dyn_cast<BinaryOperator>(V))
BO->copyIRFlags(&Inst);
Module *M = Inst.getModule();
- Function *F = Intrinsic::getOrInsertDeclaration(
- M, Intrinsic::vector_splice_right, V->getType());
+ Function *F = Intrinsic::getOrInsertDeclaration(M, SpliceID, V->getType());
return CallInst::Create(F, {V, Z, Offset});
};
Value *V1, *V2, *V3, *Offset;
diff --git a/llvm/test/Transforms/InstCombine/vector-splice.ll b/llvm/test/Transforms/InstCombine/vector-splice.ll
index b36c3e7e32fd5..081e1f116add9 100644
--- a/llvm/test/Transforms/InstCombine/vector-splice.ll
+++ b/llvm/test/Transforms/InstCombine/vector-splice.ll
@@ -5,7 +5,7 @@ define <4 x i32> @binop_splice_left(<4 x i32> %v1, <4 x i32> %v2, <4 x i32> %v3,
; CHECK-LABEL: define <4 x i32> @binop_splice_left(
; CHECK-SAME: <4 x i32> [[V1:%.*]], <4 x i32> [[V2:%.*]], <4 x i32> [[V3:%.*]], i32 [[OFFSET:%.*]]) {
; CHECK-NEXT: [[RES1:%.*]] = add <4 x i32> [[V1]], [[V2]]
-; CHECK-NEXT: [[RES:%.*]] = call <4 x i32> @llvm.vector.splice.right.v4i32(<4 x i32> [[RES1]], <4 x i32> [[V3]], i32 [[OFFSET]])
+; CHECK-NEXT: [[RES:%.*]] = call <4 x i32> @llvm.vector.splice.left.v4i32(<4 x i32> [[RES1]], <4 x i32> [[V3]], i32 [[OFFSET]])
; CHECK-NEXT: ret <4 x i32> [[RES]]
;
%splice1 = call <4 x i32> @llvm.vector.splice.left(<4 x i32> %v1, <4 x i32> %v3, i32 %offset)
@@ -20,7 +20,7 @@ define <4 x i32> @binop_splice_left_rhs_splat(<4 x i32> %v1, i32 %x, <4 x i32> %
; CHECK-NEXT: [[HEAD:%.*]] = insertelement <4 x i32> poison, i32 [[X]], i64 0
; CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x i32> [[HEAD]], <4 x i32> poison, <4 x i32> zeroinitializer
; CHECK-NEXT: [[RES1:%.*]] = add <4 x i32> [[V1]], [[SPLAT]]
-; CHECK-NEXT: [[RES:%.*]] = call <4 x i32> @llvm.vector.splice.right.v4i32(<4 x i32> [[RES1]], <4 x i32> [[V3]], i32 [[OFFSET]])
+; CHECK-NEXT: [[RES:%.*]] = call <4 x i32> @llvm.vector.splice.left.v4i32(<4 x i32> [[RES1]], <4 x i32> [[V3]], i32 [[OFFSET]])
; CHECK-NEXT: ret <4 x i32> [[RES]]
;
%splice = call <4 x i32> @llvm.vector.splice.left(<4 x i32> %v1, <4 x i32> %v3, i32 %offset)
@@ -36,7 +36,7 @@ define <4 x i32> @binop_splice_left_lhs_splat(<4 x i32> %v1, i32 %x, <4 x i32> %
; CHECK-NEXT: [[HEAD:%.*]] = insertelement <4 x i32> poison, i32 [[X]], i64 0
; CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x i32> [[HEAD]], <4 x i32> poison, <4 x i32> zeroinitializer
; CHECK-NEXT: [[RES1:%.*]] = add <4 x i32> [[SPLAT]], [[V1]]
-; CHECK-NEXT: [[RES:%.*]] = call <4 x i32> @llvm.vector.splice.right.v4i32(<4 x i32> [[RES1]], <4 x i32> [[V3]], i32 [[OFFSET]])
+; CHECK-NEXT: [[RES:%.*]] = call <4 x i32> @llvm.vector.splice.left.v4i32(<4 x i32> [[RES1]], <4 x i32> [[V3]], i32 [[OFFSET]])
; CHECK-NEXT: ret <4 x i32> [[RES]]
;
%splice = call <4 x i32> @llvm.vector.splice.left(<4 x i32> %v1, <4 x i32> %v3, i32 %offset)
>From 80bdfd2f08f71d6e745d19e6fe1092b9033646f3 Mon Sep 17 00:00:00 2001
From: Luke Lau <luke at igalia.com>
Date: Tue, 3 Feb 2026 23:26:59 +0800
Subject: [PATCH 6/6] Restrict to second splice operand being poison
---
.../InstCombine/InstructionCombining.cpp | 34 ++++-----
.../Transforms/InstCombine/vector-splice.ll | 75 ++++++++++---------
2 files changed, 55 insertions(+), 54 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
index 37964a5429d54..e2bda2450c66f 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -2396,40 +2396,40 @@ template <Intrinsic::ID SpliceID>
static Instruction *foldSpliceBinOp(BinaryOperator &Inst,
InstCombiner::BuilderTy &Builder) {
Value *LHS = Inst.getOperand(0), *RHS = Inst.getOperand(1);
- auto CreateBinOpSplice = [&](Value *X, Value *Y, Value *Z, Value *Offset) {
+ auto CreateBinOpSplice = [&](Value *X, Value *Y, Value *Offset) {
Value *V = Builder.CreateBinOp(Inst.getOpcode(), X, Y, Inst.getName());
if (auto *BO = dyn_cast<BinaryOperator>(V))
BO->copyIRFlags(&Inst);
Module *M = Inst.getModule();
Function *F = Intrinsic::getOrInsertDeclaration(M, SpliceID, V->getType());
- return CallInst::Create(F, {V, Z, Offset});
+ return CallInst::Create(F, {V, PoisonValue::get(V->getType()), Offset});
};
- Value *V1, *V2, *V3, *Offset;
+ Value *V1, *V2, *Offset;
if (match(LHS,
- m_Intrinsic<SpliceID>(m_Value(V1), m_Value(V3), m_Value(Offset)))) {
- // Op(splice(V1, V3, offset), splice(V2, V3, offset))
- // -> splice(Op(V1, V2), V3, offset)
- if (match(RHS, m_Intrinsic<SpliceID>(m_Value(V2), m_Specific(V3),
+ m_Intrinsic<SpliceID>(m_Value(V1), m_Poison(), m_Value(Offset)))) {
+ // Op(splice(V1, poison, offset), splice(V2, poison, offset))
+ // -> splice(Op(V1, V2), poison, offset)
+ if (match(RHS, m_Intrinsic<SpliceID>(m_Value(V2), m_Poison(),
m_Specific(Offset))) &&
(LHS->hasOneUse() || RHS->hasOneUse() ||
(LHS == RHS && LHS->hasNUses(2))))
- return CreateBinOpSplice(V1, V2, V3, Offset);
+ return CreateBinOpSplice(V1, V2, Offset);
- // Op(splice(V1, V3, offset), RHSSplat)
- // -> splice(Op(V1, RHSSplat), V3, offset)
+ // Op(splice(V1, poison, offset), RHSSplat)
+ // -> splice(Op(V1, RHSSplat), poison, offset)
if (LHS->hasOneUse() && isSplatValue(RHS))
- return CreateBinOpSplice(V1, RHS, V3, Offset);
+ return CreateBinOpSplice(V1, RHS, Offset);
}
- // Op(LHSSplat, splice(V2, V3, offset))
- // -> splice(Op(LHSSplat, V2), V3, offset)
+ // Op(LHSSplat, splice(V2, poison, offset))
+ // -> splice(Op(LHSSplat, V2), poison, offset)
else if (isSplatValue(LHS) &&
- match(RHS, m_OneUse(m_Intrinsic<SpliceID>(m_Value(V2), m_Value(V3),
+ match(RHS, m_OneUse(m_Intrinsic<SpliceID>(m_Value(V2), m_Poison(),
m_Value(Offset)))))
- return CreateBinOpSplice(LHS, V2, V3, Offset);
+ return CreateBinOpSplice(LHS, V2, Offset);
// TODO: Fold binops of the form
- // Op(splice(V3, V1, offset), splice(V3, V2, offset))
- // -> splice(V3, Op(V1, V2), offset)
+ // Op(splice(poison, V1, offset), splice(poison, V2, offset))
+ // -> splice(poison, Op(V1, V2), offset)
return nullptr;
}
diff --git a/llvm/test/Transforms/InstCombine/vector-splice.ll b/llvm/test/Transforms/InstCombine/vector-splice.ll
index 081e1f116add9..902ae96181a71 100644
--- a/llvm/test/Transforms/InstCombine/vector-splice.ll
+++ b/llvm/test/Transforms/InstCombine/vector-splice.ll
@@ -1,90 +1,90 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
; RUN: opt < %s -p instcombine -S | FileCheck %s
-define <4 x i32> @binop_splice_left(<4 x i32> %v1, <4 x i32> %v2, <4 x i32> %v3, i32 %offset) {
+define <4 x i32> @binop_splice_left(<4 x i32> %v1, <4 x i32> %v2, i32 %offset) {
; CHECK-LABEL: define <4 x i32> @binop_splice_left(
-; CHECK-SAME: <4 x i32> [[V1:%.*]], <4 x i32> [[V2:%.*]], <4 x i32> [[V3:%.*]], i32 [[OFFSET:%.*]]) {
+; CHECK-SAME: <4 x i32> [[V1:%.*]], <4 x i32> [[V2:%.*]], i32 [[OFFSET:%.*]]) {
; CHECK-NEXT: [[RES1:%.*]] = add <4 x i32> [[V1]], [[V2]]
-; CHECK-NEXT: [[RES:%.*]] = call <4 x i32> @llvm.vector.splice.left.v4i32(<4 x i32> [[RES1]], <4 x i32> [[V3]], i32 [[OFFSET]])
+; CHECK-NEXT: [[RES:%.*]] = call <4 x i32> @llvm.vector.splice.left.v4i32(<4 x i32> [[RES1]], <4 x i32> poison, i32 [[OFFSET]])
; CHECK-NEXT: ret <4 x i32> [[RES]]
;
- %splice1 = call <4 x i32> @llvm.vector.splice.left(<4 x i32> %v1, <4 x i32> %v3, i32 %offset)
- %splice2 = call <4 x i32> @llvm.vector.splice.left(<4 x i32> %v2, <4 x i32> %v3, i32 %offset)
+ %splice1 = call <4 x i32> @llvm.vector.splice.left(<4 x i32> %v1, <4 x i32> poison, i32 %offset)
+ %splice2 = call <4 x i32> @llvm.vector.splice.left(<4 x i32> %v2, <4 x i32> poison, i32 %offset)
%res = add <4 x i32> %splice1, %splice2
ret <4 x i32> %res
}
-define <4 x i32> @binop_splice_left_rhs_splat(<4 x i32> %v1, i32 %x, <4 x i32> %v3, i32 %offset) {
+define <4 x i32> @binop_splice_left_rhs_splat(<4 x i32> %v1, i32 %x, i32 %offset) {
; CHECK-LABEL: define <4 x i32> @binop_splice_left_rhs_splat(
-; CHECK-SAME: <4 x i32> [[V1:%.*]], i32 [[X:%.*]], <4 x i32> [[V3:%.*]], i32 [[OFFSET:%.*]]) {
+; CHECK-SAME: <4 x i32> [[V1:%.*]], i32 [[X:%.*]], i32 [[OFFSET:%.*]]) {
; CHECK-NEXT: [[HEAD:%.*]] = insertelement <4 x i32> poison, i32 [[X]], i64 0
; CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x i32> [[HEAD]], <4 x i32> poison, <4 x i32> zeroinitializer
; CHECK-NEXT: [[RES1:%.*]] = add <4 x i32> [[V1]], [[SPLAT]]
-; CHECK-NEXT: [[RES:%.*]] = call <4 x i32> @llvm.vector.splice.left.v4i32(<4 x i32> [[RES1]], <4 x i32> [[V3]], i32 [[OFFSET]])
+; CHECK-NEXT: [[RES:%.*]] = call <4 x i32> @llvm.vector.splice.left.v4i32(<4 x i32> [[RES1]], <4 x i32> poison, i32 [[OFFSET]])
; CHECK-NEXT: ret <4 x i32> [[RES]]
;
- %splice = call <4 x i32> @llvm.vector.splice.left(<4 x i32> %v1, <4 x i32> %v3, i32 %offset)
+ %splice = call <4 x i32> @llvm.vector.splice.left(<4 x i32> %v1, <4 x i32> poison, i32 %offset)
%head = insertelement <4 x i32> poison, i32 %x, i32 0
%splat = shufflevector <4 x i32> %head, <4 x i32> poison, <4 x i32> zeroinitializer
%res = add <4 x i32> %splice, %splat
ret <4 x i32> %res
}
-define <4 x i32> @binop_splice_left_lhs_splat(<4 x i32> %v1, i32 %x, <4 x i32> %v3, i32 %offset) {
+define <4 x i32> @binop_splice_left_lhs_splat(<4 x i32> %v1, i32 %x, i32 %offset) {
; CHECK-LABEL: define <4 x i32> @binop_splice_left_lhs_splat(
-; CHECK-SAME: <4 x i32> [[V1:%.*]], i32 [[X:%.*]], <4 x i32> [[V3:%.*]], i32 [[OFFSET:%.*]]) {
+; CHECK-SAME: <4 x i32> [[V1:%.*]], i32 [[X:%.*]], i32 [[OFFSET:%.*]]) {
; CHECK-NEXT: [[HEAD:%.*]] = insertelement <4 x i32> poison, i32 [[X]], i64 0
; CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x i32> [[HEAD]], <4 x i32> poison, <4 x i32> zeroinitializer
; CHECK-NEXT: [[RES1:%.*]] = add <4 x i32> [[SPLAT]], [[V1]]
-; CHECK-NEXT: [[RES:%.*]] = call <4 x i32> @llvm.vector.splice.left.v4i32(<4 x i32> [[RES1]], <4 x i32> [[V3]], i32 [[OFFSET]])
+; CHECK-NEXT: [[RES:%.*]] = call <4 x i32> @llvm.vector.splice.left.v4i32(<4 x i32> [[RES1]], <4 x i32> poison, i32 [[OFFSET]])
; CHECK-NEXT: ret <4 x i32> [[RES]]
;
- %splice = call <4 x i32> @llvm.vector.splice.left(<4 x i32> %v1, <4 x i32> %v3, i32 %offset)
+ %splice = call <4 x i32> @llvm.vector.splice.left(<4 x i32> %v1, <4 x i32> poison, i32 %offset)
%head = insertelement <4 x i32> poison, i32 %x, i32 0
%splat = shufflevector <4 x i32> %head, <4 x i32> poison, <4 x i32> zeroinitializer
%res = add <4 x i32> %splat, %splice
ret <4 x i32> %res
}
-define <4 x i32> @binop_splice_right(<4 x i32> %v1, <4 x i32> %v2, <4 x i32> %v3, i32 %offset) {
+define <4 x i32> @binop_splice_right(<4 x i32> %v1, <4 x i32> %v2, i32 %offset) {
; CHECK-LABEL: define <4 x i32> @binop_splice_right(
-; CHECK-SAME: <4 x i32> [[V1:%.*]], <4 x i32> [[V2:%.*]], <4 x i32> [[V3:%.*]], i32 [[OFFSET:%.*]]) {
+; CHECK-SAME: <4 x i32> [[V1:%.*]], <4 x i32> [[V2:%.*]], i32 [[OFFSET:%.*]]) {
; CHECK-NEXT: [[RES1:%.*]] = add <4 x i32> [[V1]], [[V2]]
-; CHECK-NEXT: [[RES:%.*]] = call <4 x i32> @llvm.vector.splice.right.v4i32(<4 x i32> [[RES1]], <4 x i32> [[V3]], i32 [[OFFSET]])
+; CHECK-NEXT: [[RES:%.*]] = call <4 x i32> @llvm.vector.splice.right.v4i32(<4 x i32> [[RES1]], <4 x i32> poison, i32 [[OFFSET]])
; CHECK-NEXT: ret <4 x i32> [[RES]]
;
- %splice1 = call <4 x i32> @llvm.vector.splice.right(<4 x i32> %v1, <4 x i32> %v3, i32 %offset)
- %splice2 = call <4 x i32> @llvm.vector.splice.right(<4 x i32> %v2, <4 x i32> %v3, i32 %offset)
+ %splice1 = call <4 x i32> @llvm.vector.splice.right(<4 x i32> %v1, <4 x i32> poison, i32 %offset)
+ %splice2 = call <4 x i32> @llvm.vector.splice.right(<4 x i32> %v2, <4 x i32> poison, i32 %offset)
%res = add <4 x i32> %splice1, %splice2
ret <4 x i32> %res
}
-define <4 x i32> @binop_splice_right_rhs_splat(<4 x i32> %v1, i32 %x, <4 x i32> %v3, i32 %offset) {
+define <4 x i32> @binop_splice_right_rhs_splat(<4 x i32> %v1, i32 %x, i32 %offset) {
; CHECK-LABEL: define <4 x i32> @binop_splice_right_rhs_splat(
-; CHECK-SAME: <4 x i32> [[V1:%.*]], i32 [[X:%.*]], <4 x i32> [[V3:%.*]], i32 [[OFFSET:%.*]]) {
+; CHECK-SAME: <4 x i32> [[V1:%.*]], i32 [[X:%.*]], i32 [[OFFSET:%.*]]) {
; CHECK-NEXT: [[HEAD:%.*]] = insertelement <4 x i32> poison, i32 [[X]], i64 0
; CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x i32> [[HEAD]], <4 x i32> poison, <4 x i32> zeroinitializer
; CHECK-NEXT: [[RES1:%.*]] = add <4 x i32> [[V1]], [[SPLAT]]
-; CHECK-NEXT: [[RES:%.*]] = call <4 x i32> @llvm.vector.splice.right.v4i32(<4 x i32> [[RES1]], <4 x i32> [[V3]], i32 [[OFFSET]])
+; CHECK-NEXT: [[RES:%.*]] = call <4 x i32> @llvm.vector.splice.right.v4i32(<4 x i32> [[RES1]], <4 x i32> poison, i32 [[OFFSET]])
; CHECK-NEXT: ret <4 x i32> [[RES]]
;
- %splice = call <4 x i32> @llvm.vector.splice.right(<4 x i32> %v1, <4 x i32> %v3, i32 %offset)
+ %splice = call <4 x i32> @llvm.vector.splice.right(<4 x i32> %v1, <4 x i32> poison, i32 %offset)
%head = insertelement <4 x i32> poison, i32 %x, i32 0
%splat = shufflevector <4 x i32> %head, <4 x i32> poison, <4 x i32> zeroinitializer
%res = add <4 x i32> %splice, %splat
ret <4 x i32> %res
}
-define <4 x i32> @binop_splice_right_lhs_splat(<4 x i32> %v1, i32 %x, <4 x i32> %v3, i32 %offset) {
+define <4 x i32> @binop_splice_right_lhs_splat(<4 x i32> %v1, i32 %x, i32 %offset) {
; CHECK-LABEL: define <4 x i32> @binop_splice_right_lhs_splat(
-; CHECK-SAME: <4 x i32> [[V1:%.*]], i32 [[X:%.*]], <4 x i32> [[V3:%.*]], i32 [[OFFSET:%.*]]) {
+; CHECK-SAME: <4 x i32> [[V1:%.*]], i32 [[X:%.*]], i32 [[OFFSET:%.*]]) {
; CHECK-NEXT: [[HEAD:%.*]] = insertelement <4 x i32> poison, i32 [[X]], i64 0
; CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x i32> [[HEAD]], <4 x i32> poison, <4 x i32> zeroinitializer
; CHECK-NEXT: [[RES1:%.*]] = add <4 x i32> [[SPLAT]], [[V1]]
-; CHECK-NEXT: [[RES:%.*]] = call <4 x i32> @llvm.vector.splice.right.v4i32(<4 x i32> [[RES1]], <4 x i32> [[V3]], i32 [[OFFSET]])
+; CHECK-NEXT: [[RES:%.*]] = call <4 x i32> @llvm.vector.splice.right.v4i32(<4 x i32> [[RES1]], <4 x i32> poison, i32 [[OFFSET]])
; CHECK-NEXT: ret <4 x i32> [[RES]]
;
- %splice = call <4 x i32> @llvm.vector.splice.right(<4 x i32> %v1, <4 x i32> %v3, i32 %offset)
+ %splice = call <4 x i32> @llvm.vector.splice.right(<4 x i32> %v1, <4 x i32> poison, i32 %offset)
%head = insertelement <4 x i32> poison, i32 %x, i32 0
%splat = shufflevector <4 x i32> %head, <4 x i32> poison, <4 x i32> zeroinitializer
%res = add <4 x i32> %splat, %splice
@@ -92,31 +92,32 @@ define <4 x i32> @binop_splice_right_lhs_splat(<4 x i32> %v1, i32 %x, <4 x i32>
}
; Negative test, mismatched offset
-define <4 x i32> @binop_splice_mismatched_offset(<4 x i32> %v1, <4 x i32> %v2, <4 x i32> %v3, i32 %offset1, i32 %offset2) {
+define <4 x i32> @binop_splice_mismatched_offset(<4 x i32> %v1, <4 x i32> %v2, i32 %offset1, i32 %offset2) {
; CHECK-LABEL: define <4 x i32> @binop_splice_mismatched_offset(
-; CHECK-SAME: <4 x i32> [[V1:%.*]], <4 x i32> [[V2:%.*]], <4 x i32> [[V3:%.*]], i32 [[OFFSET1:%.*]], i32 [[OFFSET2:%.*]]) {
-; CHECK-NEXT: [[SPLICE1:%.*]] = call <4 x i32> @llvm.vector.splice.right.v4i32(<4 x i32> [[V1]], <4 x i32> [[V3]], i32 [[OFFSET1]])
-; CHECK-NEXT: [[SPLICE2:%.*]] = call <4 x i32> @llvm.vector.splice.right.v4i32(<4 x i32> [[V2]], <4 x i32> [[V3]], i32 [[OFFSET2]])
+; CHECK-SAME: <4 x i32> [[V1:%.*]], <4 x i32> [[V2:%.*]], i32 [[OFFSET1:%.*]], i32 [[OFFSET2:%.*]]) {
+; CHECK-NEXT: [[SPLICE1:%.*]] = call <4 x i32> @llvm.vector.splice.right.v4i32(<4 x i32> [[V1]], <4 x i32> poison, i32 [[OFFSET1]])
+; CHECK-NEXT: [[SPLICE2:%.*]] = call <4 x i32> @llvm.vector.splice.right.v4i32(<4 x i32> [[V2]], <4 x i32> poison, i32 [[OFFSET2]])
; CHECK-NEXT: [[RES:%.*]] = add <4 x i32> [[SPLICE1]], [[SPLICE2]]
; CHECK-NEXT: ret <4 x i32> [[RES]]
;
- %splice1 = call <4 x i32> @llvm.vector.splice.right(<4 x i32> %v1, <4 x i32> %v3, i32 %offset1)
- %splice2 = call <4 x i32> @llvm.vector.splice.right(<4 x i32> %v2, <4 x i32> %v3, i32 %offset2)
+ %splice1 = call <4 x i32> @llvm.vector.splice.right(<4 x i32> %v1, <4 x i32> poison, i32 %offset1)
+ %splice2 = call <4 x i32> @llvm.vector.splice.right(<4 x i32> %v2, <4 x i32> poison, i32 %offset2)
%res = add <4 x i32> %splice1, %splice2
ret <4 x i32> %res
}
-; Negative test, mismatched vector operand
-define <4 x i32> @binop_splice_mismatched_vector(<4 x i32> %v1, <4 x i32> %v2, <4 x i32> %v3, <4 x i32> %v4, i32 %offset) {
+; Negative test, non poison vector operand
+define <4 x i32> @binop_splice_mismatched_vector(<4 x i32> %v1, <4 x i32> %v2, <4 x i32> %v3, i32 %offset) {
; CHECK-LABEL: define <4 x i32> @binop_splice_mismatched_vector(
-; CHECK-SAME: <4 x i32> [[V1:%.*]], <4 x i32> [[V2:%.*]], <4 x i32> [[V3:%.*]], <4 x i32> [[V4:%.*]], i32 [[OFFSET:%.*]]) {
+; CHECK-SAME: <4 x i32> [[V1:%.*]], <4 x i32> [[V2:%.*]], <4 x i32> [[V3:%.*]], i32 [[OFFSET:%.*]]) {
; CHECK-NEXT: [[SPLICE1:%.*]] = call <4 x i32> @llvm.vector.splice.right.v4i32(<4 x i32> [[V1]], <4 x i32> [[V3]], i32 [[OFFSET]])
-; CHECK-NEXT: [[SPLICE2:%.*]] = call <4 x i32> @llvm.vector.splice.right.v4i32(<4 x i32> [[V2]], <4 x i32> [[V4]], i32 [[OFFSET]])
+; CHECK-NEXT: [[SPLICE2:%.*]] = call <4 x i32> @llvm.vector.splice.right.v4i32(<4 x i32> [[V2]], <4 x i32> [[V3]], i32 [[OFFSET]])
; CHECK-NEXT: [[RES:%.*]] = add <4 x i32> [[SPLICE1]], [[SPLICE2]]
; CHECK-NEXT: ret <4 x i32> [[RES]]
;
%splice1 = call <4 x i32> @llvm.vector.splice.right(<4 x i32> %v1, <4 x i32> %v3, i32 %offset)
- %splice2 = call <4 x i32> @llvm.vector.splice.right(<4 x i32> %v2, <4 x i32> %v4, i32 %offset)
+ %splice2 = call <4 x i32> @llvm.vector.splice.right(<4 x i32> %v2, <4 x i32> %v3, i32 %offset)
%res = add <4 x i32> %splice1, %splice2
ret <4 x i32> %res
}
+
More information about the llvm-commits
mailing list