[llvm] [VectorCombine][AArch64] Fold interleave of reversed deinterleave (PR #216308)

Kamlesh Kumar via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 21 05:22:04 PDT 2026


https://github.com/kamleshbhalui updated https://github.com/llvm/llvm-project/pull/216308

>From b632258744fca28eace6a5ab124bc71c3dade274 Mon Sep 17 00:00:00 2001
From: Kamlesh Kumar <kamlesh.kumar at arm.com>
Date: Fri, 14 Aug 2026 11:38:01 +0100
Subject: [PATCH 1/3] add test

---
 .../interleave-reverse-deinterleave.ll        | 322 ++++++++++++++++++
 1 file changed, 322 insertions(+)
 create mode 100644 llvm/test/Transforms/VectorCombine/AArch64/interleave-reverse-deinterleave.ll

diff --git a/llvm/test/Transforms/VectorCombine/AArch64/interleave-reverse-deinterleave.ll b/llvm/test/Transforms/VectorCombine/AArch64/interleave-reverse-deinterleave.ll
new file mode 100644
index 0000000000000..d0db7530aa9da
--- /dev/null
+++ b/llvm/test/Transforms/VectorCombine/AArch64/interleave-reverse-deinterleave.ll
@@ -0,0 +1,322 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -mtriple=aarch64-linux-gnu -passes=vector-combine -S %s | FileCheck %s
+
+define <24 x i16> @reverse_interleave3(<24 x i16> %x) {
+; CHECK-LABEL: define <24 x i16> @reverse_interleave3(
+; CHECK-SAME: <24 x i16> [[X:%.*]]) {
+; CHECK-NEXT:    [[DEINTERLEAVE:%.*]] = call { <8 x i16>, <8 x i16>, <8 x i16> } @llvm.vector.deinterleave3.v24i16(<24 x i16> [[X]])
+; CHECK-NEXT:    [[E0:%.*]] = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } [[DEINTERLEAVE]], 0
+; CHECK-NEXT:    [[E1:%.*]] = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } [[DEINTERLEAVE]], 1
+; CHECK-NEXT:    [[E2:%.*]] = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } [[DEINTERLEAVE]], 2
+; CHECK-NEXT:    [[R0:%.*]] = shufflevector <8 x i16> [[E0]], <8 x i16> poison, <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
+; CHECK-NEXT:    [[R1:%.*]] = shufflevector <8 x i16> [[E1]], <8 x i16> poison, <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
+; CHECK-NEXT:    [[R2:%.*]] = shufflevector <8 x i16> [[E2]], <8 x i16> poison, <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
+; CHECK-NEXT:    [[INTERLEAVE:%.*]] = call <24 x i16> @llvm.vector.interleave3.v24i16(<8 x i16> [[R2]], <8 x i16> [[R1]], <8 x i16> [[R0]])
+; CHECK-NEXT:    ret <24 x i16> [[INTERLEAVE]]
+;
+  %deinterleave = call { <8 x i16>, <8 x i16>, <8 x i16> } @llvm.vector.deinterleave3(<24 x i16> %x)
+  %e0 = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } %deinterleave, 0
+  %e1 = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } %deinterleave, 1
+  %e2 = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } %deinterleave, 2
+  %r0 = shufflevector <8 x i16> %e0, <8 x i16> poison, <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
+  %r1 = shufflevector <8 x i16> %e1, <8 x i16> poison, <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
+  %r2 = shufflevector <8 x i16> %e2, <8 x i16> poison, <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
+  %interleave = call <24 x i16> @llvm.vector.interleave3(<8 x i16> %r2, <8 x i16> %r1, <8 x i16> %r0)
+  ret <24 x i16> %interleave
+}
+
+define <24 x i16> @reverse_intrinsic_interleave3(<24 x i16> %x) {
+; CHECK-LABEL: define <24 x i16> @reverse_intrinsic_interleave3(
+; CHECK-SAME: <24 x i16> [[X:%.*]]) {
+; CHECK-NEXT:    [[DEINTERLEAVE:%.*]] = call { <8 x i16>, <8 x i16>, <8 x i16> } @llvm.vector.deinterleave3.v24i16(<24 x i16> [[X]])
+; CHECK-NEXT:    [[E0:%.*]] = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } [[DEINTERLEAVE]], 0
+; CHECK-NEXT:    [[E1:%.*]] = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } [[DEINTERLEAVE]], 1
+; CHECK-NEXT:    [[E2:%.*]] = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } [[DEINTERLEAVE]], 2
+; CHECK-NEXT:    [[R0:%.*]] = call <8 x i16> @llvm.vector.reverse.v8i16(<8 x i16> [[E0]])
+; CHECK-NEXT:    [[R1:%.*]] = call <8 x i16> @llvm.vector.reverse.v8i16(<8 x i16> [[E1]])
+; CHECK-NEXT:    [[R2:%.*]] = call <8 x i16> @llvm.vector.reverse.v8i16(<8 x i16> [[E2]])
+; CHECK-NEXT:    [[INTERLEAVE:%.*]] = call <24 x i16> @llvm.vector.interleave3.v24i16(<8 x i16> [[R2]], <8 x i16> [[R1]], <8 x i16> [[R0]])
+; CHECK-NEXT:    ret <24 x i16> [[INTERLEAVE]]
+;
+  %deinterleave = call { <8 x i16>, <8 x i16>, <8 x i16> } @llvm.vector.deinterleave3(<24 x i16> %x)
+  %e0 = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } %deinterleave, 0
+  %e1 = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } %deinterleave, 1
+  %e2 = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } %deinterleave, 2
+  %r0 = call <8 x i16> @llvm.vector.reverse(<8 x i16> %e0)
+  %r1 = call <8 x i16> @llvm.vector.reverse(<8 x i16> %e1)
+  %r2 = call <8 x i16> @llvm.vector.reverse(<8 x i16> %e2)
+  %interleave = call <24 x i16> @llvm.vector.interleave3(<8 x i16> %r2, <8 x i16> %r1, <8 x i16> %r0)
+  ret <24 x i16> %interleave
+}
+
+define <vscale x 24 x i16> @reverse_intrinsic_interleave3_scalable(<vscale x 24 x i16> %x) {
+; CHECK-LABEL: define <vscale x 24 x i16> @reverse_intrinsic_interleave3_scalable(
+; CHECK-SAME: <vscale x 24 x i16> [[X:%.*]]) {
+; CHECK-NEXT:    [[DEINTERLEAVE:%.*]] = call { <vscale x 8 x i16>, <vscale x 8 x i16>, <vscale x 8 x i16> } @llvm.vector.deinterleave3.nxv24i16(<vscale x 24 x i16> [[X]])
+; CHECK-NEXT:    [[E0:%.*]] = extractvalue { <vscale x 8 x i16>, <vscale x 8 x i16>, <vscale x 8 x i16> } [[DEINTERLEAVE]], 0
+; CHECK-NEXT:    [[E1:%.*]] = extractvalue { <vscale x 8 x i16>, <vscale x 8 x i16>, <vscale x 8 x i16> } [[DEINTERLEAVE]], 1
+; CHECK-NEXT:    [[E2:%.*]] = extractvalue { <vscale x 8 x i16>, <vscale x 8 x i16>, <vscale x 8 x i16> } [[DEINTERLEAVE]], 2
+; CHECK-NEXT:    [[R0:%.*]] = call <vscale x 8 x i16> @llvm.vector.reverse.nxv8i16(<vscale x 8 x i16> [[E0]])
+; CHECK-NEXT:    [[R1:%.*]] = call <vscale x 8 x i16> @llvm.vector.reverse.nxv8i16(<vscale x 8 x i16> [[E1]])
+; CHECK-NEXT:    [[R2:%.*]] = call <vscale x 8 x i16> @llvm.vector.reverse.nxv8i16(<vscale x 8 x i16> [[E2]])
+; CHECK-NEXT:    [[INTERLEAVE:%.*]] = call <vscale x 24 x i16> @llvm.vector.interleave3.nxv24i16(<vscale x 8 x i16> [[R2]], <vscale x 8 x i16> [[R1]], <vscale x 8 x i16> [[R0]])
+; CHECK-NEXT:    ret <vscale x 24 x i16> [[INTERLEAVE]]
+;
+  %deinterleave = call { <vscale x 8 x i16>, <vscale x 8 x i16>, <vscale x 8 x i16> } @llvm.vector.deinterleave3(<vscale x 24 x i16> %x)
+  %e0 = extractvalue { <vscale x 8 x i16>, <vscale x 8 x i16>, <vscale x 8 x i16> } %deinterleave, 0
+  %e1 = extractvalue { <vscale x 8 x i16>, <vscale x 8 x i16>, <vscale x 8 x i16> } %deinterleave, 1
+  %e2 = extractvalue { <vscale x 8 x i16>, <vscale x 8 x i16>, <vscale x 8 x i16> } %deinterleave, 2
+  %r0 = call <vscale x 8 x i16> @llvm.vector.reverse(<vscale x 8 x i16> %e0)
+  %r1 = call <vscale x 8 x i16> @llvm.vector.reverse(<vscale x 8 x i16> %e1)
+  %r2 = call <vscale x 8 x i16> @llvm.vector.reverse(<vscale x 8 x i16> %e2)
+  %interleave = call <vscale x 24 x i16> @llvm.vector.interleave3(<vscale x 8 x i16> %r2, <vscale x 8 x i16> %r1, <vscale x 8 x i16> %r0)
+  ret <vscale x 24 x i16> %interleave
+}
+
+define <24 x i16> @group_reverse_interleave3(<24 x i16> %x) {
+; CHECK-LABEL: define <24 x i16> @group_reverse_interleave3(
+; CHECK-SAME: <24 x i16> [[X:%.*]]) {
+; CHECK-NEXT:    [[DEINTERLEAVE:%.*]] = call { <8 x i16>, <8 x i16>, <8 x i16> } @llvm.vector.deinterleave3.v24i16(<24 x i16> [[X]])
+; CHECK-NEXT:    [[E0:%.*]] = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } [[DEINTERLEAVE]], 0
+; CHECK-NEXT:    [[E1:%.*]] = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } [[DEINTERLEAVE]], 1
+; CHECK-NEXT:    [[E2:%.*]] = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } [[DEINTERLEAVE]], 2
+; CHECK-NEXT:    [[R0:%.*]] = shufflevector <8 x i16> [[E0]], <8 x i16> poison, <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
+; CHECK-NEXT:    [[R1:%.*]] = shufflevector <8 x i16> [[E1]], <8 x i16> poison, <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
+; CHECK-NEXT:    [[R2:%.*]] = shufflevector <8 x i16> [[E2]], <8 x i16> poison, <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
+; CHECK-NEXT:    [[INTERLEAVE:%.*]] = call <24 x i16> @llvm.vector.interleave3.v24i16(<8 x i16> [[R0]], <8 x i16> [[R1]], <8 x i16> [[R2]])
+; CHECK-NEXT:    ret <24 x i16> [[INTERLEAVE]]
+;
+  %deinterleave = call { <8 x i16>, <8 x i16>, <8 x i16> } @llvm.vector.deinterleave3(<24 x i16> %x)
+  %e0 = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } %deinterleave, 0
+  %e1 = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } %deinterleave, 1
+  %e2 = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } %deinterleave, 2
+  %r0 = shufflevector <8 x i16> %e0, <8 x i16> poison, <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
+  %r1 = shufflevector <8 x i16> %e1, <8 x i16> poison, <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
+  %r2 = shufflevector <8 x i16> %e2, <8 x i16> poison, <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
+  %interleave = call <24 x i16> @llvm.vector.interleave3(<8 x i16> %r0, <8 x i16> %r1, <8 x i16> %r2)
+  ret <24 x i16> %interleave
+}
+
+define <6 x i16> @reverse_second_operand_interleave2(<6 x i16> %x) {
+; CHECK-LABEL: define <6 x i16> @reverse_second_operand_interleave2(
+; CHECK-SAME: <6 x i16> [[X:%.*]]) {
+; CHECK-NEXT:    [[DEINTERLEAVE:%.*]] = call { <3 x i16>, <3 x i16> } @llvm.vector.deinterleave2.v6i16(<6 x i16> [[X]])
+; CHECK-NEXT:    [[E0:%.*]] = extractvalue { <3 x i16>, <3 x i16> } [[DEINTERLEAVE]], 0
+; CHECK-NEXT:    [[E1:%.*]] = extractvalue { <3 x i16>, <3 x i16> } [[DEINTERLEAVE]], 1
+; CHECK-NEXT:    [[R0:%.*]] = shufflevector <3 x i16> [[E0]], <3 x i16> zeroinitializer, <3 x i32> <i32 5, i32 4, i32 3>
+; CHECK-NEXT:    [[R1:%.*]] = shufflevector <3 x i16> [[E1]], <3 x i16> zeroinitializer, <3 x i32> <i32 5, i32 4, i32 3>
+; CHECK-NEXT:    [[INTERLEAVE:%.*]] = call <6 x i16> @llvm.vector.interleave2.v6i16(<3 x i16> [[R1]], <3 x i16> [[R0]])
+; CHECK-NEXT:    ret <6 x i16> [[INTERLEAVE]]
+;
+  %deinterleave = call { <3 x i16>, <3 x i16> } @llvm.vector.deinterleave2(<6 x i16> %x)
+  %e0 = extractvalue { <3 x i16>, <3 x i16> } %deinterleave, 0
+  %e1 = extractvalue { <3 x i16>, <3 x i16> } %deinterleave, 1
+  %r0 = shufflevector <3 x i16> %e0, <3 x i16> zeroinitializer, <3 x i32> <i32 5, i32 4, i32 3>
+  %r1 = shufflevector <3 x i16> %e1, <3 x i16> zeroinitializer, <3 x i32> <i32 5, i32 4, i32 3>
+  %interleave = call <6 x i16> @llvm.vector.interleave2(<3 x i16> %r1, <3 x i16> %r0)
+  ret <6 x i16> %interleave
+}
+
+define <6 x i16> @reverse_poison_mask_interleave2(<6 x i16> %x) {
+; CHECK-LABEL: define <6 x i16> @reverse_poison_mask_interleave2(
+; CHECK-SAME: <6 x i16> [[X:%.*]]) {
+; CHECK-NEXT:    [[DEINTERLEAVE:%.*]] = call { <3 x i16>, <3 x i16> } @llvm.vector.deinterleave2.v6i16(<6 x i16> [[X]])
+; CHECK-NEXT:    [[E0:%.*]] = extractvalue { <3 x i16>, <3 x i16> } [[DEINTERLEAVE]], 0
+; CHECK-NEXT:    [[E1:%.*]] = extractvalue { <3 x i16>, <3 x i16> } [[DEINTERLEAVE]], 1
+; CHECK-NEXT:    [[R0:%.*]] = shufflevector <3 x i16> [[E0]], <3 x i16> poison, <3 x i32> <i32 2, i32 poison, i32 0>
+; CHECK-NEXT:    [[R1:%.*]] = shufflevector <3 x i16> [[E1]], <3 x i16> poison, <3 x i32> <i32 2, i32 1, i32 poison>
+; CHECK-NEXT:    [[INTERLEAVE:%.*]] = call <6 x i16> @llvm.vector.interleave2.v6i16(<3 x i16> [[R1]], <3 x i16> [[R0]])
+; CHECK-NEXT:    ret <6 x i16> [[INTERLEAVE]]
+;
+  %deinterleave = call { <3 x i16>, <3 x i16> } @llvm.vector.deinterleave2(<6 x i16> %x)
+  %e0 = extractvalue { <3 x i16>, <3 x i16> } %deinterleave, 0
+  %e1 = extractvalue { <3 x i16>, <3 x i16> } %deinterleave, 1
+  %r0 = shufflevector <3 x i16> %e0, <3 x i16> poison, <3 x i32> <i32 2, i32 poison, i32 0>
+  %r1 = shufflevector <3 x i16> %e1, <3 x i16> poison, <3 x i32> <i32 2, i32 1, i32 poison>
+  %interleave = call <6 x i16> @llvm.vector.interleave2(<3 x i16> %r1, <3 x i16> %r0)
+  ret <6 x i16> %interleave
+}
+
+define <16 x i16> @reverse_interleave4(<16 x i16> %x) {
+; CHECK-LABEL: define <16 x i16> @reverse_interleave4(
+; CHECK-SAME: <16 x i16> [[X:%.*]]) {
+; CHECK-NEXT:    [[DEINTERLEAVE:%.*]] = call { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } @llvm.vector.deinterleave4.v16i16(<16 x i16> [[X]])
+; CHECK-NEXT:    [[E0:%.*]] = extractvalue { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } [[DEINTERLEAVE]], 0
+; CHECK-NEXT:    [[E1:%.*]] = extractvalue { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } [[DEINTERLEAVE]], 1
+; CHECK-NEXT:    [[E2:%.*]] = extractvalue { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } [[DEINTERLEAVE]], 2
+; CHECK-NEXT:    [[E3:%.*]] = extractvalue { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } [[DEINTERLEAVE]], 3
+; CHECK-NEXT:    [[R0:%.*]] = shufflevector <4 x i16> [[E0]], <4 x i16> poison, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
+; CHECK-NEXT:    [[R1:%.*]] = shufflevector <4 x i16> [[E1]], <4 x i16> poison, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
+; CHECK-NEXT:    [[R2:%.*]] = shufflevector <4 x i16> [[E2]], <4 x i16> poison, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
+; CHECK-NEXT:    [[R3:%.*]] = shufflevector <4 x i16> [[E3]], <4 x i16> poison, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
+; CHECK-NEXT:    [[INTERLEAVE:%.*]] = call <16 x i16> @llvm.vector.interleave4.v16i16(<4 x i16> [[R3]], <4 x i16> [[R2]], <4 x i16> [[R1]], <4 x i16> [[R0]])
+; CHECK-NEXT:    ret <16 x i16> [[INTERLEAVE]]
+;
+  %deinterleave = call { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } @llvm.vector.deinterleave4(<16 x i16> %x)
+  %e0 = extractvalue { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } %deinterleave, 0
+  %e1 = extractvalue { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } %deinterleave, 1
+  %e2 = extractvalue { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } %deinterleave, 2
+  %e3 = extractvalue { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } %deinterleave, 3
+  %r0 = shufflevector <4 x i16> %e0, <4 x i16> poison, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
+  %r1 = shufflevector <4 x i16> %e1, <4 x i16> poison, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
+  %r2 = shufflevector <4 x i16> %e2, <4 x i16> poison, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
+  %r3 = shufflevector <4 x i16> %e3, <4 x i16> poison, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
+  %interleave = call <16 x i16> @llvm.vector.interleave4(<4 x i16> %r3, <4 x i16> %r2, <4 x i16> %r1, <4 x i16> %r0)
+  ret <16 x i16> %interleave
+}
+
+define <24 x i16> @mixed_reverse_interleave3(<24 x i16> %x) {
+; CHECK-LABEL: define <24 x i16> @mixed_reverse_interleave3(
+; CHECK-SAME: <24 x i16> [[X:%.*]]) {
+; CHECK-NEXT:    [[DEINTERLEAVE:%.*]] = call { <8 x i16>, <8 x i16>, <8 x i16> } @llvm.vector.deinterleave3.v24i16(<24 x i16> [[X]])
+; CHECK-NEXT:    [[E0:%.*]] = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } [[DEINTERLEAVE]], 0
+; CHECK-NEXT:    [[E1:%.*]] = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } [[DEINTERLEAVE]], 1
+; CHECK-NEXT:    [[E2:%.*]] = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } [[DEINTERLEAVE]], 2
+; CHECK-NEXT:    [[R0:%.*]] = shufflevector <8 x i16> [[E0]], <8 x i16> poison, <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
+; CHECK-NEXT:    [[R1:%.*]] = call <8 x i16> @llvm.vector.reverse.v8i16(<8 x i16> [[E1]])
+; CHECK-NEXT:    [[R2:%.*]] = shufflevector <8 x i16> [[E2]], <8 x i16> poison, <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
+; CHECK-NEXT:    [[INTERLEAVE:%.*]] = call <24 x i16> @llvm.vector.interleave3.v24i16(<8 x i16> [[R2]], <8 x i16> [[R1]], <8 x i16> [[R0]])
+; CHECK-NEXT:    ret <24 x i16> [[INTERLEAVE]]
+;
+  %deinterleave = call { <8 x i16>, <8 x i16>, <8 x i16> } @llvm.vector.deinterleave3(<24 x i16> %x)
+  %e0 = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } %deinterleave, 0
+  %e1 = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } %deinterleave, 1
+  %e2 = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } %deinterleave, 2
+  %r0 = shufflevector <8 x i16> %e0, <8 x i16> poison, <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
+  %r1 = call <8 x i16> @llvm.vector.reverse(<8 x i16> %e1)
+  %r2 = shufflevector <8 x i16> %e2, <8 x i16> poison, <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
+  %interleave = call <24 x i16> @llvm.vector.interleave3(<8 x i16> %r2, <8 x i16> %r1, <8 x i16> %r0)
+  ret <24 x i16> %interleave
+}
+
+define <8 x i16> @narrowing_shuffle_interleave2(<16 x i16> %x) {
+; CHECK-LABEL: define <8 x i16> @narrowing_shuffle_interleave2(
+; CHECK-SAME: <16 x i16> [[X:%.*]]) {
+; CHECK-NEXT:    [[DEINTERLEAVE:%.*]] = call { <8 x i16>, <8 x i16> } @llvm.vector.deinterleave2.v16i16(<16 x i16> [[X]])
+; CHECK-NEXT:    [[E0:%.*]] = extractvalue { <8 x i16>, <8 x i16> } [[DEINTERLEAVE]], 0
+; CHECK-NEXT:    [[E1:%.*]] = extractvalue { <8 x i16>, <8 x i16> } [[DEINTERLEAVE]], 1
+; CHECK-NEXT:    [[R0:%.*]] = shufflevector <8 x i16> [[E0]], <8 x i16> poison, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
+; CHECK-NEXT:    [[R1:%.*]] = shufflevector <8 x i16> [[E1]], <8 x i16> poison, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
+; CHECK-NEXT:    [[INTERLEAVE:%.*]] = call <8 x i16> @llvm.vector.interleave2.v8i16(<4 x i16> [[R1]], <4 x i16> [[R0]])
+; CHECK-NEXT:    ret <8 x i16> [[INTERLEAVE]]
+;
+  %deinterleave = call { <8 x i16>, <8 x i16> } @llvm.vector.deinterleave2(<16 x i16> %x)
+  %e0 = extractvalue { <8 x i16>, <8 x i16> } %deinterleave, 0
+  %e1 = extractvalue { <8 x i16>, <8 x i16> } %deinterleave, 1
+  %r0 = shufflevector <8 x i16> %e0, <8 x i16> poison, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
+  %r1 = shufflevector <8 x i16> %e1, <8 x i16> poison, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
+  %interleave = call <8 x i16> @llvm.vector.interleave2(<4 x i16> %r1, <4 x i16> %r0)
+  ret <8 x i16> %interleave
+}
+
+define <16 x i16> @widening_shuffle_interleave2(<8 x i16> %x) {
+; CHECK-LABEL: define <16 x i16> @widening_shuffle_interleave2(
+; CHECK-SAME: <8 x i16> [[X:%.*]]) {
+; CHECK-NEXT:    [[DEINTERLEAVE:%.*]] = call { <4 x i16>, <4 x i16> } @llvm.vector.deinterleave2.v8i16(<8 x i16> [[X]])
+; CHECK-NEXT:    [[E0:%.*]] = extractvalue { <4 x i16>, <4 x i16> } [[DEINTERLEAVE]], 0
+; CHECK-NEXT:    [[E1:%.*]] = extractvalue { <4 x i16>, <4 x i16> } [[DEINTERLEAVE]], 1
+; CHECK-NEXT:    [[R0:%.*]] = shufflevector <4 x i16> [[E0]], <4 x i16> poison, <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
+; CHECK-NEXT:    [[R1:%.*]] = shufflevector <4 x i16> [[E1]], <4 x i16> poison, <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
+; CHECK-NEXT:    [[INTERLEAVE:%.*]] = call <16 x i16> @llvm.vector.interleave2.v16i16(<8 x i16> [[R1]], <8 x i16> [[R0]])
+; CHECK-NEXT:    ret <16 x i16> [[INTERLEAVE]]
+;
+  %deinterleave = call { <4 x i16>, <4 x i16> } @llvm.vector.deinterleave2(<8 x i16> %x)
+  %e0 = extractvalue { <4 x i16>, <4 x i16> } %deinterleave, 0
+  %e1 = extractvalue { <4 x i16>, <4 x i16> } %deinterleave, 1
+  %r0 = shufflevector <4 x i16> %e0, <4 x i16> poison, <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
+  %r1 = shufflevector <4 x i16> %e1, <4 x i16> poison, <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
+  %interleave = call <16 x i16> @llvm.vector.interleave2(<8 x i16> %r1, <8 x i16> %r0)
+  ret <16 x i16> %interleave
+}
+
+define <8 x i16> @multi_use_reverse_interleave2(<8 x i16> %x) {
+; CHECK-LABEL: define <8 x i16> @multi_use_reverse_interleave2(
+; CHECK-SAME: <8 x i16> [[X:%.*]]) {
+; CHECK-NEXT:    [[DEINTERLEAVE:%.*]] = call { <4 x i16>, <4 x i16> } @llvm.vector.deinterleave2.v8i16(<8 x i16> [[X]])
+; CHECK-NEXT:    [[E0:%.*]] = extractvalue { <4 x i16>, <4 x i16> } [[DEINTERLEAVE]], 0
+; CHECK-NEXT:    [[E1:%.*]] = extractvalue { <4 x i16>, <4 x i16> } [[DEINTERLEAVE]], 1
+; CHECK-NEXT:    [[R0:%.*]] = call <4 x i16> @llvm.vector.reverse.v4i16(<4 x i16> [[E0]])
+; CHECK-NEXT:    [[R1:%.*]] = call <4 x i16> @llvm.vector.reverse.v4i16(<4 x i16> [[E1]])
+; CHECK-NEXT:    call void (...) @llvm.fake.use(<4 x i16> [[R0]])
+; CHECK-NEXT:    [[INTERLEAVE:%.*]] = call <8 x i16> @llvm.vector.interleave2.v8i16(<4 x i16> [[R1]], <4 x i16> [[R0]])
+; CHECK-NEXT:    ret <8 x i16> [[INTERLEAVE]]
+;
+  %deinterleave = call { <4 x i16>, <4 x i16> } @llvm.vector.deinterleave2(<8 x i16> %x)
+  %e0 = extractvalue { <4 x i16>, <4 x i16> } %deinterleave, 0
+  %e1 = extractvalue { <4 x i16>, <4 x i16> } %deinterleave, 1
+  %r0 = call <4 x i16> @llvm.vector.reverse(<4 x i16> %e0)
+  %r1 = call <4 x i16> @llvm.vector.reverse(<4 x i16> %e1)
+  call void (...) @llvm.fake.use(<4 x i16> %r0)
+  %interleave = call <8 x i16> @llvm.vector.interleave2(<4 x i16> %r1, <4 x i16> %r0)
+  ret <8 x i16> %interleave
+}
+
+define <8 x i16> @extra_extract_use_interleave2(<8 x i16> %x) {
+; CHECK-LABEL: define <8 x i16> @extra_extract_use_interleave2(
+; CHECK-SAME: <8 x i16> [[X:%.*]]) {
+; CHECK-NEXT:    [[DEINTERLEAVE:%.*]] = call { <4 x i16>, <4 x i16> } @llvm.vector.deinterleave2.v8i16(<8 x i16> [[X]])
+; CHECK-NEXT:    [[E0:%.*]] = extractvalue { <4 x i16>, <4 x i16> } [[DEINTERLEAVE]], 0
+; CHECK-NEXT:    [[E1:%.*]] = extractvalue { <4 x i16>, <4 x i16> } [[DEINTERLEAVE]], 1
+; CHECK-NEXT:    [[EXTRA:%.*]] = extractvalue { <4 x i16>, <4 x i16> } [[DEINTERLEAVE]], 0
+; CHECK-NEXT:    call void (...) @llvm.fake.use(<4 x i16> [[EXTRA]])
+; CHECK-NEXT:    [[R0:%.*]] = call <4 x i16> @llvm.vector.reverse.v4i16(<4 x i16> [[E0]])
+; CHECK-NEXT:    [[R1:%.*]] = call <4 x i16> @llvm.vector.reverse.v4i16(<4 x i16> [[E1]])
+; CHECK-NEXT:    [[INTERLEAVE:%.*]] = call <8 x i16> @llvm.vector.interleave2.v8i16(<4 x i16> [[R1]], <4 x i16> [[R0]])
+; CHECK-NEXT:    ret <8 x i16> [[INTERLEAVE]]
+;
+  %deinterleave = call { <4 x i16>, <4 x i16> } @llvm.vector.deinterleave2(<8 x i16> %x)
+  %e0 = extractvalue { <4 x i16>, <4 x i16> } %deinterleave, 0
+  %e1 = extractvalue { <4 x i16>, <4 x i16> } %deinterleave, 1
+  %extra = extractvalue { <4 x i16>, <4 x i16> } %deinterleave, 0
+  call void (...) @llvm.fake.use(<4 x i16> %extra)
+  %r0 = call <4 x i16> @llvm.vector.reverse(<4 x i16> %e0)
+  %r1 = call <4 x i16> @llvm.vector.reverse(<4 x i16> %e1)
+  %interleave = call <8 x i16> @llvm.vector.interleave2(<4 x i16> %r1, <4 x i16> %r0)
+  ret <8 x i16> %interleave
+}
+
+define <8 x i16> @two_deinterleaves_interleave2(<8 x i16> %x, <8 x i16> %y) {
+; CHECK-LABEL: define <8 x i16> @two_deinterleaves_interleave2(
+; CHECK-SAME: <8 x i16> [[X:%.*]], <8 x i16> [[Y:%.*]]) {
+; CHECK-NEXT:    [[D0:%.*]] = call { <4 x i16>, <4 x i16> } @llvm.vector.deinterleave2.v8i16(<8 x i16> [[X]])
+; CHECK-NEXT:    [[D1:%.*]] = call { <4 x i16>, <4 x i16> } @llvm.vector.deinterleave2.v8i16(<8 x i16> [[Y]])
+; CHECK-NEXT:    [[E0:%.*]] = extractvalue { <4 x i16>, <4 x i16> } [[D0]], 0
+; CHECK-NEXT:    [[E1:%.*]] = extractvalue { <4 x i16>, <4 x i16> } [[D1]], 1
+; CHECK-NEXT:    [[R0:%.*]] = call <4 x i16> @llvm.vector.reverse.v4i16(<4 x i16> [[E0]])
+; CHECK-NEXT:    [[R1:%.*]] = call <4 x i16> @llvm.vector.reverse.v4i16(<4 x i16> [[E1]])
+; CHECK-NEXT:    [[INTERLEAVE:%.*]] = call <8 x i16> @llvm.vector.interleave2.v8i16(<4 x i16> [[R1]], <4 x i16> [[R0]])
+; CHECK-NEXT:    ret <8 x i16> [[INTERLEAVE]]
+;
+  %d0 = call { <4 x i16>, <4 x i16> } @llvm.vector.deinterleave2(<8 x i16> %x)
+  %d1 = call { <4 x i16>, <4 x i16> } @llvm.vector.deinterleave2(<8 x i16> %y)
+  %e0 = extractvalue { <4 x i16>, <4 x i16> } %d0, 0
+  %e1 = extractvalue { <4 x i16>, <4 x i16> } %d1, 1
+  %r0 = call <4 x i16> @llvm.vector.reverse(<4 x i16> %e0)
+  %r1 = call <4 x i16> @llvm.vector.reverse(<4 x i16> %e1)
+  %interleave = call <8 x i16> @llvm.vector.interleave2(<4 x i16> %r1, <4 x i16> %r0)
+  ret <8 x i16> %interleave
+}
+
+define <24 x i16> @wrong_order_interleave3(<24 x i16> %x) {
+; CHECK-LABEL: define <24 x i16> @wrong_order_interleave3(
+; CHECK-SAME: <24 x i16> [[X:%.*]]) {
+; CHECK-NEXT:    [[DEINTERLEAVE:%.*]] = call { <8 x i16>, <8 x i16>, <8 x i16> } @llvm.vector.deinterleave3.v24i16(<24 x i16> [[X]])
+; CHECK-NEXT:    [[E0:%.*]] = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } [[DEINTERLEAVE]], 0
+; CHECK-NEXT:    [[E1:%.*]] = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } [[DEINTERLEAVE]], 1
+; CHECK-NEXT:    [[E2:%.*]] = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } [[DEINTERLEAVE]], 2
+; CHECK-NEXT:    [[R0:%.*]] = call <8 x i16> @llvm.vector.reverse.v8i16(<8 x i16> [[E0]])
+; CHECK-NEXT:    [[R1:%.*]] = call <8 x i16> @llvm.vector.reverse.v8i16(<8 x i16> [[E1]])
+; CHECK-NEXT:    [[R2:%.*]] = call <8 x i16> @llvm.vector.reverse.v8i16(<8 x i16> [[E2]])
+; CHECK-NEXT:    [[INTERLEAVE:%.*]] = call <24 x i16> @llvm.vector.interleave3.v24i16(<8 x i16> [[R1]], <8 x i16> [[R2]], <8 x i16> [[R0]])
+; CHECK-NEXT:    ret <24 x i16> [[INTERLEAVE]]
+;
+  %deinterleave = call { <8 x i16>, <8 x i16>, <8 x i16> } @llvm.vector.deinterleave3(<24 x i16> %x)
+  %e0 = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } %deinterleave, 0
+  %e1 = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } %deinterleave, 1
+  %e2 = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } %deinterleave, 2
+  %r0 = call <8 x i16> @llvm.vector.reverse(<8 x i16> %e0)
+  %r1 = call <8 x i16> @llvm.vector.reverse(<8 x i16> %e1)
+  %r2 = call <8 x i16> @llvm.vector.reverse(<8 x i16> %e2)
+  %interleave = call <24 x i16> @llvm.vector.interleave3(<8 x i16> %r1, <8 x i16> %r2, <8 x i16> %r0)
+  ret <24 x i16> %interleave
+}

