[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