[llvm] [AArch64][ISel] Fix interleave3 crash (PR #192046)

Matthew Devereau via llvm-commits llvm-commits at lists.llvm.org
Tue Apr 14 08:48:34 PDT 2026


https://github.com/MDevereau updated https://github.com/llvm/llvm-project/pull/192046

>From cc222c023ede447683d5e080508afd58bdb63238 Mon Sep 17 00:00:00 2001
From: Matthew Devereau <matthew.devereau at arm.com>
Date: Tue, 14 Apr 2026 12:31:31 +0000
Subject: [PATCH 1/3] [AArch64][ISel] Fix interleave3 crash

This fixes a crash where an interleave3 intrinsic is left behind due
to multiple stores, where it has no independent lowering.
---
 .../Target/AArch64/AArch64ISelLowering.cpp    |  57 +++++++++
 .../AArch64/fixed-vector-interleave.ll        | 115 ++++++++++++++++++
 2 files changed, 172 insertions(+)

diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index ece24767bdbb9..ad5e935c2266a 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -32322,6 +32322,63 @@ SDValue AArch64TargetLowering::LowerVECTOR_INTERLEAVE(SDValue Op,
     return DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, Op->getVTList(), Ops);
   }
 
+  if (Op->getNumOperands() == 3 && (OpVT == MVT::v2f64 || OpVT == MVT::v2i64)) {
+    SDValue A = Op->getOperand(0);
+    SDValue B = Op->getOperand(1);
+    SDValue C = Op->getOperand(2);
+
+    // a0, a1 | b0, b1 | c0, c1
+    //  ->
+    // a0, b0 | c0, a1 | b1, c1
+    SDValue Shuffle0 = DAG.getVectorShuffle(OpVT, DL, A, B, {0, 2});
+    SDValue Shuffle1 = DAG.getVectorShuffle(OpVT, DL, A, C, {2, 1});
+    SDValue Shuffle2 = DAG.getVectorShuffle(OpVT, DL, B, C, {1, 3});
+
+    return DAG.getMergeValues({Shuffle0, Shuffle1, Shuffle2}, DL);
+  }
+  if (Op->getNumOperands() == 3 && OpVT.isFixedLengthVector()) {
+    unsigned NElements = OpVT.getVectorNumElements();
+    SDValue A = Op->getOperand(0);
+    SDValue B = Op->getOperand(1);
+    SDValue C = Op->getOperand(2);
+
+    //  Build two masks for two shuffles. The first mask shuffles elements from
+    //  A and B, and with elements of C represented with -1 so the shuffle
+    //  ignores them. The second shuffle then replaces -1 values with the actual
+    //  indices from C.
+    SmallVector<int> ABMask;
+    for (unsigned E = 0; E < NElements; E++) {
+      for (unsigned F = 0; F < 3; F++) {
+        if (F == 2)
+          ABMask.push_back(-1);
+        else
+          ABMask.push_back(F * NElements + E);
+      }
+    }
+
+    std::vector<int> ABCMask;
+    for (unsigned F = 0, Idx = 0; F < 3; F++) {
+      for (unsigned E = 0; E < NElements; E++) {
+        if (ABMask[F * NElements + E] == -1)
+          ABCMask.push_back(NElements + Idx++);
+        else
+          ABCMask.push_back(Idx);
+      }
+    }
+
+    SmallVector<SDValue, 3> Shuffles;
+    for (unsigned I = 0; I < 3; I++) {
+      SDValue AB = DAG.getVectorShuffle(
+          OpVT, DL, A, B,
+          ArrayRef<int>(ABMask.data() + NElements * I, NElements));
+      Shuffles.push_back(DAG.getVectorShuffle(
+          OpVT, DL, AB, C,
+          ArrayRef<int>(ABCMask.data() + NElements * I, NElements)));
+    }
+
+    return DAG.getMergeValues(Shuffles, DL);
+  }
+
   if (Op->getNumOperands() != 2)
     return SDValue();
 