>From 356c3eb2e05410bfd453143a8a50e105637322da Mon Sep 17 00:00:00 2001
From: Kamlesh Kumar <kamlesh.kumar at arm.com>
Date: Fri, 14 Aug 2026 11:41:39 +0100
Subject: [PATCH 2/3] [VectorCombine] Fold interleave of reversed deinterleave

---
 .../Transforms/Vectorize/VectorCombine.cpp    | 62 +++++++++++++++++++
 .../interleave-reverse-deinterleave.ll        | 54 ++--------------
 2 files changed, 68 insertions(+), 48 deletions(-)

diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
index dfe3070cfe87c..12fdc2d8a8367 100644
--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
+++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
@@ -156,6 +156,7 @@ class VectorCombine {
   bool foldEquivalentReductionCmp(Instruction &I);
   bool foldReduceAddCmpZero(Instruction &I);
   bool foldSelectShuffle(Instruction &I, bool FromReduction = false);
+  bool foldInterleaveOfReversedDeinterleave(Instruction &I);
   bool foldInterleaveIntrinsics(Instruction &I);
   bool foldDeinterleaveIntrinsics(Instruction &I);
   bool foldBitcastOfVPLoad(Instruction &I);
@@ -6145,6 +6146,65 @@ bool VectorCombine::foldDeinterleaveInterleavePair(Instruction &I) {
   return true;
 }
 
+/// Fold a reversed deinterleave with reversed field order to a vector reverse.
+/// i.e.
+/// interleaveN(reverse(deinterleaveN(X)[N-1]), ...,
+///             reverse(deinterleaveN(X)[0])) --> reverse(X).
+bool VectorCombine::foldInterleaveOfReversedDeinterleave(Instruction &I) {
+  auto *II = dyn_cast<IntrinsicInst>(&I);
+  if (!II)
+    return false;
+  unsigned Factor = getInterleaveIntrinsicFactor(II->getIntrinsicID());
+  if (!Factor)
+    return false;
+
+  IntrinsicInst *Deinterleave = nullptr;
+  for (unsigned Idx = 0; Idx != Factor; ++Idx) {
+    Value *Op = II->getArgOperand(Idx);
+    // Every reverse must feed only this interleave, otherwise
+    // it's not profitable to fold.
+    if (!Op->hasOneUse())
+      return false;
+
+    Value *Reversed = nullptr;
+    if (auto *Shuffle = dyn_cast<ShuffleVectorInst>(Op)) {
+      ArrayRef<int> Mask = Shuffle->getShuffleMask();
+      if (!Shuffle->isReverse() ||
+          !llvm::all_of(Mask, [NumElts = static_cast<int>(Mask.size())](
+                                  int MaskElt) { return MaskElt < NumElts; }))
+        return false;
+      Reversed = Shuffle->getOperand(0);
+    } else if (!match(Op, m_Intrinsic<Intrinsic::vector_reverse>(
+                              m_Value(Reversed)))) {
+      return false;
+    }
+
+    auto *Extract = dyn_cast<ExtractValueInst>(Reversed);
+    if (!Extract || !Extract->hasOneUse() || Extract->getNumIndices() != 1 ||
+        *Extract->idx_begin() != (Factor - Idx - 1))
+      return false;
+    auto *CurrentDeinterleave =
+        dyn_cast<IntrinsicInst>(Extract->getAggregateOperand());
+    if (!CurrentDeinterleave)
+      return false;
+    if (CurrentDeinterleave->getIntrinsicID() !=
+            Intrinsic::getDeinterleaveIntrinsicID(Factor) ||
+        (Deinterleave && Deinterleave != CurrentDeinterleave))
+      return false;
+
+    Deinterleave = CurrentDeinterleave;
+  }
+
+  if (!Deinterleave->hasNUses(Factor))
+    return false;
+
+  Value *Input = Deinterleave->getArgOperand(0);
+  Value *Reverse = Builder.CreateIntrinsic(Intrinsic::vector_reverse,
+                                           {Input->getType()}, {Input});
+  replaceValue(I, *Reverse);
+  return true;
+}
+
 /// If we're interleaving 2 constant splats, for instance `<vscale x 8 x i32>
 /// <splat of 666>` and `<vscale x 8 x i32> <splat of 777>`, we can create a
 /// larger splat `<vscale x 8 x i64> <splat of ((777 << 32) | 666)>` first
@@ -6794,6 +6854,8 @@ bool VectorCombine::run() {
         return true;
       if (scalarizeVPIntrinsic(I))
         return true;
+      if (foldInterleaveOfReversedDeinterleave(I))
+        return true;
       if (foldInterleaveIntrinsics(I))
         return true;
       if (foldBitcastOfVPLoad(I))
diff --git a/llvm/test/Transforms/VectorCombine/AArch64/interleave-reverse-deinterleave.ll b/llvm/test/Transforms/VectorCombine/AArch64/interleave-reverse-deinterleave.ll
index d0db7530aa9da..106b1cf5e0c16 100644
--- a/llvm/test/Transforms/VectorCombine/AArch64/interleave-reverse-deinterleave.ll
+++ b/llvm/test/Transforms/VectorCombine/AArch64/interleave-reverse-deinterleave.ll
@@ -4,14 +4,7 @@
 define <24 x i16> @reverse_interleave3(<24 x i16> %x) {
 ; CHECK-LABEL: define <24 x i16> @reverse_interleave3(
 ; CHECK-SAME: <24 x i16> [[X:%.*]]) {
-; CHECK-NEXT:    [[DEINTERLEAVE:%.*]] = call { <8 x i16>, <8 x i16>, <8 x i16> } @llvm.vector.deinterleave3.v24i16(<24 x i16> [[X]])
-; CHECK-NEXT:    [[E0:%.*]] = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } [[DEINTERLEAVE]], 0
-; CHECK-NEXT:    [[E1:%.*]] = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } [[DEINTERLEAVE]], 1
-; CHECK-NEXT:    [[E2:%.*]] = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } [[DEINTERLEAVE]], 2
-; CHECK-NEXT:    [[R0:%.*]] = shufflevector <8 x i16> [[E0]], <8 x i16> poison, <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
-; CHECK-NEXT:    [[R1:%.*]] = shufflevector <8 x i16> [[E1]], <8 x i16> poison, <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
-; CHECK-NEXT:    [[R2:%.*]] = shufflevector <8 x i16> [[E2]], <8 x i16> poison, <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
-; CHECK-NEXT:    [[INTERLEAVE:%.*]] = call <24 x i16> @llvm.vector.interleave3.v24i16(<8 x i16> [[R2]], <8 x i16> [[R1]], <8 x i16> [[R0]])
+; CHECK-NEXT:    [[INTERLEAVE:%.*]] = call <24 x i16> @llvm.vector.reverse.v24i16(<24 x i16> [[X]])
 ; CHECK-NEXT:    ret <24 x i16> [[INTERLEAVE]]
 ;
   %deinterleave = call { <8 x i16>, <8 x i16>, <8 x i16> } @llvm.vector.deinterleave3(<24 x i16> %x)
@@ -28,14 +21,7 @@ define <24 x i16> @reverse_interleave3(<24 x i16> %x) {
 define <24 x i16> @reverse_intrinsic_interleave3(<24 x i16> %x) {
 ; CHECK-LABEL: define <24 x i16> @reverse_intrinsic_interleave3(
 ; CHECK-SAME: <24 x i16> [[X:%.*]]) {
-; CHECK-NEXT:    [[DEINTERLEAVE:%.*]] = call { <8 x i16>, <8 x i16>, <8 x i16> } @llvm.vector.deinterleave3.v24i16(<24 x i16> [[X]])
-; CHECK-NEXT:    [[E0:%.*]] = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } [[DEINTERLEAVE]], 0
-; CHECK-NEXT:    [[E1:%.*]] = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } [[DEINTERLEAVE]], 1
-; CHECK-NEXT:    [[E2:%.*]] = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } [[DEINTERLEAVE]], 2
-; CHECK-NEXT:    [[R0:%.*]] = call <8 x i16> @llvm.vector.reverse.v8i16(<8 x i16> [[E0]])
-; CHECK-NEXT:    [[R1:%.*]] = call <8 x i16> @llvm.vector.reverse.v8i16(<8 x i16> [[E1]])
-; CHECK-NEXT:    [[R2:%.*]] = call <8 x i16> @llvm.vector.reverse.v8i16(<8 x i16> [[E2]])
-; CHECK-NEXT:    [[INTERLEAVE:%.*]] = call <24 x i16> @llvm.vector.interleave3.v24i16(<8 x i16> [[R2]], <8 x i16> [[R1]], <8 x i16> [[R0]])
+; CHECK-NEXT:    [[INTERLEAVE:%.*]] = call <24 x i16> @llvm.vector.reverse.v24i16(<24 x i16> [[X]])
 ; CHECK-NEXT:    ret <24 x i16> [[INTERLEAVE]]
 ;
   %deinterleave = call { <8 x i16>, <8 x i16>, <8 x i16> } @llvm.vector.deinterleave3(<24 x i16> %x)
@@ -52,14 +38,7 @@ define <24 x i16> @reverse_intrinsic_interleave3(<24 x i16> %x) {
 define <vscale x 24 x i16> @reverse_intrinsic_interleave3_scalable(<vscale x 24 x i16> %x) {
 ; CHECK-LABEL: define <vscale x 24 x i16> @reverse_intrinsic_interleave3_scalable(
 ; CHECK-SAME: <vscale x 24 x i16> [[X:%.*]]) {
-; CHECK-NEXT:    [[DEINTERLEAVE:%.*]] = call { <vscale x 8 x i16>, <vscale x 8 x i16>, <vscale x 8 x i16> } @llvm.vector.deinterleave3.nxv24i16(<vscale x 24 x i16> [[X]])
-; CHECK-NEXT:    [[E0:%.*]] = extractvalue { <vscale x 8 x i16>, <vscale x 8 x i16>, <vscale x 8 x i16> } [[DEINTERLEAVE]], 0
-; CHECK-NEXT:    [[E1:%.*]] = extractvalue { <vscale x 8 x i16>, <vscale x 8 x i16>, <vscale x 8 x i16> } [[DEINTERLEAVE]], 1
-; CHECK-NEXT:    [[E2:%.*]] = extractvalue { <vscale x 8 x i16>, <vscale x 8 x i16>, <vscale x 8 x i16> } [[DEINTERLEAVE]], 2
-; CHECK-NEXT:    [[R0:%.*]] = call <vscale x 8 x i16> @llvm.vector.reverse.nxv8i16(<vscale x 8 x i16> [[E0]])
-; CHECK-NEXT:    [[R1:%.*]] = call <vscale x 8 x i16> @llvm.vector.reverse.nxv8i16(<vscale x 8 x i16> [[E1]])
-; CHECK-NEXT:    [[R2:%.*]] = call <vscale x 8 x i16> @llvm.vector.reverse.nxv8i16(<vscale x 8 x i16> [[E2]])
-; CHECK-NEXT:    [[INTERLEAVE:%.*]] = call <vscale x 24 x i16> @llvm.vector.interleave3.nxv24i16(<vscale x 8 x i16> [[R2]], <vscale x 8 x i16> [[R1]], <vscale x 8 x i16> [[R0]])
+; CHECK-NEXT:    [[INTERLEAVE:%.*]] = call <vscale x 24 x i16> @llvm.vector.reverse.nxv24i16(<vscale x 24 x i16> [[X]])
 ; CHECK-NEXT:    ret <vscale x 24 x i16> [[INTERLEAVE]]
 ;
   %deinterleave = call { <vscale x 8 x i16>, <vscale x 8 x i16>, <vscale x 8 x i16> } @llvm.vector.deinterleave3(<vscale x 24 x i16> %x)
@@ -120,12 +99,7 @@ define <6 x i16> @reverse_second_operand_interleave2(<6 x i16> %x) {
 define <6 x i16> @reverse_poison_mask_interleave2(<6 x i16> %x) {
 ; CHECK-LABEL: define <6 x i16> @reverse_poison_mask_interleave2(
 ; CHECK-SAME: <6 x i16> [[X:%.*]]) {
-; CHECK-NEXT:    [[DEINTERLEAVE:%.*]] = call { <3 x i16>, <3 x i16> } @llvm.vector.deinterleave2.v6i16(<6 x i16> [[X]])
-; CHECK-NEXT:    [[E0:%.*]] = extractvalue { <3 x i16>, <3 x i16> } [[DEINTERLEAVE]], 0
-; CHECK-NEXT:    [[E1:%.*]] = extractvalue { <3 x i16>, <3 x i16> } [[DEINTERLEAVE]], 1
-; CHECK-NEXT:    [[R0:%.*]] = shufflevector <3 x i16> [[E0]], <3 x i16> poison, <3 x i32> <i32 2, i32 poison, i32 0>
-; CHECK-NEXT:    [[R1:%.*]] = shufflevector <3 x i16> [[E1]], <3 x i16> poison, <3 x i32> <i32 2, i32 1, i32 poison>
-; CHECK-NEXT:    [[INTERLEAVE:%.*]] = call <6 x i16> @llvm.vector.interleave2.v6i16(<3 x i16> [[R1]], <3 x i16> [[R0]])
+; CHECK-NEXT:    [[INTERLEAVE:%.*]] = call <6 x i16> @llvm.vector.reverse.v6i16(<6 x i16> [[X]])
 ; CHECK-NEXT:    ret <6 x i16> [[INTERLEAVE]]
 ;
   %deinterleave = call { <3 x i16>, <3 x i16> } @llvm.vector.deinterleave2(<6 x i16> %x)
@@ -140,16 +114,7 @@ define <6 x i16> @reverse_poison_mask_interleave2(<6 x i16> %x) {
 define <16 x i16> @reverse_interleave4(<16 x i16> %x) {
 ; CHECK-LABEL: define <16 x i16> @reverse_interleave4(
 ; CHECK-SAME: <16 x i16> [[X:%.*]]) {
-; CHECK-NEXT:    [[DEINTERLEAVE:%.*]] = call { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } @llvm.vector.deinterleave4.v16i16(<16 x i16> [[X]])
-; CHECK-NEXT:    [[E0:%.*]] = extractvalue { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } [[DEINTERLEAVE]], 0
-; CHECK-NEXT:    [[E1:%.*]] = extractvalue { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } [[DEINTERLEAVE]], 1
-; CHECK-NEXT:    [[E2:%.*]] = extractvalue { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } [[DEINTERLEAVE]], 2
-; CHECK-NEXT:    [[E3:%.*]] = extractvalue { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } [[DEINTERLEAVE]], 3
-; CHECK-NEXT:    [[R0:%.*]] = shufflevector <4 x i16> [[E0]], <4 x i16> poison, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
-; CHECK-NEXT:    [[R1:%.*]] = shufflevector <4 x i16> [[E1]], <4 x i16> poison, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
-; CHECK-NEXT:    [[R2:%.*]] = shufflevector <4 x i16> [[E2]], <4 x i16> poison, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
-; CHECK-NEXT:    [[R3:%.*]] = shufflevector <4 x i16> [[E3]], <4 x i16> poison, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
-; CHECK-NEXT:    [[INTERLEAVE:%.*]] = call <16 x i16> @llvm.vector.interleave4.v16i16(<4 x i16> [[R3]], <4 x i16> [[R2]], <4 x i16> [[R1]], <4 x i16> [[R0]])
+; CHECK-NEXT:    [[INTERLEAVE:%.*]] = call <16 x i16> @llvm.vector.reverse.v16i16(<16 x i16> [[X]])
 ; CHECK-NEXT:    ret <16 x i16> [[INTERLEAVE]]
 ;
   %deinterleave = call { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } @llvm.vector.deinterleave4(<16 x i16> %x)
@@ -168,14 +133,7 @@ define <16 x i16> @reverse_interleave4(<16 x i16> %x) {
 define <24 x i16> @mixed_reverse_interleave3(<24 x i16> %x) {
 ; CHECK-LABEL: define <24 x i16> @mixed_reverse_interleave3(
 ; CHECK-SAME: <24 x i16> [[X:%.*]]) {
-; CHECK-NEXT:    [[DEINTERLEAVE:%.*]] = call { <8 x i16>, <8 x i16>, <8 x i16> } @llvm.vector.deinterleave3.v24i16(<24 x i16> [[X]])
-; CHECK-NEXT:    [[E0:%.*]] = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } [[DEINTERLEAVE]], 0
-; CHECK-NEXT:    [[E1:%.*]] = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } [[DEINTERLEAVE]], 1
-; CHECK-NEXT:    [[E2:%.*]] = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } [[DEINTERLEAVE]], 2
-; CHECK-NEXT:    [[R0:%.*]] = shufflevector <8 x i16> [[E0]], <8 x i16> poison, <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
-; CHECK-NEXT:    [[R1:%.*]] = call <8 x i16> @llvm.vector.reverse.v8i16(<8 x i16> [[E1]])
-; CHECK-NEXT:    [[R2:%.*]] = shufflevector <8 x i16> [[E2]], <8 x i16> poison, <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
-; CHECK-NEXT:    [[INTERLEAVE:%.*]] = call <24 x i16> @llvm.vector.interleave3.v24i16(<8 x i16> [[R2]], <8 x i16> [[R1]], <8 x i16> [[R0]])
+; CHECK-NEXT:    [[INTERLEAVE:%.*]] = call <24 x i16> @llvm.vector.reverse.v24i16(<24 x i16> [[X]])
 ; CHECK-NEXT:    ret <24 x i16> [[INTERLEAVE]]
 ;
   %deinterleave = call { <8 x i16>, <8 x i16>, <8 x i16> } @llvm.vector.deinterleave3(<24 x i16> %x)

>From 1fcbbd005a30f478600d66676836a8f25407dbc1 Mon Sep 17 00:00:00 2001
From: Kamlesh Kumar <kamlesh.kumar at arm.com>
Date: Fri, 21 Aug 2026 11:09:55 +0000
Subject: [PATCH 3/3] Remove original combine and extend
 foldDeinterleaveInterleavePair combine

---
 .../Transforms/Vectorize/VectorCombine.cpp    | 182 ++++++++----------
 .../deinterleave-interleave-pairs.ll          |  77 ++++++++
 2 files changed, 160 insertions(+), 99 deletions(-)

diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
index 12fdc2d8a8367..d2c85590393f8 100644
--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
+++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
@@ -156,7 +156,6 @@ class VectorCombine {
   bool foldEquivalentReductionCmp(Instruction &I);
   bool foldReduceAddCmpZero(Instruction &I);
   bool foldSelectShuffle(Instruction &I, bool FromReduction = false);
-  bool foldInterleaveOfReversedDeinterleave(Instruction &I);
   bool foldInterleaveIntrinsics(Instruction &I);
   bool foldDeinterleaveIntrinsics(Instruction &I);
   bool foldBitcastOfVPLoad(Instruction &I);
@@ -5918,8 +5917,7 @@ bool VectorCombine::foldInsExtVectorToShuffle(Instruction &I) {
 }
 
 /// Fold away a matched pair of vector.deinterleave/interleave intrinsics
-/// with a chain of elementwise operations on each between the
-/// deinterleave and interleave.
+/// with a chain of operations on each between the deinterleave and interleave.
 ///
 /// For example:
 ///  ```
@@ -5967,10 +5965,15 @@ bool VectorCombine::foldDeinterleaveInterleavePair(Instruction &I) {
     CurrentUses[Index] = &U;
   }
 
-  using ElementwiseStep = SmallVector<Use *, 8>;
-  SmallVector<ElementwiseStep, 4> Steps;
+  enum class OperationKind { Elementwise, Reverse };
+  struct ChainStep {
+    SmallVector<Use *, 8> Uses;
+    OperationKind Kind;
+  };
+  SmallVector<ChainStep, 4> Steps;
   IntrinsicInst *Interleave = nullptr;
   unsigned NumVisited = 0;
+  bool HasReverseStep = false;
 
   auto GetNumDataOperands = [](Instruction *Inst) {
     if (auto *CB = dyn_cast<CallBase>(Inst))
@@ -5978,7 +5981,25 @@ bool VectorCombine::foldDeinterleaveInterleavePair(Instruction &I) {
     return Inst->getNumOperands();
   };
 
-  auto IsSupportedElementwise = [&](Instruction *Inst) {
+  auto IsSupportedOperation = [&](Use *U, OperationKind &Kind) {
+    auto *Inst = cast<Instruction>(U->getUser());
+    if (U->getOperandNo() == 0) {
+      if (auto *Shuffle = dyn_cast<ShuffleVectorInst>(Inst)) {
+        ArrayRef<int> Mask = Shuffle->getShuffleMask();
+        if (Shuffle->isReverse() &&
+            llvm::all_of(Mask, [NumElts = static_cast<int>(Mask.size())](
+                                   int M) { return M < NumElts; })) {
+          Kind = OperationKind::Reverse;
+          return true;
+        }
+      } else if (auto *II = dyn_cast<IntrinsicInst>(Inst);
+                 II && !II->hasOperandBundles() &&
+                 II->getIntrinsicID() == Intrinsic::vector_reverse) {
+        Kind = OperationKind::Reverse;
+        return true;
+      }
+    }
+
     auto *ResultTy = dyn_cast<VectorType>(Inst->getType());
     if (!ResultTy || !isSafeToSpeculativelyExecute(Inst))
       return false;
@@ -6001,6 +6022,7 @@ bool VectorCombine::foldDeinterleaveInterleavePair(Instruction &I) {
         return false;
     }
 
+    Kind = OperationKind::Elementwise;
     return true;
   };
 
@@ -6027,19 +6049,36 @@ bool VectorCombine::foldDeinterleaveInterleavePair(Instruction &I) {
       if (II->hasOperandBundles())
         return false;
 
-      for (unsigned Index = 0; Index != Factor; ++Index)
+      for (unsigned Index = 0; Index != Factor; ++Index) {
+        unsigned InterleaveIndex = HasReverseStep ? Factor - Index - 1 : Index;
         if (CurrentUses[Index]->getUser() != II ||
-            CurrentUses[Index]->getOperandNo() != Index)
+            CurrentUses[Index]->getOperandNo() != InterleaveIndex)
           return false;
+      }
 
       Interleave = II;
       break;
     }
 
-    auto *FirstInst = cast<Instruction>(CurrentUses.front()->getUser());
-    if (!IsSupportedElementwise(FirstInst))
+    OperationKind Kind;
+    if (!IsSupportedOperation(CurrentUses.front(), Kind) ||
+        llvm::any_of(CurrentUses, [&](Use *U) {
+          OperationKind OtherKind;
+          return !IsSupportedOperation(U, OtherKind) || OtherKind != Kind;
+        }))
       return false;
 
+    // Reversing every field and reversing their order in the interleave is
+    // equivalent to reversing the original wide vector.
+    if (Kind == OperationKind::Reverse) {
+      if (HasReverseStep)
+        return false;
+      HasReverseStep = true;
+      Steps.push_back({CurrentUses, Kind});
+      continue;
+    }
+
+    auto *FirstInst = cast<Instruction>(CurrentUses.front()->getUser());
     unsigned ChainOperand = CurrentUses.front()->getOperandNo();
     if (any_of(CurrentUses, [&](Use *U) {
           auto *Inst = cast<Instruction>(U->getUser());
@@ -6068,22 +6107,23 @@ bool VectorCombine::foldDeinterleaveInterleavePair(Instruction &I) {
         return false;
     }
 
-    Steps.push_back(CurrentUses);
+    Steps.push_back({CurrentUses, Kind});
   }
 
   if (!Interleave)
     return false;
 
-  // Rebuild the matched elementwise chain at the original vector width.
+  // Rebuild the matched chain at the original vector width.
   Value *WideValue = Deinterleave->getArgOperand(0);
   ElementCount WideEC =
       cast<VectorType>(WideValue->getType())->getElementCount();
 
-  auto CreateWideInstruction = [&](Instruction *NarrowInst,
-                                   ArrayRef<Value *> NewOperands,
-                                   VectorType *WideResultTy) -> Value * {
-    assert(IsSupportedElementwise(NarrowInst) &&
-           "Expected supported elementwise");
+  auto CreateWideOperation = [&](const ChainStep &Step,
+                                 ArrayRef<Value *> NewOperands,
+                                 VectorType *WideResultTy) -> Value * {
+    assert(Step.Kind == OperationKind::Elementwise &&
+           "Expected supported elementwise operation");
+    Instruction *NarrowInst = cast<Instruction>(Step.Uses.front()->getUser());
     if (isa<BinaryOperator, UnaryOperator>(NarrowInst))
       return Builder.CreateNAryOp(NarrowInst->getOpcode(), NewOperands);
     if (auto *Cast = dyn_cast<CastInst>(NarrowInst))
@@ -6105,34 +6145,39 @@ bool VectorCombine::foldDeinterleaveInterleavePair(Instruction &I) {
 
   // The BFS has succeeded and collected multiple levels of instructions that
   // can be SLP-widened into a chain of wider instructions.
-  for (const ElementwiseStep &Step : Steps) {
-    Instruction *NarrowInst = cast<Instruction>(Step.front()->getUser());
-    unsigned ChainOperand = Step.front()->getOperandNo();
+  for (const ChainStep &Step : Steps) {
+    Instruction *NarrowInst = cast<Instruction>(Step.Uses.front()->getUser());
 
     Builder.SetInsertPoint(NarrowInst);
     Builder.SetCurrentDebugLocation(NarrowInst->getDebugLoc());
 
-    unsigned NumOperands = GetNumDataOperands(NarrowInst);
-    SmallVector<Value *, 4> NewOperands;
-    NewOperands.reserve(NumOperands);
-
-    for (unsigned Op = 0; Op != NumOperands; ++Op) {
-      Value *Operand = NarrowInst->getOperand(Op);
-
-      if (Op == ChainOperand)
-        Operand = WideValue;
-      else if (isa<VectorType>(Operand->getType()))
-        Operand = Builder.CreateVectorSplat(WideEC, getSplatValue(Operand));
-      NewOperands.push_back(Operand);
-    }
-
     auto *WideResultTy =
         VectorType::get(NarrowInst->getType()->getScalarType(), WideEC);
-    Value *NewValue =
-        CreateWideInstruction(NarrowInst, NewOperands, WideResultTy);
+    Value *NewValue;
+    if (Step.Kind == OperationKind::Reverse) {
+      NewValue = Builder.CreateIntrinsic(Intrinsic::vector_reverse,
+                                         {WideResultTy}, {WideValue});
+    } else {
+      unsigned ChainOperand = Step.Uses.front()->getOperandNo();
+      unsigned NumOperands = GetNumDataOperands(NarrowInst);
+      SmallVector<Value *, 4> NewOperands;
+      NewOperands.reserve(NumOperands);
+
+      for (unsigned Op = 0; Op != NumOperands; ++Op) {
+        Value *Operand = NarrowInst->getOperand(Op);
+
+        if (Op == ChainOperand)
+          Operand = WideValue;
+        else if (isa<VectorType>(Operand->getType()))
+          Operand = Builder.CreateVectorSplat(WideEC, getSplatValue(Operand));
+        NewOperands.push_back(Operand);
+      }
+
+      NewValue = CreateWideOperation(Step, NewOperands, WideResultTy);
+    }
 
-    SmallVector<Value *> NarrowInsts =
-        map_to_vector(Step, [](Use *U) { return cast<Value>(U->getUser()); });
+    SmallVector<Value *> NarrowInsts = map_to_vector(
+        Step.Uses, [](Use *U) { return cast<Value>(U->getUser()); });
     propagateIRFlags(NewValue, NarrowInsts);
 
     if (auto *NewInst = dyn_cast<Instruction>(NewValue))
@@ -6146,65 +6191,6 @@ bool VectorCombine::foldDeinterleaveInterleavePair(Instruction &I) {
   return true;
 }
 
-/// Fold a reversed deinterleave with reversed field order to a vector reverse.
-/// i.e.
-/// interleaveN(reverse(deinterleaveN(X)[N-1]), ...,
-///             reverse(deinterleaveN(X)[0])) --> reverse(X).
-bool VectorCombine::foldInterleaveOfReversedDeinterleave(Instruction &I) {
-  auto *II = dyn_cast<IntrinsicInst>(&I);
-  if (!II)
-    return false;
-  unsigned Factor = getInterleaveIntrinsicFactor(II->getIntrinsicID());
-  if (!Factor)
-    return false;
-
-  IntrinsicInst *Deinterleave = nullptr;
-  for (unsigned Idx = 0; Idx != Factor; ++Idx) {
-    Value *Op = II->getArgOperand(Idx);
-    // Every reverse must feed only this interleave, otherwise
-    // it's not profitable to fold.
-    if (!Op->hasOneUse())
-      return false;
-
-    Value *Reversed = nullptr;
-    if (auto *Shuffle = dyn_cast<ShuffleVectorInst>(Op)) {
-      ArrayRef<int> Mask = Shuffle->getShuffleMask();
-      if (!Shuffle->isReverse() ||
-          !llvm::all_of(Mask, [NumElts = static_cast<int>(Mask.size())](
-                                  int MaskElt) { return MaskElt < NumElts; }))
-        return false;
-      Reversed = Shuffle->getOperand(0);
-    } else if (!match(Op, m_Intrinsic<Intrinsic::vector_reverse>(
-                              m_Value(Reversed)))) {
-      return false;
-    }
-
-    auto *Extract = dyn_cast<ExtractValueInst>(Reversed);
-    if (!Extract || !Extract->hasOneUse() || Extract->getNumIndices() != 1 ||
-        *Extract->idx_begin() != (Factor - Idx - 1))
-      return false;
-    auto *CurrentDeinterleave =
-        dyn_cast<IntrinsicInst>(Extract->getAggregateOperand());
-    if (!CurrentDeinterleave)
-      return false;
-    if (CurrentDeinterleave->getIntrinsicID() !=
-            Intrinsic::getDeinterleaveIntrinsicID(Factor) ||
-        (Deinterleave && Deinterleave != CurrentDeinterleave))
-      return false;
-
-    Deinterleave = CurrentDeinterleave;
-  }
-
-  if (!Deinterleave->hasNUses(Factor))
-    return false;
-
-  Value *Input = Deinterleave->getArgOperand(0);
-  Value *Reverse = Builder.CreateIntrinsic(Intrinsic::vector_reverse,
-                                           {Input->getType()}, {Input});
-  replaceValue(I, *Reverse);
-  return true;
-}
-
 /// If we're interleaving 2 constant splats, for instance `<vscale x 8 x i32>
 /// <splat of 666>` and `<vscale x 8 x i32> <splat of 777>`, we can create a
 /// larger splat `<vscale x 8 x i64> <splat of ((777 << 32) | 666)>` first
@@ -6854,8 +6840,6 @@ bool VectorCombine::run() {
         return true;
       if (scalarizeVPIntrinsic(I))
         return true;
-      if (foldInterleaveOfReversedDeinterleave(I))
-        return true;
       if (foldInterleaveIntrinsics(I))
         return true;
       if (foldBitcastOfVPLoad(I))
diff --git a/llvm/test/Transforms/VectorCombine/deinterleave-interleave-pairs.ll b/llvm/test/Transforms/VectorCombine/deinterleave-interleave-pairs.ll
index 1ffe6bac7308f..3ad55c4be136f 100644
--- a/llvm/test/Transforms/VectorCombine/deinterleave-interleave-pairs.ll
+++ b/llvm/test/Transforms/VectorCombine/deinterleave-interleave-pairs.ll
@@ -226,6 +226,83 @@ define <vscale x 8 x float> @deinterleave2_fneg_interleave2(<vscale x 8 x float>
   ret <vscale x 8 x float> %r
 }
 
+define <16 x float> @deinterleave4_fmul_reverse_interleave4(<16 x float> %v) {
+; CHECK-LABEL: define <16 x float> @deinterleave4_fmul_reverse_interleave4(
+; CHECK-SAME: <16 x float> [[V:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul <16 x float> [[V]], splat (float 2.000000e+00)
+; CHECK-NEXT:    [[R:%.*]] = call <16 x float> @llvm.vector.reverse.v16f32(<16 x float> [[MUL]])
+; CHECK-NEXT:    ret <16 x float> [[R]]
+;
+  %d = call { <4 x float>, <4 x float>, <4 x float>, <4 x float> } @llvm.vector.deinterleave4.v16f32(<16 x float> %v)
+  %f0 = extractvalue { <4 x float>, <4 x float>, <4 x float>, <4 x float> } %d, 0
+  %f1 = extractvalue { <4 x float>, <4 x float>, <4 x float>, <4 x float> } %d, 1
+  %f2 = extractvalue { <4 x float>, <4 x float>, <4 x float>, <4 x float> } %d, 2
+  %f3 = extractvalue { <4 x float>, <4 x float>, <4 x float>, <4 x float> } %d, 3
+  %mul0 = fmul <4 x float> %f0, splat (float 2.000000e+00)
+  %mul1 = fmul <4 x float> %f1, splat (float 2.000000e+00)
+  %mul2 = fmul <4 x float> %f2, splat (float 2.000000e+00)
+  %mul3 = fmul <4 x float> %f3, splat (float 2.000000e+00)
+  %rev0 = call <4 x float> @llvm.vector.reverse.v4f32(<4 x float> %mul0)
+  %rev1 = call <4 x float> @llvm.vector.reverse.v4f32(<4 x float> %mul1)
+  %rev2 = call <4 x float> @llvm.vector.reverse.v4f32(<4 x float> %mul2)
+  %rev3 = call <4 x float> @llvm.vector.reverse.v4f32(<4 x float> %mul3)
+  %r = call <16 x float> @llvm.vector.interleave4.v16f32(<4 x float> %rev3, <4 x float> %rev2, <4 x float> %rev1, <4 x float> %rev0)
+  ret <16 x float> %r
+}
+
+define <16 x float> @deinterleave4_reverse_fmul_interleave4(<16 x float> %v) {
+; CHECK-LABEL: define <16 x float> @deinterleave4_reverse_fmul_interleave4(
+; CHECK-SAME: <16 x float> [[V:%.*]]) {
+; CHECK-NEXT:    [[REVERSE:%.*]] = call <16 x float> @llvm.vector.reverse.v16f32(<16 x float> [[V]])
+; CHECK-NEXT:    [[R:%.*]] = fmul <16 x float> [[REVERSE]], splat (float 2.000000e+00)
+; CHECK-NEXT:    ret <16 x float> [[R]]
+;
+  %d = call { <4 x float>, <4 x float>, <4 x float>, <4 x float> } @llvm.vector.deinterleave4.v16f32(<16 x float> %v)
+  %f0 = extractvalue { <4 x float>, <4 x float>, <4 x float>, <4 x float> } %d, 0
+  %f1 = extractvalue { <4 x float>, <4 x float>, <4 x float>, <4 x float> } %d, 1
+  %f2 = extractvalue { <4 x float>, <4 x float>, <4 x float>, <4 x float> } %d, 2
+  %f3 = extractvalue { <4 x float>, <4 x float>, <4 x float>, <4 x float> } %d, 3
+  %rev0 = call <4 x float> @llvm.vector.reverse.v4f32(<4 x float> %f0)
+  %rev1 = call <4 x float> @llvm.vector.reverse.v4f32(<4 x float> %f1)
+  %rev2 = call <4 x float> @llvm.vector.reverse.v4f32(<4 x float> %f2)
+  %rev3 = call <4 x float> @llvm.vector.reverse.v4f32(<4 x float> %f3)
+  %mul0 = fmul <4 x float> %rev0, splat (float 2.000000e+00)
+  %mul1 = fmul <4 x float> %rev1, splat (float 2.000000e+00)
+  %mul2 = fmul <4 x float> %rev2, splat (float 2.000000e+00)
+  %mul3 = fmul <4 x float> %rev3, splat (float 2.000000e+00)
+  %r = call <16 x float> @llvm.vector.interleave4.v16f32(<4 x float> %mul3, <4 x float> %mul2, <4 x float> %mul1, <4 x float> %mul0)
+  ret <16 x float> %r
+}
+
+define <16 x i16> @deinterleave4_add_reverse_mul_interleave4(<16 x i16> %v) {
+; CHECK-LABEL: define <16 x i16> @deinterleave4_add_reverse_mul_interleave4(
+; CHECK-SAME: <16 x i16> [[V:%.*]]) {
+; CHECK-NEXT:    [[ADD:%.*]] = add <16 x i16> [[V]], splat (i16 1)
+; CHECK-NEXT:    [[REVERSE:%.*]] = call <16 x i16> @llvm.vector.reverse.v16i16(<16 x i16> [[ADD]])
+; CHECK-NEXT:    [[R:%.*]] = mul <16 x i16> [[REVERSE]], splat (i16 2)
+; CHECK-NEXT:    ret <16 x i16> [[R]]
+;
+  %d = call { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } @llvm.vector.deinterleave4.v16i16(<16 x i16> %v)
+  %f0 = extractvalue { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } %d, 0
+  %f1 = extractvalue { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } %d, 1
+  %f2 = extractvalue { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } %d, 2
+  %f3 = extractvalue { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } %d, 3
+  %add0 = add <4 x i16> %f0, splat (i16 1)
+  %add1 = add <4 x i16> %f1, splat (i16 1)
+  %add2 = add <4 x i16> %f2, splat (i16 1)
+  %add3 = add <4 x i16> %f3, splat (i16 1)
+  %rev0 = call <4 x i16> @llvm.vector.reverse.v4i16(<4 x i16> %add0)
+  %rev1 = call <4 x i16> @llvm.vector.reverse.v4i16(<4 x i16> %add1)
+  %rev2 = call <4 x i16> @llvm.vector.reverse.v4i16(<4 x i16> %add2)
+  %rev3 = call <4 x i16> @llvm.vector.reverse.v4i16(<4 x i16> %add3)
+  %mul0 = mul <4 x i16> %rev0, splat (i16 2)
+  %mul1 = mul <4 x i16> %rev1, splat (i16 2)
+  %mul2 = mul <4 x i16> %rev2, splat (i16 2)
+  %mul3 = mul <4 x i16> %rev3, splat (i16 2)
+  %r = call <16 x i16> @llvm.vector.interleave4.v16i16(<4 x i16> %mul3, <4 x i16> %mul2, <4 x i16> %mul1, <4 x i16> %mul0)
+  ret <16 x i16> %r
+}
+
 define <vscale x 8 x float> @deinterleave2_bitcast_interleave2(<vscale x 8 x i32> %v) {
 ; CHECK-LABEL: define <vscale x 8 x float> @deinterleave2_bitcast_interleave2(
 ; CHECK-SAME: <vscale x 8 x i32> [[V:%.*]]) {



More information about the llvm-commits mailing list