[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