[llvm] [AArch64] [DAG] combine vector_interleave to zip/zip2 (PR #231066)
via llvm-commits
llvm-commits at lists.llvm.org
Sun Oct 11 21:46:19 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-aarch64
Author: Chen Zheng (chenzheng1030)
<details>
<summary>Changes</summary>
Add a ZIP/ZIP2 combine pattern for scalable vector types.
NEON has similiar opportunities but since the pattern is not the same, so NEON pattern will be handled differently.
---
Full diff: https://github.com/llvm/llvm-project/pull/231066.diff
2 Files Affected:
- (modified) llvm/lib/Target/AArch64/AArch64ISelLowering.cpp (+26)
- (added) llvm/test/CodeGen/AArch64/interleave-combine-zip.ll (+38)
``````````diff
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index b86a0c439bfa3..c39f35659cd8c 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -22739,6 +22739,32 @@ static SDValue performConcatVectorsCombine(SDNode *N,
return DAG.getNode(AArch64ISD::TRN1, DL, VT, Op0MoreElems, Op1MoreElems);
}
+ // Interleaving the low (or high) halves of two packed vectors is a single
+ // ZIP1 (or ZIP2) of the whole vectors:
+ // (concat_vectors (vector_interleave (extract_subvector A, I),
+ // (extract_subvector B, I)))
+ // -> (zip1 A, B) if I == 0, (zip2 A, B) if I == half the elements.
+ // Below pattern is only for scalable vectors as fixed vectors will use
+ // vector_shuffle instead of vector_interleave.
+ if (VT.isScalableVector() && N->getNumOperands() == 2 &&
+ N0Opc == ISD::VECTOR_INTERLEAVE && N0.getNode() == N1.getNode() &&
+ N0->getNumOperands() == 2 && N0.getResNo() == 0 && N1.getResNo() == 1) {
+ SDValue Lo = N0->getOperand(0), Hi = N0->getOperand(1);
+ if (Lo.getOpcode() == ISD::EXTRACT_SUBVECTOR &&
+ Hi.getOpcode() == ISD::EXTRACT_SUBVECTOR &&
+ Lo.getOperand(0).getValueType() == VT &&
+ Hi.getOperand(0).getValueType() == VT &&
+ Lo.getConstantOperandVal(1) == Hi.getConstantOperandVal(1)) {
+ uint64_t Idx = Lo.getConstantOperandVal(1);
+ if (Idx == 0)
+ return DAG.getNode(AArch64ISD::ZIP1, DL, VT, Lo.getOperand(0),
+ Hi.getOperand(0));
+ if (Idx == VT.getVectorMinNumElements() / 2)
+ return DAG.getNode(AArch64ISD::ZIP2, DL, VT, Lo.getOperand(0),
+ Hi.getOperand(0));
+ }
+ }
+
if (VT.isScalableVector())
return SDValue();
diff --git a/llvm/test/CodeGen/AArch64/interleave-combine-zip.ll b/llvm/test/CodeGen/AArch64/interleave-combine-zip.ll
new file mode 100644
index 0000000000000..08a148d207f0f
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/interleave-combine-zip.ll
@@ -0,0 +1,38 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc < %s -mtriple=aarch64-linux-gnu -mattr=+sve -verify-machineinstrs | FileCheck %s
+
+define <vscale x 8 x bfloat> @interleave2_lo_halves_nxv8bf16(<vscale x 8 x bfloat> %a, <vscale x 8 x bfloat> %b) {
+; CHECK-LABEL: interleave2_lo_halves_nxv8bf16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: zip1 z0.h, z0.h, z1.h
+; CHECK-NEXT: ret
+ %x = call <vscale x 4 x bfloat> @llvm.vector.extract.nxv4bf16.nxv8bf16(<vscale x 8 x bfloat> %a, i64 0)
+ %y = call <vscale x 4 x bfloat> @llvm.vector.extract.nxv4bf16.nxv8bf16(<vscale x 8 x bfloat> %b, i64 0)
+ %r = call <vscale x 8 x bfloat> @llvm.vector.interleave2.nxv8bf16(<vscale x 4 x bfloat> %x, <vscale x 4 x bfloat> %y)
+ ret <vscale x 8 x bfloat> %r
+}
+
+define <vscale x 4 x float> @interleave2_hi_halves_nxv4f32(<vscale x 4 x float> %a, <vscale x 4 x float> %b) {
+; CHECK-LABEL: interleave2_hi_halves_nxv4f32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: zip2 z0.s, z0.s, z1.s
+; CHECK-NEXT: ret
+ %x = call <vscale x 2 x float> @llvm.vector.extract.nxv2f32.nxv4f32(<vscale x 4 x float> %a, i64 2)
+ %y = call <vscale x 2 x float> @llvm.vector.extract.nxv2f32.nxv4f32(<vscale x 4 x float> %b, i64 2)
+ %r = call <vscale x 4 x float> @llvm.vector.interleave2.nxv4f32(<vscale x 2 x float> %x, <vscale x 2 x float> %y)
+ ret <vscale x 4 x float> %r
+}
+
+define <vscale x 8 x bfloat> @interleave2_mixed_halves_nxv8bf16(<vscale x 8 x bfloat> %a, <vscale x 8 x bfloat> %b) {
+; CHECK-LABEL: interleave2_mixed_halves_nxv8bf16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: uunpklo z0.s, z0.h
+; CHECK-NEXT: uunpkhi z1.s, z1.h
+; CHECK-NEXT: trn1 z0.h, z0.h, z1.h
+; CHECK-NEXT: ret
+ %x = call <vscale x 4 x bfloat> @llvm.vector.extract.nxv4bf16.nxv8bf16(<vscale x 8 x bfloat> %a, i64 0)
+ %y = call <vscale x 4 x bfloat> @llvm.vector.extract.nxv4bf16.nxv8bf16(<vscale x 8 x bfloat> %b, i64 4)
+ %r = call <vscale x 8 x bfloat> @llvm.vector.interleave2.nxv8bf16(<vscale x 4 x bfloat> %x, <vscale x 4 x bfloat> %y)
+ ret <vscale x 8 x bfloat> %r
+}
+
``````````
</details>
https://github.com/llvm/llvm-project/pull/231066
More information about the llvm-commits
mailing list