[llvm] [AArch64] Support wide interleaved store combine (PR #217856)
Kamlesh Kumar via llvm-commits
llvm-commits at lists.llvm.org
Fri Sep 4 01:20:32 PDT 2026
https://github.com/kamleshbhalui updated https://github.com/llvm/llvm-project/pull/217856
>From 6591860f43c2d121f50129ab2db602dfde8b9616 Mon Sep 17 00:00:00 2001
From: Kamlesh Kumar <kamlesh.kumar at arm.com>
Date: Thu, 20 Aug 2026 19:36:41 +0000
Subject: [PATCH 1/3] added the test
---
.../AArch64/vector-interleave-store.ll | 638 ++++++++++++++++++
1 file changed, 638 insertions(+)
diff --git a/llvm/test/CodeGen/AArch64/vector-interleave-store.ll b/llvm/test/CodeGen/AArch64/vector-interleave-store.ll
index d3985991af531..9732dfc246e70 100644
--- a/llvm/test/CodeGen/AArch64/vector-interleave-store.ll
+++ b/llvm/test/CodeGen/AArch64/vector-interleave-store.ll
@@ -1,6 +1,7 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
; RUN: llc -mtriple=aarch64-linux-gnu < %s | FileCheck %s --check-prefixes=CHECK,CHECK-IAENABLED
; RUN: llc -mtriple=aarch64-linux-gnu -lower-interleaved-accesses=false < %s | FileCheck %s --check-prefixes=CHECK,CHECK-IADISABLED
+
define void @aarch64_vector_interleave_idx_st2(ptr %ptr, i64 %idx, <4 x float> %v0, <4 x float> %v1) {
; CHECK-IAENABLED-LABEL: aarch64_vector_interleave_idx_st2:
; CHECK-IAENABLED: // %bb.0: // %entry
@@ -66,3 +67,640 @@ entry:
store <16 x float> %interleave, ptr %gep1, align 16
ret void
}
+
+define void @wide_vector_interleave_st2(ptr %input0, ptr %input1, ptr %output) {
+; CHECK-IAENABLED-LABEL: wide_vector_interleave_st2:
+; CHECK-IAENABLED: // %bb.0:
+; CHECK-IAENABLED-NEXT: ldp q0, q2, [x0]
+; CHECK-IAENABLED-NEXT: ldp q1, q3, [x1]
+; CHECK-IAENABLED-NEXT: st2 { v0.4s, v1.4s }, [x2], #32
+; CHECK-IAENABLED-NEXT: st2 { v2.4s, v3.4s }, [x2]
+; CHECK-IAENABLED-NEXT: ret
+;
+; CHECK-IADISABLED-LABEL: wide_vector_interleave_st2:
+; CHECK-IADISABLED: // %bb.0:
+; CHECK-IADISABLED-NEXT: ldp q3, q0, [x1]
+; CHECK-IADISABLED-NEXT: ldp q2, q1, [x0]
+; CHECK-IADISABLED-NEXT: zip1 v4.4s, v1.4s, v0.4s
+; CHECK-IADISABLED-NEXT: zip2 v0.4s, v1.4s, v0.4s
+; CHECK-IADISABLED-NEXT: zip1 v1.4s, v2.4s, v3.4s
+; CHECK-IADISABLED-NEXT: zip2 v2.4s, v2.4s, v3.4s
+; CHECK-IADISABLED-NEXT: stp q4, q0, [x2, #32]
+; CHECK-IADISABLED-NEXT: stp q1, q2, [x2]
+; CHECK-IADISABLED-NEXT: ret
+ %v0 = load <8 x i32>, ptr %input0, align 4
+ %v1 = load <8 x i32>, ptr %input1, align 4
+ %interleaved.vec = tail call <16 x i32> @llvm.vector.interleave2.v16i32(<8 x i32> %v0, <8 x i32> %v1)
+ store <16 x i32> %interleaved.vec, ptr %output, align 8
+ ret void
+}
+
+define void @wide_vector_interleave_st3(ptr %output, ptr %input0, ptr %input1, ptr %input2) {
+; CHECK-IAENABLED-LABEL: wide_vector_interleave_st3:
+; CHECK-IAENABLED: // %bb.0:
+; CHECK-IAENABLED-NEXT: ldp q0, q3, [x1]
+; CHECK-IAENABLED-NEXT: ldp q1, q4, [x2]
+; CHECK-IAENABLED-NEXT: ldp q2, q5, [x3]
+; CHECK-IAENABLED-NEXT: st3 { v0.4s, v1.4s, v2.4s }, [x0], #48
+; CHECK-IAENABLED-NEXT: st3 { v3.4s, v4.4s, v5.4s }, [x0]
+; CHECK-IAENABLED-NEXT: ret
+;
+; CHECK-IADISABLED-LABEL: wide_vector_interleave_st3:
+; CHECK-IADISABLED: // %bb.0:
+; CHECK-IADISABLED-NEXT: sub sp, sp, #96
+; CHECK-IADISABLED-NEXT: .cfi_def_cfa_offset 96
+; CHECK-IADISABLED-NEXT: ldp q0, q3, [x1]
+; CHECK-IADISABLED-NEXT: mov x8, sp
+; CHECK-IADISABLED-NEXT: ldp q1, q4, [x2]
+; CHECK-IADISABLED-NEXT: ldp q2, q5, [x3]
+; CHECK-IADISABLED-NEXT: st3 { v0.4s, v1.4s, v2.4s }, [x8]
+; CHECK-IADISABLED-NEXT: add x8, sp, #48
+; CHECK-IADISABLED-NEXT: st3 { v3.4s, v4.4s, v5.4s }, [x8]
+; CHECK-IADISABLED-NEXT: ldp q0, q3, [sp, #32]
+; CHECK-IADISABLED-NEXT: ldp q2, q1, [sp, #64]
+; CHECK-IADISABLED-NEXT: ldp q4, q5, [sp]
+; CHECK-IADISABLED-NEXT: stp q0, q3, [x0, #32]
+; CHECK-IADISABLED-NEXT: stp q2, q1, [x0, #64]
+; CHECK-IADISABLED-NEXT: stp q4, q5, [x0]
+; CHECK-IADISABLED-NEXT: add sp, sp, #96
+; CHECK-IADISABLED-NEXT: ret
+ %v0 = load <8 x i32>, ptr %input0, align 4
+ %v1 = load <8 x i32>, ptr %input1, align 4
+ %v2 = load <8 x i32>, ptr %input2, align 4
+ %interleave = call <24 x i32> @llvm.vector.interleave3.v24i32(<8 x i32> %v0, <8 x i32> %v1, <8 x i32> %v2)
+ store <24 x i32> %interleave, ptr %output, align 4
+ ret void
+}
+
+define void @wide_vector_interleave_st4(ptr %output, ptr %input0, ptr %input1, ptr %input2, ptr %input3) {
+; CHECK-IAENABLED-LABEL: wide_vector_interleave_st4:
+; CHECK-IAENABLED: // %bb.0:
+; CHECK-IAENABLED-NEXT: ldp q0, q4, [x1]
+; CHECK-IAENABLED-NEXT: ldp q1, q5, [x2]
+; CHECK-IAENABLED-NEXT: ldp q2, q6, [x3]
+; CHECK-IAENABLED-NEXT: ldp q3, q7, [x4]
+; CHECK-IAENABLED-NEXT: st4 { v0.4s, v1.4s, v2.4s, v3.4s }, [x0], #64
+; CHECK-IAENABLED-NEXT: st4 { v4.4s, v5.4s, v6.4s, v7.4s }, [x0]
+; CHECK-IAENABLED-NEXT: ret
+;
+; CHECK-IADISABLED-LABEL: wide_vector_interleave_st4:
+; CHECK-IADISABLED: // %bb.0:
+; CHECK-IADISABLED-NEXT: ldp q5, q0, [x2]
+; CHECK-IADISABLED-NEXT: ldp q6, q1, [x3]
+; CHECK-IADISABLED-NEXT: ldp q7, q2, [x4]
+; CHECK-IADISABLED-NEXT: ldp q4, q3, [x1]
+; CHECK-IADISABLED-NEXT: zip2 v16.4s, v0.4s, v2.4s
+; CHECK-IADISABLED-NEXT: zip1 v0.4s, v0.4s, v2.4s
+; CHECK-IADISABLED-NEXT: zip2 v2.4s, v5.4s, v7.4s
+; CHECK-IADISABLED-NEXT: zip2 v17.4s, v3.4s, v1.4s
+; CHECK-IADISABLED-NEXT: zip1 v1.4s, v3.4s, v1.4s
+; CHECK-IADISABLED-NEXT: zip2 v3.4s, v4.4s, v6.4s
+; CHECK-IADISABLED-NEXT: zip1 v5.4s, v5.4s, v7.4s
+; CHECK-IADISABLED-NEXT: zip1 v4.4s, v4.4s, v6.4s
+; CHECK-IADISABLED-NEXT: zip1 v18.4s, v17.4s, v16.4s
+; CHECK-IADISABLED-NEXT: zip2 v16.4s, v17.4s, v16.4s
+; CHECK-IADISABLED-NEXT: zip1 v6.4s, v1.4s, v0.4s
+; CHECK-IADISABLED-NEXT: zip2 v0.4s, v1.4s, v0.4s
+; CHECK-IADISABLED-NEXT: zip1 v1.4s, v3.4s, v2.4s
+; CHECK-IADISABLED-NEXT: zip2 v2.4s, v3.4s, v2.4s
+; CHECK-IADISABLED-NEXT: zip1 v3.4s, v4.4s, v5.4s
+; CHECK-IADISABLED-NEXT: zip2 v4.4s, v4.4s, v5.4s
+; CHECK-IADISABLED-NEXT: stp q18, q16, [x0, #96]
+; CHECK-IADISABLED-NEXT: stp q1, q2, [x0, #32]
+; CHECK-IADISABLED-NEXT: stp q3, q4, [x0]
+; CHECK-IADISABLED-NEXT: stp q6, q0, [x0, #64]
+; CHECK-IADISABLED-NEXT: ret
+ %v0 = load <8 x i32>, ptr %input0, align 4
+ %v1 = load <8 x i32>, ptr %input1, align 4
+ %v2 = load <8 x i32>, ptr %input2, align 4
+ %v3 = load <8 x i32>, ptr %input3, align 4
+ %interleave = call <32 x i32> @llvm.vector.interleave4.v32i32(<8 x i32> %v0, <8 x i32> %v1, <8 x i32> %v2, <8 x i32> %v3)
+ store <32 x i32> %interleave, ptr %output, align 4
+ ret void
+}
+
+define void @wide_vector_interleave_st3_i8(ptr %output, ptr %input0, ptr %input1, ptr %input2) {
+; CHECK-IAENABLED-LABEL: wide_vector_interleave_st3_i8:
+; CHECK-IAENABLED: // %bb.0:
+; CHECK-IAENABLED-NEXT: ldp q0, q3, [x1]
+; CHECK-IAENABLED-NEXT: ldp q1, q4, [x2]
+; CHECK-IAENABLED-NEXT: ldp q2, q5, [x3]
+; CHECK-IAENABLED-NEXT: st3 { v0.16b, v1.16b, v2.16b }, [x0], #48
+; CHECK-IAENABLED-NEXT: st3 { v3.16b, v4.16b, v5.16b }, [x0]
+; CHECK-IAENABLED-NEXT: ret
+;
+; CHECK-IADISABLED-LABEL: wide_vector_interleave_st3_i8:
+; CHECK-IADISABLED: // %bb.0:
+; CHECK-IADISABLED-NEXT: sub sp, sp, #96
+; CHECK-IADISABLED-NEXT: .cfi_def_cfa_offset 96
+; CHECK-IADISABLED-NEXT: ldp q0, q3, [x1]
+; CHECK-IADISABLED-NEXT: mov x8, sp
+; CHECK-IADISABLED-NEXT: ldp q1, q4, [x2]
+; CHECK-IADISABLED-NEXT: ldp q2, q5, [x3]
+; CHECK-IADISABLED-NEXT: st3 { v0.16b, v1.16b, v2.16b }, [x8]
+; CHECK-IADISABLED-NEXT: add x8, sp, #48
+; CHECK-IADISABLED-NEXT: st3 { v3.16b, v4.16b, v5.16b }, [x8]
+; CHECK-IADISABLED-NEXT: ldp q0, q3, [sp, #32]
+; CHECK-IADISABLED-NEXT: ldp q2, q1, [sp, #64]
+; CHECK-IADISABLED-NEXT: ldp q4, q5, [sp]
+; CHECK-IADISABLED-NEXT: stp q0, q3, [x0, #32]
+; CHECK-IADISABLED-NEXT: stp q2, q1, [x0, #64]
+; CHECK-IADISABLED-NEXT: stp q4, q5, [x0]
+; CHECK-IADISABLED-NEXT: add sp, sp, #96
+; CHECK-IADISABLED-NEXT: ret
+ %v0 = load <32 x i8>, ptr %input0, align 1
+ %v1 = load <32 x i8>, ptr %input1, align 1
+ %v2 = load <32 x i8>, ptr %input2, align 1
+ %interleave = call <96 x i8> @llvm.vector.interleave3.v96i8(<32 x i8> %v0, <32 x i8> %v1, <32 x i8> %v2)
+ store <96 x i8> %interleave, ptr %output, align 1
+ ret void
+}
+
+define void @wide_vector_interleave_st4_i8(ptr %output, ptr %input0, ptr %input1, ptr %input2, ptr %input3) {
+; CHECK-IAENABLED-LABEL: wide_vector_interleave_st4_i8:
+; CHECK-IAENABLED: // %bb.0:
+; CHECK-IAENABLED-NEXT: ldp q0, q4, [x1]
+; CHECK-IAENABLED-NEXT: ldp q1, q5, [x2]
+; CHECK-IAENABLED-NEXT: ldp q2, q6, [x3]
+; CHECK-IAENABLED-NEXT: ldp q3, q7, [x4]
+; CHECK-IAENABLED-NEXT: st4 { v0.16b, v1.16b, v2.16b, v3.16b }, [x0], #64
+; CHECK-IAENABLED-NEXT: st4 { v4.16b, v5.16b, v6.16b, v7.16b }, [x0]
+; CHECK-IAENABLED-NEXT: ret
+;
+; CHECK-IADISABLED-LABEL: wide_vector_interleave_st4_i8:
+; CHECK-IADISABLED: // %bb.0:
+; CHECK-IADISABLED-NEXT: ldp q5, q0, [x2]
+; CHECK-IADISABLED-NEXT: ldp q6, q1, [x3]
+; CHECK-IADISABLED-NEXT: ldp q7, q2, [x4]
+; CHECK-IADISABLED-NEXT: ldp q4, q3, [x1]
+; CHECK-IADISABLED-NEXT: zip2 v16.16b, v0.16b, v2.16b
+; CHECK-IADISABLED-NEXT: zip1 v0.16b, v0.16b, v2.16b
+; CHECK-IADISABLED-NEXT: zip2 v2.16b, v5.16b, v7.16b
+; CHECK-IADISABLED-NEXT: zip2 v17.16b, v3.16b, v1.16b
+; CHECK-IADISABLED-NEXT: zip1 v1.16b, v3.16b, v1.16b
+; CHECK-IADISABLED-NEXT: zip2 v3.16b, v4.16b, v6.16b
+; CHECK-IADISABLED-NEXT: zip1 v5.16b, v5.16b, v7.16b
+; CHECK-IADISABLED-NEXT: zip1 v4.16b, v4.16b, v6.16b
+; CHECK-IADISABLED-NEXT: zip1 v18.16b, v17.16b, v16.16b
+; CHECK-IADISABLED-NEXT: zip2 v16.16b, v17.16b, v16.16b
+; CHECK-IADISABLED-NEXT: zip1 v6.16b, v1.16b, v0.16b
+; CHECK-IADISABLED-NEXT: zip2 v0.16b, v1.16b, v0.16b
+; CHECK-IADISABLED-NEXT: zip1 v1.16b, v3.16b, v2.16b
+; CHECK-IADISABLED-NEXT: zip2 v2.16b, v3.16b, v2.16b
+; CHECK-IADISABLED-NEXT: zip1 v3.16b, v4.16b, v5.16b
+; CHECK-IADISABLED-NEXT: zip2 v4.16b, v4.16b, v5.16b
+; CHECK-IADISABLED-NEXT: stp q18, q16, [x0, #96]
+; CHECK-IADISABLED-NEXT: stp q1, q2, [x0, #32]
+; CHECK-IADISABLED-NEXT: stp q3, q4, [x0]
+; CHECK-IADISABLED-NEXT: stp q6, q0, [x0, #64]
+; CHECK-IADISABLED-NEXT: ret
+ %v0 = load <32 x i8>, ptr %input0, align 1
+ %v1 = load <32 x i8>, ptr %input1, align 1
+ %v2 = load <32 x i8>, ptr %input2, align 1
+ %v3 = load <32 x i8>, ptr %input3, align 1
+ %interleave = call <128 x i8> @llvm.vector.interleave4.v128i8(<32 x i8> %v0, <32 x i8> %v1, <32 x i8> %v2, <32 x i8> %v3)
+ store <128 x i8> %interleave, ptr %output, align 1
+ ret void
+}
+
+define void @wide_vector_interleave_st3_i16(ptr %output, ptr %input0, ptr %input1, ptr %input2) {
+; CHECK-IAENABLED-LABEL: wide_vector_interleave_st3_i16:
+; CHECK-IAENABLED: // %bb.0:
+; CHECK-IAENABLED-NEXT: ldp q0, q3, [x1]
+; CHECK-IAENABLED-NEXT: ldp q1, q4, [x2]
+; CHECK-IAENABLED-NEXT: ldp q2, q5, [x3]
+; CHECK-IAENABLED-NEXT: st3 { v0.8h, v1.8h, v2.8h }, [x0], #48
+; CHECK-IAENABLED-NEXT: st3 { v3.8h, v4.8h, v5.8h }, [x0]
+; CHECK-IAENABLED-NEXT: ret
+;
+; CHECK-IADISABLED-LABEL: wide_vector_interleave_st3_i16:
+; CHECK-IADISABLED: // %bb.0:
+; CHECK-IADISABLED-NEXT: sub sp, sp, #96
+; CHECK-IADISABLED-NEXT: .cfi_def_cfa_offset 96
+; CHECK-IADISABLED-NEXT: ldp q0, q3, [x1]
+; CHECK-IADISABLED-NEXT: mov x8, sp
+; CHECK-IADISABLED-NEXT: ldp q1, q4, [x2]
+; CHECK-IADISABLED-NEXT: ldp q2, q5, [x3]
+; CHECK-IADISABLED-NEXT: st3 { v0.8h, v1.8h, v2.8h }, [x8]
+; CHECK-IADISABLED-NEXT: add x8, sp, #48
+; CHECK-IADISABLED-NEXT: st3 { v3.8h, v4.8h, v5.8h }, [x8]
+; CHECK-IADISABLED-NEXT: ldp q0, q3, [sp, #32]
+; CHECK-IADISABLED-NEXT: ldp q2, q1, [sp, #64]
+; CHECK-IADISABLED-NEXT: ldp q4, q5, [sp]
+; CHECK-IADISABLED-NEXT: stp q0, q3, [x0, #32]
+; CHECK-IADISABLED-NEXT: stp q2, q1, [x0, #64]
+; CHECK-IADISABLED-NEXT: stp q4, q5, [x0]
+; CHECK-IADISABLED-NEXT: add sp, sp, #96
+; CHECK-IADISABLED-NEXT: ret
+ %v0 = load <16 x i16>, ptr %input0, align 2
+ %v1 = load <16 x i16>, ptr %input1, align 2
+ %v2 = load <16 x i16>, ptr %input2, align 2
+ %interleave = call <48 x i16> @llvm.vector.interleave3.v48i16(<16 x i16> %v0, <16 x i16> %v1, <16 x i16> %v2)
+ store <48 x i16> %interleave, ptr %output, align 2
+ ret void
+}
+
+define void @wide_vector_interleave_st4_i16(ptr %output, ptr %input0, ptr %input1, ptr %input2, ptr %input3) {
+; CHECK-IAENABLED-LABEL: wide_vector_interleave_st4_i16:
+; CHECK-IAENABLED: // %bb.0:
+; CHECK-IAENABLED-NEXT: ldp q0, q4, [x1]
+; CHECK-IAENABLED-NEXT: ldp q1, q5, [x2]
+; CHECK-IAENABLED-NEXT: ldp q2, q6, [x3]
+; CHECK-IAENABLED-NEXT: ldp q3, q7, [x4]
+; CHECK-IAENABLED-NEXT: st4 { v0.8h, v1.8h, v2.8h, v3.8h }, [x0], #64
+; CHECK-IAENABLED-NEXT: st4 { v4.8h, v5.8h, v6.8h, v7.8h }, [x0]
+; CHECK-IAENABLED-NEXT: ret
+;
+; CHECK-IADISABLED-LABEL: wide_vector_interleave_st4_i16:
+; CHECK-IADISABLED: // %bb.0:
+; CHECK-IADISABLED-NEXT: ldp q5, q0, [x2]
+; CHECK-IADISABLED-NEXT: ldp q6, q1, [x3]
+; CHECK-IADISABLED-NEXT: ldp q7, q2, [x4]
+; CHECK-IADISABLED-NEXT: ldp q4, q3, [x1]
+; CHECK-IADISABLED-NEXT: zip2 v16.8h, v0.8h, v2.8h
+; CHECK-IADISABLED-NEXT: zip1 v0.8h, v0.8h, v2.8h
+; CHECK-IADISABLED-NEXT: zip2 v2.8h, v5.8h, v7.8h
+; CHECK-IADISABLED-NEXT: zip2 v17.8h, v3.8h, v1.8h
+; CHECK-IADISABLED-NEXT: zip1 v1.8h, v3.8h, v1.8h
+; CHECK-IADISABLED-NEXT: zip2 v3.8h, v4.8h, v6.8h
+; CHECK-IADISABLED-NEXT: zip1 v5.8h, v5.8h, v7.8h
+; CHECK-IADISABLED-NEXT: zip1 v4.8h, v4.8h, v6.8h
+; CHECK-IADISABLED-NEXT: zip1 v18.8h, v17.8h, v16.8h
+; CHECK-IADISABLED-NEXT: zip2 v16.8h, v17.8h, v16.8h
+; CHECK-IADISABLED-NEXT: zip1 v6.8h, v1.8h, v0.8h
+; CHECK-IADISABLED-NEXT: zip2 v0.8h, v1.8h, v0.8h
+; CHECK-IADISABLED-NEXT: zip1 v1.8h, v3.8h, v2.8h
+; CHECK-IADISABLED-NEXT: zip2 v2.8h, v3.8h, v2.8h
+; CHECK-IADISABLED-NEXT: zip1 v3.8h, v4.8h, v5.8h
+; CHECK-IADISABLED-NEXT: zip2 v4.8h, v4.8h, v5.8h
+; CHECK-IADISABLED-NEXT: stp q18, q16, [x0, #96]
+; CHECK-IADISABLED-NEXT: stp q1, q2, [x0, #32]
+; CHECK-IADISABLED-NEXT: stp q3, q4, [x0]
+; CHECK-IADISABLED-NEXT: stp q6, q0, [x0, #64]
+; CHECK-IADISABLED-NEXT: ret
+ %v0 = load <16 x i16>, ptr %input0, align 2
+ %v1 = load <16 x i16>, ptr %input1, align 2
+ %v2 = load <16 x i16>, ptr %input2, align 2
+ %v3 = load <16 x i16>, ptr %input3, align 2
+ %interleave = call <64 x i16> @llvm.vector.interleave4.v64i16(<16 x i16> %v0, <16 x i16> %v1, <16 x i16> %v2, <16 x i16> %v3)
+ store <64 x i16> %interleave, ptr %output, align 2
+ ret void
+}
+
+define void @wide_vector_interleave_st3_i64(ptr %output, ptr %input0, ptr %input1, ptr %input2) {
+; CHECK-IAENABLED-LABEL: wide_vector_interleave_st3_i64:
+; CHECK-IAENABLED: // %bb.0:
+; CHECK-IAENABLED-NEXT: ldp q0, q3, [x1]
+; CHECK-IAENABLED-NEXT: ldp q1, q4, [x2]
+; CHECK-IAENABLED-NEXT: ldp q2, q5, [x3]
+; CHECK-IAENABLED-NEXT: st3 { v0.2d, v1.2d, v2.2d }, [x0], #48
+; CHECK-IAENABLED-NEXT: st3 { v3.2d, v4.2d, v5.2d }, [x0]
+; CHECK-IAENABLED-NEXT: ret
+;
+; CHECK-IADISABLED-LABEL: wide_vector_interleave_st3_i64:
+; CHECK-IADISABLED: // %bb.0:
+; CHECK-IADISABLED-NEXT: sub sp, sp, #96
+; CHECK-IADISABLED-NEXT: .cfi_def_cfa_offset 96
+; CHECK-IADISABLED-NEXT: ldp q0, q3, [x1]
+; CHECK-IADISABLED-NEXT: mov x8, sp
+; CHECK-IADISABLED-NEXT: ldp q1, q4, [x2]
+; CHECK-IADISABLED-NEXT: ldp q2, q5, [x3]
+; CHECK-IADISABLED-NEXT: st3 { v0.2d, v1.2d, v2.2d }, [x8]
+; CHECK-IADISABLED-NEXT: add x8, sp, #48
+; CHECK-IADISABLED-NEXT: st3 { v3.2d, v4.2d, v5.2d }, [x8]
+; CHECK-IADISABLED-NEXT: ldp q0, q3, [sp, #32]
+; CHECK-IADISABLED-NEXT: ldp q2, q1, [sp, #64]
+; CHECK-IADISABLED-NEXT: ldp q4, q5, [sp]
+; CHECK-IADISABLED-NEXT: stp q0, q3, [x0, #32]
+; CHECK-IADISABLED-NEXT: stp q2, q1, [x0, #64]
+; CHECK-IADISABLED-NEXT: stp q4, q5, [x0]
+; CHECK-IADISABLED-NEXT: add sp, sp, #96
+; CHECK-IADISABLED-NEXT: ret
+ %v0 = load <4 x i64>, ptr %input0, align 8
+ %v1 = load <4 x i64>, ptr %input1, align 8
+ %v2 = load <4 x i64>, ptr %input2, align 8
+ %interleave = call <12 x i64> @llvm.vector.interleave3.v12i64(<4 x i64> %v0, <4 x i64> %v1, <4 x i64> %v2)
+ store <12 x i64> %interleave, ptr %output, align 8
+ ret void
+}
+
+define void @wide_vector_interleave_st4_i64(ptr %output, ptr %input0, ptr %input1, ptr %input2, ptr %input3) {
+; CHECK-IAENABLED-LABEL: wide_vector_interleave_st4_i64:
+; CHECK-IAENABLED: // %bb.0:
+; CHECK-IAENABLED-NEXT: ldp q0, q4, [x1]
+; CHECK-IAENABLED-NEXT: ldp q1, q5, [x2]
+; CHECK-IAENABLED-NEXT: ldp q2, q6, [x3]
+; CHECK-IAENABLED-NEXT: ldp q3, q7, [x4]
+; CHECK-IAENABLED-NEXT: st4 { v0.2d, v1.2d, v2.2d, v3.2d }, [x0], #64
+; CHECK-IAENABLED-NEXT: st4 { v4.2d, v5.2d, v6.2d, v7.2d }, [x0]
+; CHECK-IAENABLED-NEXT: ret
+;
+; CHECK-IADISABLED-LABEL: wide_vector_interleave_st4_i64:
+; CHECK-IADISABLED: // %bb.0:
+; CHECK-IADISABLED-NEXT: ldp q5, q0, [x2]
+; CHECK-IADISABLED-NEXT: ldp q6, q1, [x3]
+; CHECK-IADISABLED-NEXT: ldp q7, q2, [x4]
+; CHECK-IADISABLED-NEXT: ldp q4, q3, [x1]
+; CHECK-IADISABLED-NEXT: zip2 v16.2d, v0.2d, v2.2d
+; CHECK-IADISABLED-NEXT: zip1 v0.2d, v0.2d, v2.2d
+; CHECK-IADISABLED-NEXT: zip2 v2.2d, v5.2d, v7.2d
+; CHECK-IADISABLED-NEXT: zip2 v17.2d, v3.2d, v1.2d
+; CHECK-IADISABLED-NEXT: zip1 v1.2d, v3.2d, v1.2d
+; CHECK-IADISABLED-NEXT: zip2 v3.2d, v4.2d, v6.2d
+; CHECK-IADISABLED-NEXT: zip1 v5.2d, v5.2d, v7.2d
+; CHECK-IADISABLED-NEXT: zip1 v4.2d, v4.2d, v6.2d
+; CHECK-IADISABLED-NEXT: zip1 v18.2d, v17.2d, v16.2d
+; CHECK-IADISABLED-NEXT: zip2 v16.2d, v17.2d, v16.2d
+; CHECK-IADISABLED-NEXT: zip1 v6.2d, v1.2d, v0.2d
+; CHECK-IADISABLED-NEXT: zip2 v0.2d, v1.2d, v0.2d
+; CHECK-IADISABLED-NEXT: zip1 v1.2d, v3.2d, v2.2d
+; CHECK-IADISABLED-NEXT: zip2 v2.2d, v3.2d, v2.2d
+; CHECK-IADISABLED-NEXT: zip1 v3.2d, v4.2d, v5.2d
+; CHECK-IADISABLED-NEXT: zip2 v4.2d, v4.2d, v5.2d
+; CHECK-IADISABLED-NEXT: stp q18, q16, [x0, #96]
+; CHECK-IADISABLED-NEXT: stp q1, q2, [x0, #32]
+; CHECK-IADISABLED-NEXT: stp q3, q4, [x0]
+; CHECK-IADISABLED-NEXT: stp q6, q0, [x0, #64]
+; CHECK-IADISABLED-NEXT: ret
+ %v0 = load <4 x i64>, ptr %input0, align 8
+ %v1 = load <4 x i64>, ptr %input1, align 8
+ %v2 = load <4 x i64>, ptr %input2, align 8
+ %v3 = load <4 x i64>, ptr %input3, align 8
+ %interleave = call <16 x i64> @llvm.vector.interleave4.v16i64(<4 x i64> %v0, <4 x i64> %v1, <4 x i64> %v2, <4 x i64> %v3)
+ store <16 x i64> %interleave, ptr %output, align 8
+ ret void
+}
+
+define void @wide_vector_interleave_st3_i32_dreg(ptr %output, <6 x i32> %v0, <6 x i32> %v1, <6 x i32> %v2) {
+; CHECK-LABEL: wide_vector_interleave_st3_i32_dreg:
+; CHECK: // %bb.0:
+; CHECK-NEXT: fmov s1, w5
+; CHECK-NEXT: fmov s3, w1
+; CHECK-NEXT: ldr s0, [sp, #56]
+; CHECK-NEXT: add x8, sp, #24
+; CHECK-NEXT: ldr s2, [sp]
+; CHECK-NEXT: add x9, sp, #16
+; CHECK-NEXT: mov v0.s[1], w4
+; CHECK-NEXT: ldr s4, [sp, #32]
+; CHECK-NEXT: ld1 { v1.s }[1], [x8]
+; CHECK-NEXT: add x8, sp, #48
+; CHECK-NEXT: mov v3.s[1], w7
+; CHECK-NEXT: ld1 { v2.s }[1], [x8]
+; CHECK-NEXT: add x8, sp, #72
+; CHECK-NEXT: ld1 { v1.s }[2], [x8]
+; CHECK-NEXT: add x8, sp, #40
+; CHECK-NEXT: ld1 { v0.s }[2], [x9]
+; CHECK-NEXT: mov v2.s[2], w3
+; CHECK-NEXT: ld1 { v3.s }[2], [x8]
+; CHECK-NEXT: add x8, sp, #64
+; CHECK-NEXT: add x9, sp, #80
+; CHECK-NEXT: mov v1.s[3], w6
+; CHECK-NEXT: ld1 { v0.s }[3], [x8]
+; CHECK-NEXT: add x8, sp, #8
+; CHECK-NEXT: mov v3.s[3], w2
+; CHECK-NEXT: ld1 { v4.s }[1], [x9]
+; CHECK-NEXT: ld1 { v2.s }[3], [x8]
+; CHECK-NEXT: str d4, [x0, #64]
+; CHECK-NEXT: stp q3, q2, [x0]
+; CHECK-NEXT: stp q0, q1, [x0, #32]
+; CHECK-NEXT: ret
+ %interleave = call <18 x i32> @llvm.vector.interleave3.v18i32(<6 x i32> %v0, <6 x i32> %v1, <6 x i32> %v2)
+ store <18 x i32> %interleave, ptr %output, align 4
+ ret void
+}
+
+define void @wide_vector_interleave_st4_i32_dreg(ptr %output, <6 x i32> %v0, <6 x i32> %v1, <6 x i32> %v2, <6 x i32> %v3) {
+; CHECK-LABEL: wide_vector_interleave_st4_i32_dreg:
+; CHECK: // %bb.0:
+; CHECK-NEXT: fmov s5, w6
+; CHECK-NEXT: fmov s4, w5
+; CHECK-NEXT: add x9, sp, #32
+; CHECK-NEXT: fmov s1, w2
+; CHECK-NEXT: fmov s3, w4
+; CHECK-NEXT: mov x10, sp
+; CHECK-NEXT: fmov s2, w3
+; CHECK-NEXT: fmov s0, w1
+; CHECK-NEXT: add x11, sp, #24
+; CHECK-NEXT: ld1 { v5.s }[1], [x9]
+; CHECK-NEXT: add x9, sp, #16
+; CHECK-NEXT: ld1 { v4.s }[1], [x11]
+; CHECK-NEXT: ld1 { v1.s }[1], [x10]
+; CHECK-NEXT: add x10, sp, #8
+; CHECK-NEXT: ld1 { v3.s }[1], [x9]
+; CHECK-NEXT: mov v0.s[1], w7
+; CHECK-NEXT: ld1 { v2.s }[1], [x10]
+; CHECK-NEXT: add x10, sp, #72
+; CHECK-NEXT: add x9, sp, #80
+; CHECK-NEXT: add x11, sp, #64
+; CHECK-NEXT: ld1 { v4.s }[2], [x10]
+; CHECK-NEXT: add x10, sp, #56
+; CHECK-NEXT: add x8, sp, #40
+; CHECK-NEXT: ld1 { v5.s }[2], [x9]
+; CHECK-NEXT: add x9, sp, #48
+; CHECK-NEXT: ld1 { v3.s }[2], [x11]
+; CHECK-NEXT: ld1 { v2.s }[2], [x10]
+; CHECK-NEXT: ld1 { v1.s }[2], [x9]
+; CHECK-NEXT: ld1 { v0.s }[2], [x8]
+; CHECK-NEXT: add x9, sp, #112
+; CHECK-NEXT: add x8, sp, #104
+; CHECK-NEXT: add x11, sp, #128
+; CHECK-NEXT: add x10, sp, #120
+; CHECK-NEXT: ld1 { v3.s }[3], [x9]
+; CHECK-NEXT: add x9, sp, #96
+; CHECK-NEXT: ld1 { v2.s }[3], [x8]
+; CHECK-NEXT: add x8, sp, #88
+; CHECK-NEXT: ld1 { v5.s }[3], [x11]
+; CHECK-NEXT: ld1 { v4.s }[3], [x10]
+; CHECK-NEXT: ld1 { v1.s }[3], [x9]
+; CHECK-NEXT: ld1 { v0.s }[3], [x8]
+; CHECK-NEXT: stp q2, q3, [x0, #32]
+; CHECK-NEXT: str q5, [x0, #80]
+; CHECK-NEXT: str q4, [x0, #64]
+; CHECK-NEXT: stp q0, q1, [x0]
+; CHECK-NEXT: ret
+ %interleave = call <24 x i32> @llvm.vector.interleave4.v24i32(<6 x i32> %v0, <6 x i32> %v1, <6 x i32> %v2, <6 x i32> %v3)
+ store <24 x i32> %interleave, ptr %output, align 4
+ ret void
+}
+
+define void @wide_vector_interleave_st3_i16_dreg(ptr %output, ptr %input0, ptr %input1, ptr %input2) {
+; CHECK-LABEL: wide_vector_interleave_st3_i16_dreg:
+; CHECK: // %bb.0:
+; CHECK-NEXT: sub sp, sp, #192
+; CHECK-NEXT: .cfi_def_cfa_offset 192
+; CHECK-NEXT: ldr q0, [x1]
+; CHECK-NEXT: ldr d3, [x1, #16]
+; CHECK-NEXT: mov x8, sp
+; CHECK-NEXT: ldr q1, [x2]
+; CHECK-NEXT: ldr d4, [x2, #16]
+; CHECK-NEXT: ldr q2, [x3]
+; CHECK-NEXT: ldr d5, [x3, #16]
+; CHECK-NEXT: st3 { v0.8h, v1.8h, v2.8h }, [x8]
+; CHECK-NEXT: add x8, sp, #48
+; CHECK-NEXT: st3 { v3.8h, v4.8h, v5.8h }, [x8]
+; CHECK-NEXT: ldr q0, [sp, #32]
+; CHECK-NEXT: dup v1.2d, v0.d[1]
+; CHECK-NEXT: str d1, [sp, #144]
+; CHECK-NEXT: ldr q1, [sp, #64]
+; CHECK-NEXT: ldr q3, [sp, #144]
+; CHECK-NEXT: str d1, [sp, #112]
+; CHECK-NEXT: ldp q2, q1, [sp]
+; CHECK-NEXT: ext v0.16b, v1.16b, v0.16b, #8
+; CHECK-NEXT: mov v1.d[1], v0.d[0]
+; CHECK-NEXT: ext v0.16b, v0.16b, v3.16b, #8
+; CHECK-NEXT: ldr q3, [sp, #48]
+; CHECK-NEXT: stp q2, q1, [x0]
+; CHECK-NEXT: stp q0, q3, [x0, #32]
+; CHECK-NEXT: ldr q0, [sp, #112]
+; CHECK-NEXT: str d0, [x0, #64]
+; CHECK-NEXT: add sp, sp, #192
+; CHECK-NEXT: ret
+ %v0 = load <12 x i16>, ptr %input0, align 2
+ %v1 = load <12 x i16>, ptr %input1, align 2
+ %v2 = load <12 x i16>, ptr %input2, align 2
+ %interleave = call <36 x i16> @llvm.vector.interleave3.v36i16(<12 x i16> %v0, <12 x i16> %v1, <12 x i16> %v2)
+ store <36 x i16> %interleave, ptr %output, align 2
+ ret void
+}
+
+define void @wide_vector_interleave_st4_i16_dreg(ptr %output, ptr %input0, ptr %input1, ptr %input2, ptr %input3) {
+; CHECK-LABEL: wide_vector_interleave_st4_i16_dreg:
+; CHECK: // %bb.0:
+; CHECK-NEXT: sub sp, sp, #128
+; CHECK-NEXT: .cfi_def_cfa_offset 128
+; CHECK-NEXT: ldr q0, [x2]
+; CHECK-NEXT: ldr d1, [x1, #16]
+; CHECK-NEXT: ldr d2, [x2, #16]
+; CHECK-NEXT: ldr d3, [x3, #16]
+; CHECK-NEXT: ldr q4, [x4]
+; CHECK-NEXT: ldr d5, [x4, #16]
+; CHECK-NEXT: ldr q6, [x1]
+; CHECK-NEXT: ldr q7, [x3]
+; CHECK-NEXT: zip1 v2.8h, v2.8h, v5.8h
+; CHECK-NEXT: zip1 v1.8h, v1.8h, v3.8h
+; CHECK-NEXT: zip2 v3.8h, v0.8h, v4.8h
+; CHECK-NEXT: zip2 v5.8h, v6.8h, v7.8h
+; CHECK-NEXT: zip1 v0.8h, v0.8h, v4.8h
+; CHECK-NEXT: zip1 v4.8h, v6.8h, v7.8h
+; CHECK-NEXT: zip2 v6.8h, v1.8h, v2.8h
+; CHECK-NEXT: zip1 v1.8h, v1.8h, v2.8h
+; CHECK-NEXT: zip1 v7.8h, v5.8h, v3.8h
+; CHECK-NEXT: zip2 v16.8h, v4.8h, v0.8h
+; CHECK-NEXT: zip1 v0.8h, v4.8h, v0.8h
+; CHECK-NEXT: zip2 v3.8h, v5.8h, v3.8h
+; CHECK-NEXT: dup v2.2d, v6.d[1]
+; CHECK-NEXT: dup v17.2d, v7.d[1]
+; CHECK-NEXT: ext v7.16b, v16.16b, v7.16b, #8
+; CHECK-NEXT: str d2, [sp, #16]
+; CHECK-NEXT: ext v2.16b, v1.16b, v6.16b, #8
+; CHECK-NEXT: str d17, [sp, #80]
+; CHECK-NEXT: ldr q5, [sp, #16]
+; CHECK-NEXT: mov v16.d[1], v7.d[0]
+; CHECK-NEXT: ldr q4, [sp, #80]
+; CHECK-NEXT: ext v4.16b, v7.16b, v4.16b, #8
+; CHECK-NEXT: mov v1.d[1], v2.d[0]
+; CHECK-NEXT: stp q0, q16, [x0]
+; CHECK-NEXT: ext v0.16b, v2.16b, v5.16b, #8
+; CHECK-NEXT: stp q4, q3, [x0, #32]
+; CHECK-NEXT: stp q1, q0, [x0, #64]
+; CHECK-NEXT: add sp, sp, #128
+; CHECK-NEXT: ret
+ %v0 = load <12 x i16>, ptr %input0, align 2
+ %v1 = load <12 x i16>, ptr %input1, align 2
+ %v2 = load <12 x i16>, ptr %input2, align 2
+ %v3 = load <12 x i16>, ptr %input3, align 2
+ %interleave = call <48 x i16> @llvm.vector.interleave4.v48i16(<12 x i16> %v0, <12 x i16> %v1, <12 x i16> %v2, <12 x i16> %v3)
+ store <48 x i16> %interleave, ptr %output, align 2
+ ret void
+}
+
+define void @wide_vector_interleave_st3_i8_dreg(ptr %output, ptr %input0, ptr %input1, ptr %input2) {
+; CHECK-LABEL: wide_vector_interleave_st3_i8_dreg:
+; CHECK: // %bb.0:
+; CHECK-NEXT: sub sp, sp, #192
+; CHECK-NEXT: .cfi_def_cfa_offset 192
+; CHECK-NEXT: ldr q0, [x1]
+; CHECK-NEXT: ldr d3, [x1, #16]
+; CHECK-NEXT: mov x8, sp
+; CHECK-NEXT: ldr q1, [x2]
+; CHECK-NEXT: ldr d4, [x2, #16]
+; CHECK-NEXT: ldr q2, [x3]
+; CHECK-NEXT: ldr d5, [x3, #16]
+; CHECK-NEXT: st3 { v0.16b, v1.16b, v2.16b }, [x8]
+; CHECK-NEXT: add x8, sp, #48
+; CHECK-NEXT: st3 { v3.16b, v4.16b, v5.16b }, [x8]
+; CHECK-NEXT: ldr q0, [sp, #32]
+; CHECK-NEXT: dup v1.2d, v0.d[1]
+; CHECK-NEXT: str d1, [sp, #144]
+; CHECK-NEXT: ldr q1, [sp, #64]
+; CHECK-NEXT: ldr q3, [sp, #144]
+; CHECK-NEXT: str d1, [sp, #112]
+; CHECK-NEXT: ldp q2, q1, [sp]
+; CHECK-NEXT: ext v0.16b, v1.16b, v0.16b, #8
+; CHECK-NEXT: mov v1.d[1], v0.d[0]
+; CHECK-NEXT: ext v0.16b, v0.16b, v3.16b, #8
+; CHECK-NEXT: ldr q3, [sp, #48]
+; CHECK-NEXT: stp q2, q1, [x0]
+; CHECK-NEXT: stp q0, q3, [x0, #32]
+; CHECK-NEXT: ldr q0, [sp, #112]
+; CHECK-NEXT: str d0, [x0, #64]
+; CHECK-NEXT: add sp, sp, #192
+; CHECK-NEXT: ret
+ %v0 = load <24 x i8>, ptr %input0, align 1
+ %v1 = load <24 x i8>, ptr %input1, align 1
+ %v2 = load <24 x i8>, ptr %input2, align 1
+ %interleave = call <72 x i8> @llvm.vector.interleave3.v72i8(<24 x i8> %v0, <24 x i8> %v1, <24 x i8> %v2)
+ store <72 x i8> %interleave, ptr %output, align 1
+ ret void
+}
+
+define void @wide_vector_interleave_st4_i8_dreg(ptr %output, ptr %input0, ptr %input1, ptr %input2, ptr %input3) {
+; CHECK-LABEL: wide_vector_interleave_st4_i8_dreg:
+; CHECK: // %bb.0:
+; CHECK-NEXT: sub sp, sp, #128
+; CHECK-NEXT: .cfi_def_cfa_offset 128
+; CHECK-NEXT: ldr q0, [x2]
+; CHECK-NEXT: ldr d1, [x1, #16]
+; CHECK-NEXT: ldr d2, [x2, #16]
+; CHECK-NEXT: ldr d3, [x3, #16]
+; CHECK-NEXT: ldr q4, [x4]
+; CHECK-NEXT: ldr d5, [x4, #16]
+; CHECK-NEXT: ldr q6, [x1]
+; CHECK-NEXT: ldr q7, [x3]
+; CHECK-NEXT: zip1 v2.16b, v2.16b, v5.16b
+; CHECK-NEXT: zip1 v1.16b, v1.16b, v3.16b
+; CHECK-NEXT: zip2 v3.16b, v0.16b, v4.16b
+; CHECK-NEXT: zip2 v5.16b, v6.16b, v7.16b
+; CHECK-NEXT: zip1 v0.16b, v0.16b, v4.16b
+; CHECK-NEXT: zip1 v4.16b, v6.16b, v7.16b
+; CHECK-NEXT: zip2 v6.16b, v1.16b, v2.16b
+; CHECK-NEXT: zip1 v1.16b, v1.16b, v2.16b
+; CHECK-NEXT: zip1 v7.16b, v5.16b, v3.16b
+; CHECK-NEXT: zip2 v16.16b, v4.16b, v0.16b
+; CHECK-NEXT: zip1 v0.16b, v4.16b, v0.16b
+; CHECK-NEXT: zip2 v3.16b, v5.16b, v3.16b
+; CHECK-NEXT: dup v2.2d, v6.d[1]
+; CHECK-NEXT: dup v17.2d, v7.d[1]
+; CHECK-NEXT: ext v7.16b, v16.16b, v7.16b, #8
+; CHECK-NEXT: str d2, [sp, #16]
+; CHECK-NEXT: ext v2.16b, v1.16b, v6.16b, #8
+; CHECK-NEXT: str d17, [sp, #80]
+; CHECK-NEXT: ldr q5, [sp, #16]
+; CHECK-NEXT: mov v16.d[1], v7.d[0]
+; CHECK-NEXT: ldr q4, [sp, #80]
+; CHECK-NEXT: ext v4.16b, v7.16b, v4.16b, #8
+; CHECK-NEXT: mov v1.d[1], v2.d[0]
+; CHECK-NEXT: stp q0, q16, [x0]
+; CHECK-NEXT: ext v0.16b, v2.16b, v5.16b, #8
+; CHECK-NEXT: stp q4, q3, [x0, #32]
+; CHECK-NEXT: stp q1, q0, [x0, #64]
+; CHECK-NEXT: add sp, sp, #128
+; CHECK-NEXT: ret
+ %v0 = load <24 x i8>, ptr %input0, align 1
+ %v1 = load <24 x i8>, ptr %input1, align 1
+ %v2 = load <24 x i8>, ptr %input2, align 1
+ %v3 = load <24 x i8>, ptr %input3, align 1
+ %interleave = call <96 x i8> @llvm.vector.interleave4.v96i8(<24 x i8> %v0, <24 x i8> %v1, <24 x i8> %v2, <24 x i8> %v3)
+ store <96 x i8> %interleave, ptr %output, align 1
+ ret void
+}
>From fd19361ea201aa55aa3dd605b3f61d81f047c0be Mon Sep 17 00:00:00 2001
From: Kamlesh Kumar <kamlesh.kumar at arm.com>
Date: Wed, 2 Sep 2026 17:35:57 +0100
Subject: [PATCH 2/3] perform the dag combine after the type legalization
---
llvm/include/llvm/CodeGen/SelectionDAG.h | 7 +
.../lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 38 +-
.../Target/AArch64/AArch64ISelLowering.cpp | 71 ++++
.../CodeGen/AArch64/interleaved-accesses.ll | 95 ++---
.../AArch64/vector-interleave-store.ll | 328 ++++--------------
5 files changed, 196 insertions(+), 343 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/SelectionDAG.h b/llvm/include/llvm/CodeGen/SelectionDAG.h
index ccf25e50c9578..ffaed86161421 100644
--- a/llvm/include/llvm/CodeGen/SelectionDAG.h
+++ b/llvm/include/llvm/CodeGen/SelectionDAG.h
@@ -2581,6 +2581,13 @@ class SelectionDAG {
LLVM_ABI bool areNonVolatileConsecutiveLoads(LoadSDNode *LD, LoadSDNode *Base,
unsigned Bytes, int Dist) const;
+ /// Return true if stores are next to each other and can be merged. Check that
+ /// both are nonvolatile and if \p ST is storing \p Bytes bytes to a location
+ /// that is \p Dist units away from the location that \p Base is storing to.
+ LLVM_ABI bool areNonVolatileConsecutiveStores(StoreSDNode *ST,
+ StoreSDNode *Base,
+ unsigned Bytes, int Dist) const;
+
/// Infer alignment of a load / store address. Return std::nullopt if it
/// cannot be inferred.
LLVM_ABI MaybeAlign InferPtrAlign(SDValue Ptr) const;
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 2218e5f59752f..5b4a656ee7a2b 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -14433,32 +14433,46 @@ std::pair<SDValue, SDValue> SelectionDAG::UnrollVectorOverflowOp(
getBuildVector(NewOvVT, dl, OvScalars));
}
-bool SelectionDAG::areNonVolatileConsecutiveLoads(LoadSDNode *LD,
- LoadSDNode *Base,
- unsigned Bytes,
- int Dist) const {
- if (LD->isVolatile() || Base->isVolatile())
+static bool areNonVolatileConsecutiveLoadsOrStores(LSBaseSDNode *LS,
+ LSBaseSDNode *Base,
+ unsigned Bytes, int Dist,
+ const SelectionDAG &DAG) {
+ if (LS->isVolatile() || Base->isVolatile())
return false;
// TODO: probably too restrictive for atomics, revisit
- if (!LD->isSimple())
+ if (!LS->isSimple())
return false;
- if (LD->isIndexed() || Base->isIndexed())
+ if (LS->isIndexed() || Base->isIndexed())
return false;
- if (LD->getChain() != Base->getChain())
+ if (LS->getChain() != Base->getChain())
return false;
- EVT VT = LD->getMemoryVT();
+ EVT VT = LS->getMemoryVT();
if (VT.getSizeInBits() / 8 != Bytes)
return false;
- auto BaseLocDecomp = BaseIndexOffset::match(Base, *this);
- auto LocDecomp = BaseIndexOffset::match(LD, *this);
+ auto BaseLocDecomp = BaseIndexOffset::match(Base, DAG);
+ auto LocDecomp = BaseIndexOffset::match(LS, DAG);
int64_t Offset = 0;
- if (BaseLocDecomp.equalBaseIndex(LocDecomp, *this, Offset))
+ if (BaseLocDecomp.equalBaseIndex(LocDecomp, DAG, Offset))
return (Dist * (int64_t)Bytes == Offset);
return false;
}
+bool SelectionDAG::areNonVolatileConsecutiveLoads(LoadSDNode *LD,
+ LoadSDNode *Base,
+ unsigned Bytes,
+ int Dist) const {
+ return areNonVolatileConsecutiveLoadsOrStores(LD, Base, Bytes, Dist, *this);
+}
+
+bool SelectionDAG::areNonVolatileConsecutiveStores(StoreSDNode *ST,
+ StoreSDNode *Base,
+ unsigned Bytes,
+ int Dist) const {
+ return areNonVolatileConsecutiveLoadsOrStores(ST, Base, Bytes, Dist, *this);
+}
+
/// InferPtrAlignment - Infer alignment of a load / store address. Return
/// std::nullopt if it cannot be inferred.
MaybeAlign SelectionDAG::InferPtrAlign(SDValue Ptr) const {
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index d7fafc6c840c0..906f2f7018b47 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -27807,6 +27807,9 @@ static SDValue
performInterleavedStoreCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI,
SelectionDAG &DAG);
+static SDValue performLegalizedInterleavedStoreCombine(
+ StoreSDNode *ST, TargetLowering::DAGCombinerInfo &DCI, SelectionDAG &DAG);
+
static SDValue performSTORECombine(SDNode *N,
TargetLowering::DAGCombinerInfo &DCI,
SelectionDAG &DAG,
@@ -27841,6 +27844,9 @@ static SDValue performSTORECombine(SDNode *N,
if (SDValue Res = performInterleavedStoreCombine(N, DCI, DAG))
return Res;
+ if (SDValue Res = performLegalizedInterleavedStoreCombine(ST, DCI, DAG))
+ return Res;
+
// Cast ptr32 and ptr64 pointers to the default address space before a store.
unsigned AddrSpace = ST->getAddressSpace();
if (AddrSpace == ARM64AS::PTR64 || AddrSpace == ARM64AS::PTR32_SPTR ||
@@ -28200,6 +28206,71 @@ performInterleavedStoreCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI,
MemN->getMemoryVT(), MemN->getMemOperand());
}
+static SDValue performLegalizedInterleavedStoreCombine(
+ StoreSDNode *ST, TargetLowering::DAGCombinerInfo &DCI, SelectionDAG &DAG) {
+ // Type legalization splits a wide interleaved store into consecutive legal
+ // stores. Combine each group that directly stores all results of a legal
+ // VECTOR_INTERLEAVE into a structured store.
+ if (DCI.getDAGCombineLevel() != AfterLegalizeTypes ||
+ !DAG.getSubtarget<AArch64Subtarget>().isNeonAvailable())
+ return SDValue();
+
+ SDValue StoredValue = ST->getValue();
+ SDNode *Interleave = StoredValue.getNode();
+ if (Interleave->getOpcode() != ISD::VECTOR_INTERLEAVE)
+ return SDValue();
+
+ unsigned NumParts = Interleave->getNumOperands();
+ if (NumParts < 2 || NumParts > 4)
+ return SDValue();
+
+ EVT SubVecTy = Interleave->getValueType(0);
+ const TargetLowering &TLI = DAG.getTargetLoweringInfo();
+ if (!SubVecTy.isFixedLengthVector() || !TLI.isTypeLegal(SubVecTy) ||
+ (!SubVecTy.is64BitVector() && !SubVecTy.is128BitVector()))
+ return SDValue();
+
+ SmallVector<StoreSDNode *, 4> Stores(NumParts, nullptr);
+ for (SDUse &Use : Interleave->uses()) {
+ unsigned ResNo = Use.getResNo();
+ auto *Store = dyn_cast<StoreSDNode>(Use.getUser());
+ if (Stores[ResNo] || !Store)
+ return SDValue();
+ Stores[ResNo] = Store;
+ }
+
+ StoreSDNode *BaseStore = Stores[0];
+ unsigned Bytes = SubVecTy.getStoreSize().getFixedValue();
+ for (auto [Idx, Store] : enumerate(Stores)) {
+ if (!DAG.areNonVolatileConsecutiveStores(Store, BaseStore, Bytes, Idx))
+ return SDValue();
+ }
+
+ static constexpr Intrinsic::ID NEONStores[] = {Intrinsic::aarch64_neon_st2,
+ Intrinsic::aarch64_neon_st3,
+ Intrinsic::aarch64_neon_st4};
+ SDLoc DL(Interleave);
+ SmallVector<SDValue, 8> Ops = {
+ BaseStore->getChain(),
+ DAG.getTargetConstant(NEONStores[NumParts - 2], DL, MVT::i64)};
+ Ops.append(Interleave->op_begin(), Interleave->op_end());
+ Ops.push_back(BaseStore->getBasePtr());
+
+ EVT MemVT = EVT::getVectorVT(
+ *DAG.getContext(), SubVecTy.getVectorElementType(),
+ SubVecTy.getVectorElementCount().multiplyCoefficientBy(NumParts));
+ MachineFunction &MF = DAG.getMachineFunction();
+ MachineMemOperand *MMO =
+ MF.getMachineMemOperand(BaseStore->getMemOperand(), 0, NumParts * Bytes);
+ SDValue NewStore = DAG.getMemIntrinsicNode(
+ ISD::INTRINSIC_VOID, DL, DAG.getVTList(MVT::Other), Ops, MemVT, MMO);
+
+ for (StoreSDNode *Store : Stores)
+ if (Store != ST)
+ DCI.CombineTo(Store, NewStore);
+ return NewStore;
+}
+
static SDValue performMSTORECombine(SDNode *N,
TargetLowering::DAGCombinerInfo &DCI,
SelectionDAG &DAG,
diff --git a/llvm/test/CodeGen/AArch64/interleaved-accesses.ll b/llvm/test/CodeGen/AArch64/interleaved-accesses.ll
index bedce9ec6a86e..2e52b3b373484 100644
--- a/llvm/test/CodeGen/AArch64/interleaved-accesses.ll
+++ b/llvm/test/CodeGen/AArch64/interleaved-accesses.ll
@@ -2331,40 +2331,17 @@ define void @store_factor3_intrinsic(ptr %ptr, <4 x i32> %v0, <4 x i32> %v1, <4
}
define void @store_factor3_wide_intrinsic(ptr %ptr, <8 x i32> %v0, <8 x i32> %v1, <8 x i32> %v2) {
-; NEON-IAENABLED-LABEL: store_factor3_wide_intrinsic:
-; NEON-IAENABLED: // %bb.0:
-; NEON-IAENABLED-NEXT: mov v18.16b, v4.16b
-; NEON-IAENABLED-NEXT: // kill: def $q5 killed $q5 killed $q3_q4_q5 def $q3_q4_q5
-; NEON-IAENABLED-NEXT: mov v17.16b, v2.16b
-; NEON-IAENABLED-NEXT: mov v4.16b, v3.16b
-; NEON-IAENABLED-NEXT: mov v16.16b, v0.16b
-; NEON-IAENABLED-NEXT: mov v3.16b, v1.16b
-; NEON-IAENABLED-NEXT: st3 { v16.4s, v17.4s, v18.4s }, [x0], #48
-; NEON-IAENABLED-NEXT: st3 { v3.4s, v4.4s, v5.4s }, [x0]
-; NEON-IAENABLED-NEXT: ret
-;
-; NEON-IADISABLED-LABEL: store_factor3_wide_intrinsic:
-; NEON-IADISABLED: // %bb.0:
-; NEON-IADISABLED-NEXT: sub sp, sp, #96
-; NEON-IADISABLED-NEXT: .cfi_def_cfa_offset 96
-; NEON-IADISABLED-NEXT: // kill: def $q5 killed $q5 killed $q3_q4_q5 def $q3_q4_q5
-; NEON-IADISABLED-NEXT: mov v18.16b, v4.16b
-; NEON-IADISABLED-NEXT: mov x8, sp
-; NEON-IADISABLED-NEXT: mov v17.16b, v2.16b
-; NEON-IADISABLED-NEXT: mov v4.16b, v3.16b
-; NEON-IADISABLED-NEXT: mov v16.16b, v0.16b
-; NEON-IADISABLED-NEXT: mov v3.16b, v1.16b
-; NEON-IADISABLED-NEXT: st3 { v16.4s, v17.4s, v18.4s }, [x8]
-; NEON-IADISABLED-NEXT: add x8, sp, #48
-; NEON-IADISABLED-NEXT: st3 { v3.4s, v4.4s, v5.4s }, [x8]
-; NEON-IADISABLED-NEXT: ldp q2, q0, [sp, #64]
-; NEON-IADISABLED-NEXT: ldp q5, q1, [sp, #32]
-; NEON-IADISABLED-NEXT: ldp q3, q4, [sp]
-; NEON-IADISABLED-NEXT: stp q2, q0, [x0, #64]
-; NEON-IADISABLED-NEXT: stp q5, q1, [x0, #32]
-; NEON-IADISABLED-NEXT: stp q3, q4, [x0]
-; NEON-IADISABLED-NEXT: add sp, sp, #96
-; NEON-IADISABLED-NEXT: ret
+; NEON-LABEL: store_factor3_wide_intrinsic:
+; NEON: // %bb.0:
+; NEON-NEXT: mov v18.16b, v4.16b
+; NEON-NEXT: // kill: def $q5 killed $q5 killed $q3_q4_q5 def $q3_q4_q5
+; NEON-NEXT: mov v17.16b, v2.16b
+; NEON-NEXT: mov v4.16b, v3.16b
+; NEON-NEXT: mov v16.16b, v0.16b
+; NEON-NEXT: mov v3.16b, v1.16b
+; NEON-NEXT: st3 { v16.4s, v17.4s, v18.4s }, [x0], #48
+; NEON-NEXT: st3 { v3.4s, v4.4s, v5.4s }, [x0]
+; NEON-NEXT: ret
;
; NO_NEON-LABEL: store_factor3_wide_intrinsic:
; NO_NEON: // %bb.0:
@@ -2458,43 +2435,19 @@ define void @store_factor4_intrinsic(ptr %ptr, <4 x i32> %v0, <4 x i32> %v1, <4
}
define void @store_factor4_wide_intrinsic(ptr %ptr, <8 x i32> %v0, <8 x i32> %v1, <8 x i32> %v2, <8 x i32> %v3) {
-; NEON-IAENABLED-LABEL: store_factor4_wide_intrinsic:
-; NEON-IAENABLED: // %bb.0:
-; NEON-IAENABLED-NEXT: // kill: def $q7 killed $q7 killed $q4_q5_q6_q7 def $q4_q5_q6_q7
-; NEON-IAENABLED-NEXT: mov v19.16b, v6.16b
-; NEON-IAENABLED-NEXT: mov v18.16b, v4.16b
-; NEON-IAENABLED-NEXT: mov v6.16b, v5.16b
-; NEON-IAENABLED-NEXT: mov v17.16b, v2.16b
-; NEON-IAENABLED-NEXT: mov v5.16b, v3.16b
-; NEON-IAENABLED-NEXT: mov v16.16b, v0.16b
-; NEON-IAENABLED-NEXT: mov v4.16b, v1.16b
-; NEON-IAENABLED-NEXT: st4 { v16.4s, v17.4s, v18.4s, v19.4s }, [x0], #64
-; NEON-IAENABLED-NEXT: st4 { v4.4s, v5.4s, v6.4s, v7.4s }, [x0]
-; NEON-IAENABLED-NEXT: ret
-;
-; NEON-IADISABLED-LABEL: store_factor4_wide_intrinsic:
-; NEON-IADISABLED: // %bb.0:
-; NEON-IADISABLED-NEXT: zip2 v16.4s, v3.4s, v7.4s
-; NEON-IADISABLED-NEXT: zip2 v17.4s, v1.4s, v5.4s
-; NEON-IADISABLED-NEXT: zip1 v3.4s, v3.4s, v7.4s
-; NEON-IADISABLED-NEXT: zip1 v1.4s, v1.4s, v5.4s
-; NEON-IADISABLED-NEXT: zip2 v5.4s, v2.4s, v6.4s
-; NEON-IADISABLED-NEXT: zip2 v7.4s, v0.4s, v4.4s
-; NEON-IADISABLED-NEXT: zip1 v2.4s, v2.4s, v6.4s
-; NEON-IADISABLED-NEXT: zip1 v0.4s, v0.4s, v4.4s
-; NEON-IADISABLED-NEXT: zip2 v18.4s, v17.4s, v16.4s
-; NEON-IADISABLED-NEXT: zip1 v16.4s, v17.4s, v16.4s
-; NEON-IADISABLED-NEXT: zip2 v4.4s, v1.4s, v3.4s
-; NEON-IADISABLED-NEXT: zip1 v1.4s, v1.4s, v3.4s
-; NEON-IADISABLED-NEXT: zip2 v3.4s, v7.4s, v5.4s
-; NEON-IADISABLED-NEXT: zip1 v5.4s, v7.4s, v5.4s
-; NEON-IADISABLED-NEXT: zip2 v6.4s, v0.4s, v2.4s
-; NEON-IADISABLED-NEXT: zip1 v0.4s, v0.4s, v2.4s
-; NEON-IADISABLED-NEXT: stp q16, q18, [x0, #96]
-; NEON-IADISABLED-NEXT: stp q1, q4, [x0, #64]
-; NEON-IADISABLED-NEXT: stp q0, q6, [x0]
-; NEON-IADISABLED-NEXT: stp q5, q3, [x0, #32]
-; NEON-IADISABLED-NEXT: ret
+; NEON-LABEL: store_factor4_wide_intrinsic:
+; NEON: // %bb.0:
+; NEON-NEXT: // kill: def $q7 killed $q7 killed $q4_q5_q6_q7 def $q4_q5_q6_q7
+; NEON-NEXT: mov v19.16b, v6.16b
+; NEON-NEXT: mov v18.16b, v4.16b
+; NEON-NEXT: mov v6.16b, v5.16b
+; NEON-NEXT: mov v17.16b, v2.16b
+; NEON-NEXT: mov v5.16b, v3.16b
+; NEON-NEXT: mov v16.16b, v0.16b
+; NEON-NEXT: mov v4.16b, v1.16b
+; NEON-NEXT: st4 { v16.4s, v17.4s, v18.4s, v19.4s }, [x0], #64
+; NEON-NEXT: st4 { v4.4s, v5.4s, v6.4s, v7.4s }, [x0]
+; NEON-NEXT: ret
;
; NO_NEON-LABEL: store_factor4_wide_intrinsic:
; NO_NEON: // %bb.0:
diff --git a/llvm/test/CodeGen/AArch64/vector-interleave-store.ll b/llvm/test/CodeGen/AArch64/vector-interleave-store.ll
index 9732dfc246e70..a245990361f3e 100644
--- a/llvm/test/CodeGen/AArch64/vector-interleave-store.ll
+++ b/llvm/test/CodeGen/AArch64/vector-interleave-store.ll
@@ -96,34 +96,14 @@ define void @wide_vector_interleave_st2(ptr %input0, ptr %input1, ptr %output) {
}
define void @wide_vector_interleave_st3(ptr %output, ptr %input0, ptr %input1, ptr %input2) {
-; CHECK-IAENABLED-LABEL: wide_vector_interleave_st3:
-; CHECK-IAENABLED: // %bb.0:
-; CHECK-IAENABLED-NEXT: ldp q0, q3, [x1]
-; CHECK-IAENABLED-NEXT: ldp q1, q4, [x2]
-; CHECK-IAENABLED-NEXT: ldp q2, q5, [x3]
-; CHECK-IAENABLED-NEXT: st3 { v0.4s, v1.4s, v2.4s }, [x0], #48
-; CHECK-IAENABLED-NEXT: st3 { v3.4s, v4.4s, v5.4s }, [x0]
-; CHECK-IAENABLED-NEXT: ret
-;
-; CHECK-IADISABLED-LABEL: wide_vector_interleave_st3:
-; CHECK-IADISABLED: // %bb.0:
-; CHECK-IADISABLED-NEXT: sub sp, sp, #96
-; CHECK-IADISABLED-NEXT: .cfi_def_cfa_offset 96
-; CHECK-IADISABLED-NEXT: ldp q0, q3, [x1]
-; CHECK-IADISABLED-NEXT: mov x8, sp
-; CHECK-IADISABLED-NEXT: ldp q1, q4, [x2]
-; CHECK-IADISABLED-NEXT: ldp q2, q5, [x3]
-; CHECK-IADISABLED-NEXT: st3 { v0.4s, v1.4s, v2.4s }, [x8]
-; CHECK-IADISABLED-NEXT: add x8, sp, #48
-; CHECK-IADISABLED-NEXT: st3 { v3.4s, v4.4s, v5.4s }, [x8]
-; CHECK-IADISABLED-NEXT: ldp q0, q3, [sp, #32]
-; CHECK-IADISABLED-NEXT: ldp q2, q1, [sp, #64]
-; CHECK-IADISABLED-NEXT: ldp q4, q5, [sp]
-; CHECK-IADISABLED-NEXT: stp q0, q3, [x0, #32]
-; CHECK-IADISABLED-NEXT: stp q2, q1, [x0, #64]
-; CHECK-IADISABLED-NEXT: stp q4, q5, [x0]
-; CHECK-IADISABLED-NEXT: add sp, sp, #96
-; CHECK-IADISABLED-NEXT: ret
+; CHECK-LABEL: wide_vector_interleave_st3:
+; CHECK: // %bb.0:
+; CHECK-NEXT: ldp q0, q3, [x1]
+; CHECK-NEXT: ldp q1, q4, [x2]
+; CHECK-NEXT: ldp q2, q5, [x3]
+; CHECK-NEXT: st3 { v0.4s, v1.4s, v2.4s }, [x0], #48
+; CHECK-NEXT: st3 { v3.4s, v4.4s, v5.4s }, [x0]
+; CHECK-NEXT: ret
%v0 = load <8 x i32>, ptr %input0, align 4
%v1 = load <8 x i32>, ptr %input1, align 4
%v2 = load <8 x i32>, ptr %input2, align 4
@@ -133,43 +113,15 @@ define void @wide_vector_interleave_st3(ptr %output, ptr %input0, ptr %input1, p
}
define void @wide_vector_interleave_st4(ptr %output, ptr %input0, ptr %input1, ptr %input2, ptr %input3) {
-; CHECK-IAENABLED-LABEL: wide_vector_interleave_st4:
-; CHECK-IAENABLED: // %bb.0:
-; CHECK-IAENABLED-NEXT: ldp q0, q4, [x1]
-; CHECK-IAENABLED-NEXT: ldp q1, q5, [x2]
-; CHECK-IAENABLED-NEXT: ldp q2, q6, [x3]
-; CHECK-IAENABLED-NEXT: ldp q3, q7, [x4]
-; CHECK-IAENABLED-NEXT: st4 { v0.4s, v1.4s, v2.4s, v3.4s }, [x0], #64
-; CHECK-IAENABLED-NEXT: st4 { v4.4s, v5.4s, v6.4s, v7.4s }, [x0]
-; CHECK-IAENABLED-NEXT: ret
-;
-; CHECK-IADISABLED-LABEL: wide_vector_interleave_st4:
-; CHECK-IADISABLED: // %bb.0:
-; CHECK-IADISABLED-NEXT: ldp q5, q0, [x2]
-; CHECK-IADISABLED-NEXT: ldp q6, q1, [x3]
-; CHECK-IADISABLED-NEXT: ldp q7, q2, [x4]
-; CHECK-IADISABLED-NEXT: ldp q4, q3, [x1]
-; CHECK-IADISABLED-NEXT: zip2 v16.4s, v0.4s, v2.4s
-; CHECK-IADISABLED-NEXT: zip1 v0.4s, v0.4s, v2.4s
-; CHECK-IADISABLED-NEXT: zip2 v2.4s, v5.4s, v7.4s
-; CHECK-IADISABLED-NEXT: zip2 v17.4s, v3.4s, v1.4s
-; CHECK-IADISABLED-NEXT: zip1 v1.4s, v3.4s, v1.4s
-; CHECK-IADISABLED-NEXT: zip2 v3.4s, v4.4s, v6.4s
-; CHECK-IADISABLED-NEXT: zip1 v5.4s, v5.4s, v7.4s
-; CHECK-IADISABLED-NEXT: zip1 v4.4s, v4.4s, v6.4s
-; CHECK-IADISABLED-NEXT: zip1 v18.4s, v17.4s, v16.4s
-; CHECK-IADISABLED-NEXT: zip2 v16.4s, v17.4s, v16.4s
-; CHECK-IADISABLED-NEXT: zip1 v6.4s, v1.4s, v0.4s
-; CHECK-IADISABLED-NEXT: zip2 v0.4s, v1.4s, v0.4s
-; CHECK-IADISABLED-NEXT: zip1 v1.4s, v3.4s, v2.4s
-; CHECK-IADISABLED-NEXT: zip2 v2.4s, v3.4s, v2.4s
-; CHECK-IADISABLED-NEXT: zip1 v3.4s, v4.4s, v5.4s
-; CHECK-IADISABLED-NEXT: zip2 v4.4s, v4.4s, v5.4s
-; CHECK-IADISABLED-NEXT: stp q18, q16, [x0, #96]
-; CHECK-IADISABLED-NEXT: stp q1, q2, [x0, #32]
-; CHECK-IADISABLED-NEXT: stp q3, q4, [x0]
-; CHECK-IADISABLED-NEXT: stp q6, q0, [x0, #64]
-; CHECK-IADISABLED-NEXT: ret
+; CHECK-LABEL: wide_vector_interleave_st4:
+; CHECK: // %bb.0:
+; CHECK-NEXT: ldp q0, q4, [x1]
+; CHECK-NEXT: ldp q1, q5, [x2]
+; CHECK-NEXT: ldp q2, q6, [x3]
+; CHECK-NEXT: ldp q3, q7, [x4]
+; CHECK-NEXT: st4 { v0.4s, v1.4s, v2.4s, v3.4s }, [x0], #64
+; CHECK-NEXT: st4 { v4.4s, v5.4s, v6.4s, v7.4s }, [x0]
+; CHECK-NEXT: ret
%v0 = load <8 x i32>, ptr %input0, align 4
%v1 = load <8 x i32>, ptr %input1, align 4
%v2 = load <8 x i32>, ptr %input2, align 4
@@ -180,34 +132,14 @@ define void @wide_vector_interleave_st4(ptr %output, ptr %input0, ptr %input1, p
}
define void @wide_vector_interleave_st3_i8(ptr %output, ptr %input0, ptr %input1, ptr %input2) {
-; CHECK-IAENABLED-LABEL: wide_vector_interleave_st3_i8:
-; CHECK-IAENABLED: // %bb.0:
-; CHECK-IAENABLED-NEXT: ldp q0, q3, [x1]
-; CHECK-IAENABLED-NEXT: ldp q1, q4, [x2]
-; CHECK-IAENABLED-NEXT: ldp q2, q5, [x3]
-; CHECK-IAENABLED-NEXT: st3 { v0.16b, v1.16b, v2.16b }, [x0], #48
-; CHECK-IAENABLED-NEXT: st3 { v3.16b, v4.16b, v5.16b }, [x0]
-; CHECK-IAENABLED-NEXT: ret
-;
-; CHECK-IADISABLED-LABEL: wide_vector_interleave_st3_i8:
-; CHECK-IADISABLED: // %bb.0:
-; CHECK-IADISABLED-NEXT: sub sp, sp, #96
-; CHECK-IADISABLED-NEXT: .cfi_def_cfa_offset 96
-; CHECK-IADISABLED-NEXT: ldp q0, q3, [x1]
-; CHECK-IADISABLED-NEXT: mov x8, sp
-; CHECK-IADISABLED-NEXT: ldp q1, q4, [x2]
-; CHECK-IADISABLED-NEXT: ldp q2, q5, [x3]
-; CHECK-IADISABLED-NEXT: st3 { v0.16b, v1.16b, v2.16b }, [x8]
-; CHECK-IADISABLED-NEXT: add x8, sp, #48
-; CHECK-IADISABLED-NEXT: st3 { v3.16b, v4.16b, v5.16b }, [x8]
-; CHECK-IADISABLED-NEXT: ldp q0, q3, [sp, #32]
-; CHECK-IADISABLED-NEXT: ldp q2, q1, [sp, #64]
-; CHECK-IADISABLED-NEXT: ldp q4, q5, [sp]
-; CHECK-IADISABLED-NEXT: stp q0, q3, [x0, #32]
-; CHECK-IADISABLED-NEXT: stp q2, q1, [x0, #64]
-; CHECK-IADISABLED-NEXT: stp q4, q5, [x0]
-; CHECK-IADISABLED-NEXT: add sp, sp, #96
-; CHECK-IADISABLED-NEXT: ret
+; CHECK-LABEL: wide_vector_interleave_st3_i8:
+; CHECK: // %bb.0:
+; CHECK-NEXT: ldp q0, q3, [x1]
+; CHECK-NEXT: ldp q1, q4, [x2]
+; CHECK-NEXT: ldp q2, q5, [x3]
+; CHECK-NEXT: st3 { v0.16b, v1.16b, v2.16b }, [x0], #48
+; CHECK-NEXT: st3 { v3.16b, v4.16b, v5.16b }, [x0]
+; CHECK-NEXT: ret
%v0 = load <32 x i8>, ptr %input0, align 1
%v1 = load <32 x i8>, ptr %input1, align 1
%v2 = load <32 x i8>, ptr %input2, align 1
@@ -217,43 +149,15 @@ define void @wide_vector_interleave_st3_i8(ptr %output, ptr %input0, ptr %input1
}
define void @wide_vector_interleave_st4_i8(ptr %output, ptr %input0, ptr %input1, ptr %input2, ptr %input3) {
-; CHECK-IAENABLED-LABEL: wide_vector_interleave_st4_i8:
-; CHECK-IAENABLED: // %bb.0:
-; CHECK-IAENABLED-NEXT: ldp q0, q4, [x1]
-; CHECK-IAENABLED-NEXT: ldp q1, q5, [x2]
-; CHECK-IAENABLED-NEXT: ldp q2, q6, [x3]
-; CHECK-IAENABLED-NEXT: ldp q3, q7, [x4]
-; CHECK-IAENABLED-NEXT: st4 { v0.16b, v1.16b, v2.16b, v3.16b }, [x0], #64
-; CHECK-IAENABLED-NEXT: st4 { v4.16b, v5.16b, v6.16b, v7.16b }, [x0]
-; CHECK-IAENABLED-NEXT: ret
-;
-; CHECK-IADISABLED-LABEL: wide_vector_interleave_st4_i8:
-; CHECK-IADISABLED: // %bb.0:
-; CHECK-IADISABLED-NEXT: ldp q5, q0, [x2]
-; CHECK-IADISABLED-NEXT: ldp q6, q1, [x3]
-; CHECK-IADISABLED-NEXT: ldp q7, q2, [x4]
-; CHECK-IADISABLED-NEXT: ldp q4, q3, [x1]
-; CHECK-IADISABLED-NEXT: zip2 v16.16b, v0.16b, v2.16b
-; CHECK-IADISABLED-NEXT: zip1 v0.16b, v0.16b, v2.16b
-; CHECK-IADISABLED-NEXT: zip2 v2.16b, v5.16b, v7.16b
-; CHECK-IADISABLED-NEXT: zip2 v17.16b, v3.16b, v1.16b
-; CHECK-IADISABLED-NEXT: zip1 v1.16b, v3.16b, v1.16b
-; CHECK-IADISABLED-NEXT: zip2 v3.16b, v4.16b, v6.16b
-; CHECK-IADISABLED-NEXT: zip1 v5.16b, v5.16b, v7.16b
-; CHECK-IADISABLED-NEXT: zip1 v4.16b, v4.16b, v6.16b
-; CHECK-IADISABLED-NEXT: zip1 v18.16b, v17.16b, v16.16b
-; CHECK-IADISABLED-NEXT: zip2 v16.16b, v17.16b, v16.16b
-; CHECK-IADISABLED-NEXT: zip1 v6.16b, v1.16b, v0.16b
-; CHECK-IADISABLED-NEXT: zip2 v0.16b, v1.16b, v0.16b
-; CHECK-IADISABLED-NEXT: zip1 v1.16b, v3.16b, v2.16b
-; CHECK-IADISABLED-NEXT: zip2 v2.16b, v3.16b, v2.16b
-; CHECK-IADISABLED-NEXT: zip1 v3.16b, v4.16b, v5.16b
-; CHECK-IADISABLED-NEXT: zip2 v4.16b, v4.16b, v5.16b
-; CHECK-IADISABLED-NEXT: stp q18, q16, [x0, #96]
-; CHECK-IADISABLED-NEXT: stp q1, q2, [x0, #32]
-; CHECK-IADISABLED-NEXT: stp q3, q4, [x0]
-; CHECK-IADISABLED-NEXT: stp q6, q0, [x0, #64]
-; CHECK-IADISABLED-NEXT: ret
+; CHECK-LABEL: wide_vector_interleave_st4_i8:
+; CHECK: // %bb.0:
+; CHECK-NEXT: ldp q0, q4, [x1]
+; CHECK-NEXT: ldp q1, q5, [x2]
+; CHECK-NEXT: ldp q2, q6, [x3]
+; CHECK-NEXT: ldp q3, q7, [x4]
+; CHECK-NEXT: st4 { v0.16b, v1.16b, v2.16b, v3.16b }, [x0], #64
+; CHECK-NEXT: st4 { v4.16b, v5.16b, v6.16b, v7.16b }, [x0]
+; CHECK-NEXT: ret
%v0 = load <32 x i8>, ptr %input0, align 1
%v1 = load <32 x i8>, ptr %input1, align 1
%v2 = load <32 x i8>, ptr %input2, align 1
@@ -264,34 +168,14 @@ define void @wide_vector_interleave_st4_i8(ptr %output, ptr %input0, ptr %input1
}
define void @wide_vector_interleave_st3_i16(ptr %output, ptr %input0, ptr %input1, ptr %input2) {
-; CHECK-IAENABLED-LABEL: wide_vector_interleave_st3_i16:
-; CHECK-IAENABLED: // %bb.0:
-; CHECK-IAENABLED-NEXT: ldp q0, q3, [x1]
-; CHECK-IAENABLED-NEXT: ldp q1, q4, [x2]
-; CHECK-IAENABLED-NEXT: ldp q2, q5, [x3]
-; CHECK-IAENABLED-NEXT: st3 { v0.8h, v1.8h, v2.8h }, [x0], #48
-; CHECK-IAENABLED-NEXT: st3 { v3.8h, v4.8h, v5.8h }, [x0]
-; CHECK-IAENABLED-NEXT: ret
-;
-; CHECK-IADISABLED-LABEL: wide_vector_interleave_st3_i16:
-; CHECK-IADISABLED: // %bb.0:
-; CHECK-IADISABLED-NEXT: sub sp, sp, #96
-; CHECK-IADISABLED-NEXT: .cfi_def_cfa_offset 96
-; CHECK-IADISABLED-NEXT: ldp q0, q3, [x1]
-; CHECK-IADISABLED-NEXT: mov x8, sp
-; CHECK-IADISABLED-NEXT: ldp q1, q4, [x2]
-; CHECK-IADISABLED-NEXT: ldp q2, q5, [x3]
-; CHECK-IADISABLED-NEXT: st3 { v0.8h, v1.8h, v2.8h }, [x8]
-; CHECK-IADISABLED-NEXT: add x8, sp, #48
-; CHECK-IADISABLED-NEXT: st3 { v3.8h, v4.8h, v5.8h }, [x8]
-; CHECK-IADISABLED-NEXT: ldp q0, q3, [sp, #32]
-; CHECK-IADISABLED-NEXT: ldp q2, q1, [sp, #64]
-; CHECK-IADISABLED-NEXT: ldp q4, q5, [sp]
-; CHECK-IADISABLED-NEXT: stp q0, q3, [x0, #32]
-; CHECK-IADISABLED-NEXT: stp q2, q1, [x0, #64]
-; CHECK-IADISABLED-NEXT: stp q4, q5, [x0]
-; CHECK-IADISABLED-NEXT: add sp, sp, #96
-; CHECK-IADISABLED-NEXT: ret
+; CHECK-LABEL: wide_vector_interleave_st3_i16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: ldp q0, q3, [x1]
+; CHECK-NEXT: ldp q1, q4, [x2]
+; CHECK-NEXT: ldp q2, q5, [x3]
+; CHECK-NEXT: st3 { v0.8h, v1.8h, v2.8h }, [x0], #48
+; CHECK-NEXT: st3 { v3.8h, v4.8h, v5.8h }, [x0]
+; CHECK-NEXT: ret
%v0 = load <16 x i16>, ptr %input0, align 2
%v1 = load <16 x i16>, ptr %input1, align 2
%v2 = load <16 x i16>, ptr %input2, align 2
@@ -301,43 +185,15 @@ define void @wide_vector_interleave_st3_i16(ptr %output, ptr %input0, ptr %input
}
define void @wide_vector_interleave_st4_i16(ptr %output, ptr %input0, ptr %input1, ptr %input2, ptr %input3) {
-; CHECK-IAENABLED-LABEL: wide_vector_interleave_st4_i16:
-; CHECK-IAENABLED: // %bb.0:
-; CHECK-IAENABLED-NEXT: ldp q0, q4, [x1]
-; CHECK-IAENABLED-NEXT: ldp q1, q5, [x2]
-; CHECK-IAENABLED-NEXT: ldp q2, q6, [x3]
-; CHECK-IAENABLED-NEXT: ldp q3, q7, [x4]
-; CHECK-IAENABLED-NEXT: st4 { v0.8h, v1.8h, v2.8h, v3.8h }, [x0], #64
-; CHECK-IAENABLED-NEXT: st4 { v4.8h, v5.8h, v6.8h, v7.8h }, [x0]
-; CHECK-IAENABLED-NEXT: ret
-;
-; CHECK-IADISABLED-LABEL: wide_vector_interleave_st4_i16:
-; CHECK-IADISABLED: // %bb.0:
-; CHECK-IADISABLED-NEXT: ldp q5, q0, [x2]
-; CHECK-IADISABLED-NEXT: ldp q6, q1, [x3]
-; CHECK-IADISABLED-NEXT: ldp q7, q2, [x4]
-; CHECK-IADISABLED-NEXT: ldp q4, q3, [x1]
-; CHECK-IADISABLED-NEXT: zip2 v16.8h, v0.8h, v2.8h
-; CHECK-IADISABLED-NEXT: zip1 v0.8h, v0.8h, v2.8h
-; CHECK-IADISABLED-NEXT: zip2 v2.8h, v5.8h, v7.8h
-; CHECK-IADISABLED-NEXT: zip2 v17.8h, v3.8h, v1.8h
-; CHECK-IADISABLED-NEXT: zip1 v1.8h, v3.8h, v1.8h
-; CHECK-IADISABLED-NEXT: zip2 v3.8h, v4.8h, v6.8h
-; CHECK-IADISABLED-NEXT: zip1 v5.8h, v5.8h, v7.8h
-; CHECK-IADISABLED-NEXT: zip1 v4.8h, v4.8h, v6.8h
-; CHECK-IADISABLED-NEXT: zip1 v18.8h, v17.8h, v16.8h
-; CHECK-IADISABLED-NEXT: zip2 v16.8h, v17.8h, v16.8h
-; CHECK-IADISABLED-NEXT: zip1 v6.8h, v1.8h, v0.8h
-; CHECK-IADISABLED-NEXT: zip2 v0.8h, v1.8h, v0.8h
-; CHECK-IADISABLED-NEXT: zip1 v1.8h, v3.8h, v2.8h
-; CHECK-IADISABLED-NEXT: zip2 v2.8h, v3.8h, v2.8h
-; CHECK-IADISABLED-NEXT: zip1 v3.8h, v4.8h, v5.8h
-; CHECK-IADISABLED-NEXT: zip2 v4.8h, v4.8h, v5.8h
-; CHECK-IADISABLED-NEXT: stp q18, q16, [x0, #96]
-; CHECK-IADISABLED-NEXT: stp q1, q2, [x0, #32]
-; CHECK-IADISABLED-NEXT: stp q3, q4, [x0]
-; CHECK-IADISABLED-NEXT: stp q6, q0, [x0, #64]
-; CHECK-IADISABLED-NEXT: ret
+; CHECK-LABEL: wide_vector_interleave_st4_i16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: ldp q0, q4, [x1]
+; CHECK-NEXT: ldp q1, q5, [x2]
+; CHECK-NEXT: ldp q2, q6, [x3]
+; CHECK-NEXT: ldp q3, q7, [x4]
+; CHECK-NEXT: st4 { v0.8h, v1.8h, v2.8h, v3.8h }, [x0], #64
+; CHECK-NEXT: st4 { v4.8h, v5.8h, v6.8h, v7.8h }, [x0]
+; CHECK-NEXT: ret
%v0 = load <16 x i16>, ptr %input0, align 2
%v1 = load <16 x i16>, ptr %input1, align 2
%v2 = load <16 x i16>, ptr %input2, align 2
@@ -348,34 +204,14 @@ define void @wide_vector_interleave_st4_i16(ptr %output, ptr %input0, ptr %input
}
define void @wide_vector_interleave_st3_i64(ptr %output, ptr %input0, ptr %input1, ptr %input2) {
-; CHECK-IAENABLED-LABEL: wide_vector_interleave_st3_i64:
-; CHECK-IAENABLED: // %bb.0:
-; CHECK-IAENABLED-NEXT: ldp q0, q3, [x1]
-; CHECK-IAENABLED-NEXT: ldp q1, q4, [x2]
-; CHECK-IAENABLED-NEXT: ldp q2, q5, [x3]
-; CHECK-IAENABLED-NEXT: st3 { v0.2d, v1.2d, v2.2d }, [x0], #48
-; CHECK-IAENABLED-NEXT: st3 { v3.2d, v4.2d, v5.2d }, [x0]
-; CHECK-IAENABLED-NEXT: ret
-;
-; CHECK-IADISABLED-LABEL: wide_vector_interleave_st3_i64:
-; CHECK-IADISABLED: // %bb.0:
-; CHECK-IADISABLED-NEXT: sub sp, sp, #96
-; CHECK-IADISABLED-NEXT: .cfi_def_cfa_offset 96
-; CHECK-IADISABLED-NEXT: ldp q0, q3, [x1]
-; CHECK-IADISABLED-NEXT: mov x8, sp
-; CHECK-IADISABLED-NEXT: ldp q1, q4, [x2]
-; CHECK-IADISABLED-NEXT: ldp q2, q5, [x3]
-; CHECK-IADISABLED-NEXT: st3 { v0.2d, v1.2d, v2.2d }, [x8]
-; CHECK-IADISABLED-NEXT: add x8, sp, #48
-; CHECK-IADISABLED-NEXT: st3 { v3.2d, v4.2d, v5.2d }, [x8]
-; CHECK-IADISABLED-NEXT: ldp q0, q3, [sp, #32]
-; CHECK-IADISABLED-NEXT: ldp q2, q1, [sp, #64]
-; CHECK-IADISABLED-NEXT: ldp q4, q5, [sp]
-; CHECK-IADISABLED-NEXT: stp q0, q3, [x0, #32]
-; CHECK-IADISABLED-NEXT: stp q2, q1, [x0, #64]
-; CHECK-IADISABLED-NEXT: stp q4, q5, [x0]
-; CHECK-IADISABLED-NEXT: add sp, sp, #96
-; CHECK-IADISABLED-NEXT: ret
+; CHECK-LABEL: wide_vector_interleave_st3_i64:
+; CHECK: // %bb.0:
+; CHECK-NEXT: ldp q0, q3, [x1]
+; CHECK-NEXT: ldp q1, q4, [x2]
+; CHECK-NEXT: ldp q2, q5, [x3]
+; CHECK-NEXT: st3 { v0.2d, v1.2d, v2.2d }, [x0], #48
+; CHECK-NEXT: st3 { v3.2d, v4.2d, v5.2d }, [x0]
+; CHECK-NEXT: ret
%v0 = load <4 x i64>, ptr %input0, align 8
%v1 = load <4 x i64>, ptr %input1, align 8
%v2 = load <4 x i64>, ptr %input2, align 8
@@ -385,43 +221,15 @@ define void @wide_vector_interleave_st3_i64(ptr %output, ptr %input0, ptr %input
}
define void @wide_vector_interleave_st4_i64(ptr %output, ptr %input0, ptr %input1, ptr %input2, ptr %input3) {
-; CHECK-IAENABLED-LABEL: wide_vector_interleave_st4_i64:
-; CHECK-IAENABLED: // %bb.0:
-; CHECK-IAENABLED-NEXT: ldp q0, q4, [x1]
-; CHECK-IAENABLED-NEXT: ldp q1, q5, [x2]
-; CHECK-IAENABLED-NEXT: ldp q2, q6, [x3]
-; CHECK-IAENABLED-NEXT: ldp q3, q7, [x4]
-; CHECK-IAENABLED-NEXT: st4 { v0.2d, v1.2d, v2.2d, v3.2d }, [x0], #64
-; CHECK-IAENABLED-NEXT: st4 { v4.2d, v5.2d, v6.2d, v7.2d }, [x0]
-; CHECK-IAENABLED-NEXT: ret
-;
-; CHECK-IADISABLED-LABEL: wide_vector_interleave_st4_i64:
-; CHECK-IADISABLED: // %bb.0:
-; CHECK-IADISABLED-NEXT: ldp q5, q0, [x2]
-; CHECK-IADISABLED-NEXT: ldp q6, q1, [x3]
-; CHECK-IADISABLED-NEXT: ldp q7, q2, [x4]
-; CHECK-IADISABLED-NEXT: ldp q4, q3, [x1]
-; CHECK-IADISABLED-NEXT: zip2 v16.2d, v0.2d, v2.2d
-; CHECK-IADISABLED-NEXT: zip1 v0.2d, v0.2d, v2.2d
-; CHECK-IADISABLED-NEXT: zip2 v2.2d, v5.2d, v7.2d
-; CHECK-IADISABLED-NEXT: zip2 v17.2d, v3.2d, v1.2d
-; CHECK-IADISABLED-NEXT: zip1 v1.2d, v3.2d, v1.2d
-; CHECK-IADISABLED-NEXT: zip2 v3.2d, v4.2d, v6.2d
-; CHECK-IADISABLED-NEXT: zip1 v5.2d, v5.2d, v7.2d
-; CHECK-IADISABLED-NEXT: zip1 v4.2d, v4.2d, v6.2d
-; CHECK-IADISABLED-NEXT: zip1 v18.2d, v17.2d, v16.2d
-; CHECK-IADISABLED-NEXT: zip2 v16.2d, v17.2d, v16.2d
-; CHECK-IADISABLED-NEXT: zip1 v6.2d, v1.2d, v0.2d
-; CHECK-IADISABLED-NEXT: zip2 v0.2d, v1.2d, v0.2d
-; CHECK-IADISABLED-NEXT: zip1 v1.2d, v3.2d, v2.2d
-; CHECK-IADISABLED-NEXT: zip2 v2.2d, v3.2d, v2.2d
-; CHECK-IADISABLED-NEXT: zip1 v3.2d, v4.2d, v5.2d
-; CHECK-IADISABLED-NEXT: zip2 v4.2d, v4.2d, v5.2d
-; CHECK-IADISABLED-NEXT: stp q18, q16, [x0, #96]
-; CHECK-IADISABLED-NEXT: stp q1, q2, [x0, #32]
-; CHECK-IADISABLED-NEXT: stp q3, q4, [x0]
-; CHECK-IADISABLED-NEXT: stp q6, q0, [x0, #64]
-; CHECK-IADISABLED-NEXT: ret
+; CHECK-LABEL: wide_vector_interleave_st4_i64:
+; CHECK: // %bb.0:
+; CHECK-NEXT: ldp q0, q4, [x1]
+; CHECK-NEXT: ldp q1, q5, [x2]
+; CHECK-NEXT: ldp q2, q6, [x3]
+; CHECK-NEXT: ldp q3, q7, [x4]
+; CHECK-NEXT: st4 { v0.2d, v1.2d, v2.2d, v3.2d }, [x0], #64
+; CHECK-NEXT: st4 { v4.2d, v5.2d, v6.2d, v7.2d }, [x0]
+; CHECK-NEXT: ret
%v0 = load <4 x i64>, ptr %input0, align 8
%v1 = load <4 x i64>, ptr %input1, align 8
%v2 = load <4 x i64>, ptr %input2, align 8
>From 9ae463402d89ac1ee7f42248a55cf16ee96c6b5e Mon Sep 17 00:00:00 2001
From: Kamlesh Kumar <kamlesh.kumar at arm.com>
Date: Thu, 3 Sep 2026 15:10:54 +0000
Subject: [PATCH 3/3] fixup address comments
---
.../Target/AArch64/AArch64ISelLowering.cpp | 15 ++++++------
.../AArch64/vector-interleave-store.ll | 23 +++++++++++++++++++
2 files changed, 31 insertions(+), 7 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 906f2f7018b47..bb0c2aa0052eb 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -28211,7 +28211,7 @@ static SDValue performLegalizedInterleavedStoreCombine(
// Type legalization splits a wide interleaved store into consecutive legal
// stores. Combine each group that directly stores all results of a legal
// VECTOR_INTERLEAVE into a structured store.
- if (DCI.getDAGCombineLevel() != AfterLegalizeTypes ||
+ if (DCI.getDAGCombineLevel() < AfterLegalizeTypes ||
!DAG.getSubtarget<AArch64Subtarget>().isNeonAvailable())
return SDValue();
@@ -28225,9 +28225,7 @@ static SDValue performLegalizedInterleavedStoreCombine(
return SDValue();
EVT SubVecTy = Interleave->getValueType(0);
- const TargetLowering &TLI = DAG.getTargetLoweringInfo();
- if (!SubVecTy.isFixedLengthVector() || !TLI.isTypeLegal(SubVecTy) ||
- (!SubVecTy.is64BitVector() && !SubVecTy.is128BitVector()))
+ if (!SubVecTy.is64BitVector() && !SubVecTy.is128BitVector())
return SDValue();
SmallVector<StoreSDNode *, 4> Stores(NumParts, nullptr);
@@ -28239,6 +28237,9 @@ static SDValue performLegalizedInterleavedStoreCombine(
Stores[ResNo] = Store;
}
+ if (llvm::is_contained(Stores, nullptr))
+ return SDValue();
+
StoreSDNode *BaseStore = Stores[0];
unsigned Bytes = SubVecTy.getStoreSize().getFixedValue();
for (auto [Idx, Store] : enumerate(Stores)) {
@@ -28256,9 +28257,9 @@ static SDValue performLegalizedInterleavedStoreCombine(
Ops.append(Interleave->op_begin(), Interleave->op_end());
Ops.push_back(BaseStore->getBasePtr());
- EVT MemVT = EVT::getVectorVT(
- *DAG.getContext(), SubVecTy.getVectorElementType(),
- SubVecTy.getVectorElementCount().multiplyCoefficientBy(NumParts));
+ EVT MemVT =
+ EVT::getVectorVT(*DAG.getContext(), SubVecTy.getVectorElementType(),
+ SubVecTy.getVectorElementCount() * NumParts);
MachineFunction &MF = DAG.getMachineFunction();
MachineMemOperand *MMO =
MF.getMachineMemOperand(BaseStore->getMemOperand(), 0, NumParts * Bytes);
diff --git a/llvm/test/CodeGen/AArch64/vector-interleave-store.ll b/llvm/test/CodeGen/AArch64/vector-interleave-store.ll
index a245990361f3e..e720275dc242e 100644
--- a/llvm/test/CodeGen/AArch64/vector-interleave-store.ll
+++ b/llvm/test/CodeGen/AArch64/vector-interleave-store.ll
@@ -112,6 +112,29 @@ define void @wide_vector_interleave_st3(ptr %output, ptr %input0, ptr %input1, p
ret void
}
+define void @wide_vector_interleave_missing_stores(ptr %output, ptr %input0, ptr %input1, ptr %input2) {
+; CHECK-LABEL: wide_vector_interleave_missing_stores:
+; CHECK: // %bb.0:
+; CHECK-NEXT: sub sp, sp, #48
+; CHECK-NEXT: .cfi_def_cfa_offset 48
+; CHECK-NEXT: ldr q0, [x1, #16]
+; CHECK-NEXT: mov x8, sp
+; CHECK-NEXT: ldr q1, [x2, #16]
+; CHECK-NEXT: ldr q2, [x3, #16]
+; CHECK-NEXT: st3 { v0.4s, v1.4s, v2.4s }, [x8]
+; CHECK-NEXT: ldp q1, q0, [sp, #16]
+; CHECK-NEXT: stp q1, q0, [x0]
+; CHECK-NEXT: add sp, sp, #48
+; CHECK-NEXT: ret
+ %v0 = load <8 x i32>, ptr %input0, align 4
+ %v1 = load <8 x i32>, ptr %input1, align 4
+ %v2 = load <8 x i32>, ptr %input2, align 4
+ %interleave = call <24 x i32> @llvm.vector.interleave3.v24i32(<8 x i32> %v0, <8 x i32> %v1, <8 x i32> %v2)
+ %part = call <8 x i32> @llvm.vector.extract.v8i32.v24i32(<24 x i32> %interleave, i64 16)
+ store <8 x i32> %part, ptr %output, align 4
+ ret void
+}
+
define void @wide_vector_interleave_st4(ptr %output, ptr %input0, ptr %input1, ptr %input2, ptr %input3) {
; CHECK-LABEL: wide_vector_interleave_st4:
; CHECK: // %bb.0:
More information about the llvm-commits
mailing list