diff --git a/llvm/test/CodeGen/AArch64/fixed-vector-interleave.ll b/llvm/test/CodeGen/AArch64/fixed-vector-interleave.ll
index eb9d576daee4e..054173a5eabbb 100644
--- a/llvm/test/CodeGen/AArch64/fixed-vector-interleave.ll
+++ b/llvm/test/CodeGen/AArch64/fixed-vector-interleave.ll
@@ -453,3 +453,118 @@ define <32 x bfloat> @interleave4_v32bf16(<8 x bfloat> %vec0, <8 x bfloat> %vec1
   %retval = call <32 x bfloat> @llvm.vector.interleave4.v32bf16(<8 x bfloat> %vec0, <8 x bfloat> %vec1, <8 x bfloat> %vec2, <8 x bfloat> %vec3)
   ret <32 x bfloat> %retval
 }
+
+define void @interleave3_v6f64(ptr %p, ptr %p0, <2 x double> %vec0, <2 x double> %vec1, <2 x double> %vec2) {
+; CHECK-LABEL: interleave3_v6f64:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    zip1 v3.2d, v0.2d, v1.2d
+; CHECK-NEXT:    mov v0.d[0], v2.d[0]
+; CHECK-NEXT:    zip2 v1.2d, v1.2d, v2.2d
+; CHECK-NEXT:    stp q3, q0, [x0]
+; CHECK-NEXT:    str q1, [x0, #32]
+; CHECK-NEXT:    stp q3, q0, [x1]
+; CHECK-NEXT:    str q1, [x1, #32]
+; CHECK-NEXT:    ret
+  %retval = call <6 x double> @llvm.vector.interleave3.v6f64(<2 x double> %vec0, <2 x double> %vec1, <2 x double> %vec2)
+  store <6 x double> %retval, ptr %p
+  store <6 x double> %retval, ptr %p0
+  ret void
+}
+
+define void @interleave3_v12f32(ptr %p, ptr %p0, <4 x float> %vec0, <4 x float> %vec1, <4 x float> %vec2) {
+; CHECK-LABEL: interleave3_v12f32:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    trn2 v3.4s, v0.4s, v1.4s
+; CHECK-NEXT:    trn1 v4.4s, v0.4s, v1.4s
+; CHECK-NEXT:    uzp1 v5.4s, v0.4s, v1.4s
+; CHECK-NEXT:    ext v3.16b, v3.16b, v0.16b, #4
+; CHECK-NEXT:    mov v4.d[1], v0.d[0]
+; CHECK-NEXT:    uzp2 v0.4s, v1.4s, v5.4s
+; CHECK-NEXT:    zip2 v1.4s, v3.4s, v2.4s
+; CHECK-NEXT:    zip1 v5.4s, v4.4s, v2.4s
+; CHECK-NEXT:    zip1 v2.4s, v0.4s, v2.4s
+; CHECK-NEXT:    dup v0.4s, v0.s[2]
+; CHECK-NEXT:    ext v3.16b, v3.16b, v1.16b, #12
+; CHECK-NEXT:    zip1 v4.4s, v5.4s, v4.4s
+; CHECK-NEXT:    ext v0.16b, v2.16b, v0.16b, #8
+; CHECK-NEXT:    zip2 v1.4s, v3.4s, v1.4s
+; CHECK-NEXT:    stp q4, q0, [x0]
+; CHECK-NEXT:    str q1, [x0, #32]
+; CHECK-NEXT:    stp q4, q0, [x1]
+; CHECK-NEXT:    str q1, [x1, #32]
+; CHECK-NEXT:    ret
+  %retval = call <12 x float> @llvm.vector.interleave3.v12f32(<4 x float> %vec0, <4 x float> %vec1, <4 x float> %vec2)
+  store <12 x float> %retval, ptr %p
+  store <12 x float> %retval, ptr %p0
+  ret void
+}
+
+define void @interleave3_v24i16(ptr %p, ptr %p0, <8 x i16> %vec0, <8 x i16> %vec1, <8 x i16> %vec2) {
+; CHECK-LABEL: interleave3_v24i16:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    // kill: def $q2 killed $q2 killed $q1_q2 def $q1_q2
+; CHECK-NEXT:    mov v4.16b, v1.16b
+; CHECK-NEXT:    adrp x8, .LCPI32_0
+; CHECK-NEXT:    adrp x9, .LCPI32_2
+; CHECK-NEXT:    mov v3.16b, v0.16b
+; CHECK-NEXT:    ldr q0, [x8, :lo12:.LCPI32_0]
+; CHECK-NEXT:    adrp x8, .LCPI32_1
+; CHECK-NEXT:    ldr q5, [x9, :lo12:.LCPI32_2]
+; CHECK-NEXT:    adrp x9, .LCPI32_4
+; CHECK-NEXT:    ldr q6, [x9, :lo12:.LCPI32_4]
+; CHECK-NEXT:    tbl v1.16b, { v3.16b, v4.16b }, v0.16b
+; CHECK-NEXT:    ldr q0, [x8, :lo12:.LCPI32_1]
+; CHECK-NEXT:    adrp x8, .LCPI32_3
+; CHECK-NEXT:    tbl v0.16b, { v1.16b, v2.16b }, v0.16b
+; CHECK-NEXT:    tbl v1.16b, { v3.16b, v4.16b }, v5.16b
+; CHECK-NEXT:    ldr q5, [x8, :lo12:.LCPI32_3]
+; CHECK-NEXT:    adrp x8, .LCPI32_5
+; CHECK-NEXT:    tbl v5.16b, { v1.16b, v2.16b }, v5.16b
+; CHECK-NEXT:    tbl v1.16b, { v3.16b, v4.16b }, v6.16b
+; CHECK-NEXT:    ldr q3, [x8, :lo12:.LCPI32_5]
+; CHECK-NEXT:    tbl v1.16b, { v1.16b, v2.16b }, v3.16b
+; CHECK-NEXT:    stp q5, q0, [x0, #16]
+; CHECK-NEXT:    str q1, [x0]
+; CHECK-NEXT:    stp q1, q5, [x1]
+; CHECK-NEXT:    str q0, [x1, #32]
+; CHECK-NEXT:    ret
+  %retval = call <24 x i16> @llvm.vector.interleave3.v24i16(<8 x i16> %vec0, <8 x i16> %vec1, <8 x i16> %vec2)
+  store <24 x i16> %retval, ptr %p
+  store <24 x i16> %retval, ptr %p0
+  ret void
+}
+
+define void @interleave3_v48i8(ptr %p, ptr %p0, <16 x i8> %vec0, <16 x i8> %vec1, <16 x i8> %vec2) {
+; CHECK-LABEL: interleave3_v48i8:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    // kill: def $q2 killed $q2 killed $q1_q2 def $q1_q2
+; CHECK-NEXT:    mov v4.16b, v1.16b
+; CHECK-NEXT:    adrp x8, .LCPI33_0
+; CHECK-NEXT:    adrp x9, .LCPI33_2
+; CHECK-NEXT:    mov v3.16b, v0.16b
+; CHECK-NEXT:    ldr q0, [x8, :lo12:.LCPI33_0]
+; CHECK-NEXT:    adrp x8, .LCPI33_1
+; CHECK-NEXT:    ldr q5, [x9, :lo12:.LCPI33_2]
+; CHECK-NEXT:    adrp x9, .LCPI33_4
+; CHECK-NEXT:    ldr q6, [x9, :lo12:.LCPI33_4]
+; CHECK-NEXT:    tbl v1.16b, { v3.16b, v4.16b }, v0.16b
+; CHECK-NEXT:    ldr q0, [x8, :lo12:.LCPI33_1]
+; CHECK-NEXT:    adrp x8, .LCPI33_3
+; CHECK-NEXT:    tbl v0.16b, { v1.16b, v2.16b }, v0.16b
+; CHECK-NEXT:    tbl v1.16b, { v3.16b, v4.16b }, v5.16b
+; CHECK-NEXT:    ldr q5, [x8, :lo12:.LCPI33_3]
+; CHECK-NEXT:    adrp x8, .LCPI33_5
+; CHECK-NEXT:    tbl v5.16b, { v1.16b, v2.16b }, v5.16b
+; CHECK-NEXT:    tbl v1.16b, { v3.16b, v4.16b }, v6.16b
+; CHECK-NEXT:    ldr q3, [x8, :lo12:.LCPI33_5]
+; CHECK-NEXT:    tbl v1.16b, { v1.16b, v2.16b }, v3.16b
+; CHECK-NEXT:    stp q5, q0, [x0, #16]
+; CHECK-NEXT:    str q1, [x0]
+; CHECK-NEXT:    stp q1, q5, [x1]
+; CHECK-NEXT:    str q0, [x1, #32]
+; CHECK-NEXT:    ret
+  %retval = call <48 x i8> @llvm.vector.interleave3.v48i8(<16 x i8> %vec0, <16 x i8> %vec1, <16 x i8> %vec2)
+  store <48 x i8> %retval, ptr %p
+  store <48 x i8> %retval, ptr %p0
+  ret void
+}

>From b336783e01d3aaf1b02bbd9361de8258747f73ec Mon Sep 17 00:00:00 2001
From: Matthew Devereau <matthew.devereau at arm.com>
Date: Tue, 14 Apr 2026 14:57:41 +0000
Subject: [PATCH 2/3] Add more comments and tests, fix bug

---
 .../Target/AArch64/AArch64ISelLowering.cpp    | 35 +++++---
 .../AArch64/fixed-vector-deinterleave.ll      |  4 +
 .../AArch64/fixed-vector-interleave.ll        | 90 ++++++++++++++++---
 3 files changed, 107 insertions(+), 22 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index ad5e935c2266a..62693e08ffe85 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -32322,30 +32322,45 @@ SDValue AArch64TargetLowering::LowerVECTOR_INTERLEAVE(SDValue Op,
     return DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, Op->getVTList(), Ops);
   }
 
+  // For v2f64 and v2i64, each vector part of the interleaved v6f64 vector can
+  // be made with one shuffle only, as the interleave factor is greater than the
+  // number of elements in the vector. a0, a1 | b0, b1 | c0, c1
+  //  ->
+  // a0, b0 | c0, a1 | b1, c1
   if (Op->getNumOperands() == 3 && (OpVT == MVT::v2f64 || OpVT == MVT::v2i64)) {
     SDValue A = Op->getOperand(0);
     SDValue B = Op->getOperand(1);
     SDValue C = Op->getOperand(2);
-
-    // a0, a1 | b0, b1 | c0, c1
-    //  ->
-    // a0, b0 | c0, a1 | b1, c1
     SDValue Shuffle0 = DAG.getVectorShuffle(OpVT, DL, A, B, {0, 2});
     SDValue Shuffle1 = DAG.getVectorShuffle(OpVT, DL, A, C, {2, 1});
     SDValue Shuffle2 = DAG.getVectorShuffle(OpVT, DL, B, C, {1, 3});
 
     return DAG.getMergeValues({Shuffle0, Shuffle1, Shuffle2}, DL);
   }
+
+  // When the interleave factor is less than the number of vector elements we
+  // need two shuffles to mix three vector's elements together:
+  //  step1: a0, b0, __, a1, | b1, __, a2, b2 | ...
+  //  step2: a0, b0, c0, a1  | b1, c1, a2, b2 | ...
   if (Op->getNumOperands() == 3 && OpVT.isFixedLengthVector()) {
     unsigned NElements = OpVT.getVectorNumElements();
     SDValue A = Op->getOperand(0);
     SDValue B = Op->getOperand(1);
     SDValue C = Op->getOperand(2);
-
-    //  Build two masks for two shuffles. The first mask shuffles elements from
-    //  A and B, and with elements of C represented with -1 so the shuffle
-    //  ignores them. The second shuffle then replaces -1 values with the actual
-    //  indices from C.
+    //  Build two masks for the two shuffles. The first mask shuffles elements
+    //  from A and B, and with elements of C represented with -1 to be ignored.
+    //  The second shuffle then replaces -1 values with the actual
+    //  indices from C like so:
+
+    //  0   1   2   3   4   5   6   7
+    // a0, a1, a2, a3, b0, b1, b2, b3
+    // t55: v4f32 = vector_shuffle<0,4,u,1> A, B
+    // t55 = a0, b0, -1, a1
+    //
+    //  0   1   2   3   4   5   6   7
+    // a0, b0, -1, a1, c0, c1, c2, c3
+    // t56: v4f32 = vector_shuffle<0,1,4,3> t55, C
+    // t56 = a0, b0, c1, a1
     SmallVector<int> ABMask;
     for (unsigned E = 0; E < NElements; E++) {
       for (unsigned F = 0; F < 3; F++) {
@@ -32362,7 +32377,7 @@ SDValue AArch64TargetLowering::LowerVECTOR_INTERLEAVE(SDValue Op,
         if (ABMask[F * NElements + E] == -1)
           ABCMask.push_back(NElements + Idx++);
         else
-          ABCMask.push_back(Idx);
+          ABCMask.push_back(E);
       }
     }
 
diff --git a/llvm/test/CodeGen/AArch64/fixed-vector-deinterleave.ll b/llvm/test/CodeGen/AArch64/fixed-vector-deinterleave.ll
index 24670ef2abd24..c1a6122de8f2f 100644
--- a/llvm/test/CodeGen/AArch64/fixed-vector-deinterleave.ll
+++ b/llvm/test/CodeGen/AArch64/fixed-vector-deinterleave.ll
@@ -392,3 +392,7 @@ define {<8 x bfloat>, <8 x bfloat>, <8 x bfloat>, <8 x bfloat>} @vector_deinterl
   ret {<8 x bfloat>, <8 x bfloat>, <8 x bfloat>, <8 x bfloat>} %retval
 }
 
+define {<4 x float>, <4 x float>, <4 x float>} @vector_deinterleave3_v4f32_v12f32(<12 x float> %vec) {
+  %retval = call {<4 x float>, <4 x float>, <4 x float>} @llvm.vector.deinterleave3.v12f32(<12 x float> %vec)
+  ret {<4 x float>, <4 x float>, <4 x float>} %retval
+}
\ No newline at end of file
diff --git a/llvm/test/CodeGen/AArch64/fixed-vector-interleave.ll b/llvm/test/CodeGen/AArch64/fixed-vector-interleave.ll
index 054173a5eabbb..6ce2a35cb6fba 100644
--- a/llvm/test/CodeGen/AArch64/fixed-vector-interleave.ll
+++ b/llvm/test/CodeGen/AArch64/fixed-vector-interleave.ll
@@ -480,18 +480,14 @@ define void @interleave3_v12f32(ptr %p, ptr %p0, <4 x float> %vec0, <4 x float>
 ; CHECK-NEXT:    ext v3.16b, v3.16b, v0.16b, #4
 ; CHECK-NEXT:    mov v4.d[1], v0.d[0]
 ; CHECK-NEXT:    uzp2 v0.4s, v1.4s, v5.4s
-; CHECK-NEXT:    zip2 v1.4s, v3.4s, v2.4s
-; CHECK-NEXT:    zip1 v5.4s, v4.4s, v2.4s
-; CHECK-NEXT:    zip1 v2.4s, v0.4s, v2.4s
-; CHECK-NEXT:    dup v0.4s, v0.s[2]
-; CHECK-NEXT:    ext v3.16b, v3.16b, v1.16b, #12
-; CHECK-NEXT:    zip1 v4.4s, v5.4s, v4.4s
-; CHECK-NEXT:    ext v0.16b, v2.16b, v0.16b, #8
-; CHECK-NEXT:    zip2 v1.4s, v3.4s, v1.4s
+; CHECK-NEXT:    mov v3.s[0], v2.s[2]
+; CHECK-NEXT:    mov v4.s[2], v2.s[0]
+; CHECK-NEXT:    mov v0.s[1], v2.s[1]
+; CHECK-NEXT:    mov v3.s[3], v2.s[3]
 ; CHECK-NEXT:    stp q4, q0, [x0]
-; CHECK-NEXT:    str q1, [x0, #32]
+; CHECK-NEXT:    str q3, [x0, #32]
 ; CHECK-NEXT:    stp q4, q0, [x1]
-; CHECK-NEXT:    str q1, [x1, #32]
+; CHECK-NEXT:    str q3, [x1, #32]
 ; CHECK-NEXT:    ret
   %retval = call <12 x float> @llvm.vector.interleave3.v12f32(<4 x float> %vec0, <4 x float> %vec1, <4 x float> %vec2)
   store <12 x float> %retval, ptr %p
@@ -534,8 +530,8 @@ define void @interleave3_v24i16(ptr %p, ptr %p0, <8 x i16> %vec0, <8 x i16> %vec
   ret void
 }
 
-define void @interleave3_v48i8(ptr %p, ptr %p0, <16 x i8> %vec0, <16 x i8> %vec1, <16 x i8> %vec2) {
-; CHECK-LABEL: interleave3_v48i8:
+define void @interleave3_v24f16(ptr %p, ptr %p0, <8 x half> %vec0, <8 x half> %vec1, <8 x half> %vec2) {
+; CHECK-LABEL: interleave3_v24f16:
 ; CHECK:       // %bb.0:
 ; CHECK-NEXT:    // kill: def $q2 killed $q2 killed $q1_q2 def $q1_q2
 ; CHECK-NEXT:    mov v4.16b, v1.16b
@@ -562,6 +558,76 @@ define void @interleave3_v48i8(ptr %p, ptr %p0, <16 x i8> %vec0, <16 x i8> %vec1
 ; CHECK-NEXT:    str q1, [x0]
 ; CHECK-NEXT:    stp q1, q5, [x1]
 ; CHECK-NEXT:    str q0, [x1, #32]
+; CHECK-NEXT:    ret
+  %retval = call <24 x half> @llvm.vector.interleave3.v24f16(<8 x half> %vec0, <8 x half> %vec1, <8 x half> %vec2)
+  store <24 x half> %retval, ptr %p
+  store <24 x half> %retval, ptr %p0
+  ret void
+}
+
+define void @interleave3_v24bf16(ptr %p, ptr %p0, <8 x bfloat> %vec0, <8 x bfloat> %vec1, <8 x bfloat> %vec2) {
+; CHECK-LABEL: interleave3_v24bf16:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    // kill: def $q2 killed $q2 killed $q1_q2 def $q1_q2
+; CHECK-NEXT:    mov v4.16b, v1.16b
+; CHECK-NEXT:    adrp x8, .LCPI34_0
+; CHECK-NEXT:    adrp x9, .LCPI34_2
+; CHECK-NEXT:    mov v3.16b, v0.16b
+; CHECK-NEXT:    ldr q0, [x8, :lo12:.LCPI34_0]
+; CHECK-NEXT:    adrp x8, .LCPI34_1
+; CHECK-NEXT:    ldr q5, [x9, :lo12:.LCPI34_2]
+; CHECK-NEXT:    adrp x9, .LCPI34_4
+; CHECK-NEXT:    ldr q6, [x9, :lo12:.LCPI34_4]
+; CHECK-NEXT:    tbl v1.16b, { v3.16b, v4.16b }, v0.16b
+; CHECK-NEXT:    ldr q0, [x8, :lo12:.LCPI34_1]
+; CHECK-NEXT:    adrp x8, .LCPI34_3
+; CHECK-NEXT:    tbl v0.16b, { v1.16b, v2.16b }, v0.16b
+; CHECK-NEXT:    tbl v1.16b, { v3.16b, v4.16b }, v5.16b
+; CHECK-NEXT:    ldr q5, [x8, :lo12:.LCPI34_3]
+; CHECK-NEXT:    adrp x8, .LCPI34_5
+; CHECK-NEXT:    tbl v5.16b, { v1.16b, v2.16b }, v5.16b
+; CHECK-NEXT:    tbl v1.16b, { v3.16b, v4.16b }, v6.16b
+; CHECK-NEXT:    ldr q3, [x8, :lo12:.LCPI34_5]
+; CHECK-NEXT:    tbl v1.16b, { v1.16b, v2.16b }, v3.16b
+; CHECK-NEXT:    stp q5, q0, [x0, #16]
+; CHECK-NEXT:    str q1, [x0]
+; CHECK-NEXT:    stp q1, q5, [x1]
+; CHECK-NEXT:    str q0, [x1, #32]
+; CHECK-NEXT:    ret
+  %retval = call <24 x bfloat> @llvm.vector.interleave3.v24bf16(<8 x bfloat> %vec0, <8 x bfloat> %vec1, <8 x bfloat> %vec2)
+  store <24 x bfloat> %retval, ptr %p
+  store <24 x bfloat> %retval, ptr %p0
+  ret void
+}
+
+define void @interleave3_v48i8(ptr %p, ptr %p0, <16 x i8> %vec0, <16 x i8> %vec1, <16 x i8> %vec2) {
+; CHECK-LABEL: interleave3_v48i8:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    // kill: def $q2 killed $q2 killed $q1_q2 def $q1_q2
+; CHECK-NEXT:    mov v4.16b, v1.16b
+; CHECK-NEXT:    adrp x8, .LCPI35_0
+; CHECK-NEXT:    adrp x9, .LCPI35_2
+; CHECK-NEXT:    mov v3.16b, v0.16b
+; CHECK-NEXT:    ldr q0, [x8, :lo12:.LCPI35_0]
+; CHECK-NEXT:    adrp x8, .LCPI35_1
+; CHECK-NEXT:    ldr q5, [x9, :lo12:.LCPI35_2]
+; CHECK-NEXT:    adrp x9, .LCPI35_4
+; CHECK-NEXT:    ldr q6, [x9, :lo12:.LCPI35_4]
+; CHECK-NEXT:    tbl v1.16b, { v3.16b, v4.16b }, v0.16b
+; CHECK-NEXT:    ldr q0, [x8, :lo12:.LCPI35_1]
+; CHECK-NEXT:    adrp x8, .LCPI35_3
+; CHECK-NEXT:    tbl v0.16b, { v1.16b, v2.16b }, v0.16b
+; CHECK-NEXT:    tbl v1.16b, { v3.16b, v4.16b }, v5.16b
+; CHECK-NEXT:    ldr q5, [x8, :lo12:.LCPI35_3]
+; CHECK-NEXT:    adrp x8, .LCPI35_5
+; CHECK-NEXT:    tbl v5.16b, { v1.16b, v2.16b }, v5.16b
+; CHECK-NEXT:    tbl v1.16b, { v3.16b, v4.16b }, v6.16b
+; CHECK-NEXT:    ldr q3, [x8, :lo12:.LCPI35_5]
+; CHECK-NEXT:    tbl v1.16b, { v1.16b, v2.16b }, v3.16b
+; CHECK-NEXT:    stp q5, q0, [x0, #16]
+; CHECK-NEXT:    str q1, [x0]
+; CHECK-NEXT:    stp q1, q5, [x1]
+; CHECK-NEXT:    str q0, [x1, #32]
 ; CHECK-NEXT:    ret
   %retval = call <48 x i8> @llvm.vector.interleave3.v48i8(<16 x i8> %vec0, <16 x i8> %vec1, <16 x i8> %vec2)
   store <48 x i8> %retval, ptr %p

>From 6c891301dcd9b6a416c2fa85e23a49083baa5a8c Mon Sep 17 00:00:00 2001
From: Matthew Devereau <matthew.devereau at arm.com>
Date: Tue, 14 Apr 2026 15:47:19 +0000
Subject: [PATCH 3/3] Remove deinterleave test changes

---
 llvm/test/CodeGen/AArch64/fixed-vector-deinterleave.ll | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/llvm/test/CodeGen/AArch64/fixed-vector-deinterleave.ll b/llvm/test/CodeGen/AArch64/fixed-vector-deinterleave.ll
index c1a6122de8f2f..24670ef2abd24 100644
--- a/llvm/test/CodeGen/AArch64/fixed-vector-deinterleave.ll
+++ b/llvm/test/CodeGen/AArch64/fixed-vector-deinterleave.ll
@@ -392,7 +392,3 @@ define {<8 x bfloat>, <8 x bfloat>, <8 x bfloat>, <8 x bfloat>} @vector_deinterl
   ret {<8 x bfloat>, <8 x bfloat>, <8 x bfloat>, <8 x bfloat>} %retval
 }
 
-define {<4 x float>, <4 x float>, <4 x float>} @vector_deinterleave3_v4f32_v12f32(<12 x float> %vec) {
-  %retval = call {<4 x float>, <4 x float>, <4 x float>} @llvm.vector.deinterleave3.v12f32(<12 x float> %vec)
-  ret {<4 x float>, <4 x float>, <4 x float>} %retval
-}
\ No newline at end of file



More information about the llvm-commits mailing list