[llvm] [AArch64][GlobalISel] Create zip in shuffle(v, undefined) situations (PR #219226)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 27 08:58:50 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-aarch64
Author: Joshua Rodriguez (JoshdRod)
<details>
<summary>Changes</summary>
In SDAG, the aarch64-isel phase checks if vector shuffles can be expressed as a zips. To do this, it checks shuffles of type shuffle(v, v), and shuffle(v, undefined).
GlobalISel previously only checked shuffles of type shuffle(v, v). Add a check for the situation where one of the operands in undefined.
Notes:
A zip interleaves two vectors together.
e.g: `zip <A, B, C, D>, <1, 2, 3, 4> => <A, 1, B, 2, C, 3, D, 4>`.
A zip1 takes the bottom half of the result.
e.g: `zip1 <A, B, C, D>, <1, 2, 3, 4> => <A, 1, B, 2>`.
A shuffle is an LLVM IR generic opcode that takes 2 vectors, and places elements of each into a single vector. The elements are selected based on a mask.
e.g: `G_SHUFFLE_VECTOR <A, B, C, D>, <E, F, G, H>, <0, 4, 6, 3> => <A, E, G, D>`.
A shuffle can be represented as a zip when the result of the shuffle is just an interleaving of the two vectors.
e.g: `G_SHUFFLE_VECTOR <A, B, C, D>, <A, B, C, D>, <0, 4, 1, 5> => zip1 <A, B, C, D>`.
---
Full diff: https://github.com/llvm/llvm-project/pull/219226.diff
3 Files Affected:
- (modified) llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerLowering.cpp (+21-1)
- (modified) llvm/test/CodeGen/AArch64/arm64-neon-aba-abd.ll (+24-53)
- (modified) llvm/test/CodeGen/AArch64/arm64-zip.ll (+19-28)
``````````diff
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerLowering.cpp b/llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerLowering.cpp
index 53c150d13e3fa..f7e18a16a08d3 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerLowering.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerLowering.cpp
@@ -226,6 +226,25 @@ bool matchUZP(MachineInstr &MI, MachineRegisterInfo &MRI,
return true;
}
+/// isZIP_v_undef_Mask - Special case of isZIPMask for canonical form of
+/// "vector_shuffle v, v", i.e., "vector_shuffle v, undef".
+/// Mask is e.g., <0, 0, 1, 1> instead of <0, 4, 1, 5>.
+static bool isZIP_v_undef_Mask(ArrayRef<int> M, unsigned NumElts,
+ unsigned &WhichResult) {
+ if (NumElts % 2 != 0)
+ return false;
+ WhichResult = (M[0] == 0 ? 0 : 1);
+ unsigned Idx = WhichResult * NumElts / 2;
+ for (unsigned i = 0; i != NumElts; i += 2) {
+ if ((M[i] >= 0 && (unsigned)M[i] != Idx) ||
+ (M[i + 1] >= 0 && (unsigned)M[i + 1] != Idx))
+ return false;
+ Idx += 1;
+ }
+
+ return true;
+}
+
bool matchZip(MachineInstr &MI, MachineRegisterInfo &MRI,
ShuffleVectorPseudo &MatchInfo) {
assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
@@ -234,7 +253,8 @@ bool matchZip(MachineInstr &MI, MachineRegisterInfo &MRI,
ArrayRef<int> ShuffleMask = MI.getOperand(3).getShuffleMask();
Register Dst = MI.getOperand(0).getReg();
unsigned NumElts = MRI.getType(Dst).getNumElements();
- if (!isZIPMask(ShuffleMask, NumElts, WhichResult, OperandOrder))
+ if (!isZIPMask(ShuffleMask, NumElts, WhichResult, OperandOrder) &&
+ !isZIP_v_undef_Mask(ShuffleMask, NumElts, WhichResult))
return false;
unsigned Opc = (WhichResult == 0) ? AArch64::G_ZIP1 : AArch64::G_ZIP2;
Register V1 = MI.getOperand(OperandOrder == 0 ? 1 : 2).getReg();
diff --git a/llvm/test/CodeGen/AArch64/arm64-neon-aba-abd.ll b/llvm/test/CodeGen/AArch64/arm64-neon-aba-abd.ll
index e6f2d4248084f..8adf687b8e20d 100644
--- a/llvm/test/CodeGen/AArch64/arm64-neon-aba-abd.ll
+++ b/llvm/test/CodeGen/AArch64/arm64-neon-aba-abd.ll
@@ -503,27 +503,15 @@ define <4 x i32> @test_sabd_knownbits_vec4i32(<4 x i32> %lhs, <4 x i32> %rhs) {
}
define <4 x i32> @knownbits_sabd_and_mask(<4 x i32> %a0, <4 x i32> %a1) {
-; CHECK-SD-LABEL: knownbits_sabd_and_mask:
-; CHECK-SD: // %bb.0:
-; CHECK-SD-NEXT: adrp x8, .LCPI44_0
-; CHECK-SD-NEXT: ldr q2, [x8, :lo12:.LCPI44_0]
-; CHECK-SD-NEXT: and v0.16b, v0.16b, v2.16b
-; CHECK-SD-NEXT: and v1.16b, v1.16b, v2.16b
-; CHECK-SD-NEXT: sabd v0.4s, v0.4s, v1.4s
-; CHECK-SD-NEXT: zip2 v0.4s, v0.4s, v0.4s
-; CHECK-SD-NEXT: ret
-;
-; CHECK-GI-LABEL: knownbits_sabd_and_mask:
-; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: adrp x8, .LCPI44_1
-; CHECK-GI-NEXT: ldr q2, [x8, :lo12:.LCPI44_1]
-; CHECK-GI-NEXT: adrp x8, .LCPI44_0
-; CHECK-GI-NEXT: and v0.16b, v0.16b, v2.16b
-; CHECK-GI-NEXT: and v1.16b, v1.16b, v2.16b
-; CHECK-GI-NEXT: sabd v0.4s, v0.4s, v1.4s
-; CHECK-GI-NEXT: ldr q1, [x8, :lo12:.LCPI44_0]
-; CHECK-GI-NEXT: tbl v0.16b, { v0.16b }, v1.16b
-; CHECK-GI-NEXT: ret
+; CHECK-LABEL: knownbits_sabd_and_mask:
+; CHECK: // %bb.0:
+; CHECK-NEXT: adrp x8, .LCPI44_0
+; CHECK-NEXT: ldr q2, [x8, :lo12:.LCPI44_0]
+; CHECK-NEXT: and v0.16b, v0.16b, v2.16b
+; CHECK-NEXT: and v1.16b, v1.16b, v2.16b
+; CHECK-NEXT: sabd v0.4s, v0.4s, v1.4s
+; CHECK-NEXT: zip2 v0.4s, v0.4s, v0.4s
+; CHECK-NEXT: ret
%1 = and <4 x i32> %a0, <i32 -1, i32 -1, i32 255, i32 4085>
%2 = and <4 x i32> %a1, <i32 -1, i32 -1, i32 255, i32 4085>
%3 = call <4 x i32> @llvm.aarch64.neon.sabd.v4i32(<4 x i32> %1, <4 x i32> %2)
@@ -539,17 +527,15 @@ define <4 x i32> @knownbits_sabd_and_or_mask(<4 x i32> %a0, <4 x i32> %a1) {
;
; CHECK-GI-LABEL: knownbits_sabd_and_or_mask:
; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: adrp x8, .LCPI45_1
-; CHECK-GI-NEXT: movi v3.2d, #0x00ffff0000ffff
-; CHECK-GI-NEXT: ldr q2, [x8, :lo12:.LCPI45_1]
; CHECK-GI-NEXT: adrp x8, .LCPI45_0
+; CHECK-GI-NEXT: movi v3.2d, #0x00ffff0000ffff
+; CHECK-GI-NEXT: ldr q2, [x8, :lo12:.LCPI45_0]
; CHECK-GI-NEXT: and v0.16b, v0.16b, v2.16b
; CHECK-GI-NEXT: and v1.16b, v1.16b, v2.16b
; CHECK-GI-NEXT: orr v0.16b, v0.16b, v3.16b
; CHECK-GI-NEXT: orr v1.16b, v1.16b, v3.16b
; CHECK-GI-NEXT: uabd v0.4s, v0.4s, v1.4s
-; CHECK-GI-NEXT: ldr q1, [x8, :lo12:.LCPI45_0]
-; CHECK-GI-NEXT: tbl v0.16b, { v0.16b }, v1.16b
+; CHECK-GI-NEXT: zip2 v0.4s, v0.4s, v0.4s
; CHECK-GI-NEXT: ret
%1 = and <4 x i32> %a0, <i32 -1, i32 -1, i32 255, i32 4085>
%2 = or <4 x i32> %1, <i32 65535, i32 65535, i32 65535, i32 65535>
@@ -561,33 +547,18 @@ define <4 x i32> @knownbits_sabd_and_or_mask(<4 x i32> %a0, <4 x i32> %a1) {
}
define <4 x i32> @knownbits_sabd_and_xor_mask(<4 x i32> %a0, <4 x i32> %a1) {
-; CHECK-SD-LABEL: knownbits_sabd_and_xor_mask:
-; CHECK-SD: // %bb.0:
-; CHECK-SD-NEXT: adrp x8, .LCPI46_0
-; CHECK-SD-NEXT: movi v3.2d, #0x00ffff0000ffff
-; CHECK-SD-NEXT: ldr q2, [x8, :lo12:.LCPI46_0]
-; CHECK-SD-NEXT: and v0.16b, v0.16b, v2.16b
-; CHECK-SD-NEXT: and v1.16b, v1.16b, v2.16b
-; CHECK-SD-NEXT: eor v0.16b, v0.16b, v3.16b
-; CHECK-SD-NEXT: eor v1.16b, v1.16b, v3.16b
-; CHECK-SD-NEXT: sabd v0.4s, v0.4s, v1.4s
-; CHECK-SD-NEXT: zip2 v0.4s, v0.4s, v0.4s
-; CHECK-SD-NEXT: ret
-;
-; CHECK-GI-LABEL: knownbits_sabd_and_xor_mask:
-; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: adrp x8, .LCPI46_1
-; CHECK-GI-NEXT: movi v3.2d, #0x00ffff0000ffff
-; CHECK-GI-NEXT: ldr q2, [x8, :lo12:.LCPI46_1]
-; CHECK-GI-NEXT: adrp x8, .LCPI46_0
-; CHECK-GI-NEXT: and v0.16b, v0.16b, v2.16b
-; CHECK-GI-NEXT: and v1.16b, v1.16b, v2.16b
-; CHECK-GI-NEXT: eor v0.16b, v0.16b, v3.16b
-; CHECK-GI-NEXT: eor v1.16b, v1.16b, v3.16b
-; CHECK-GI-NEXT: sabd v0.4s, v0.4s, v1.4s
-; CHECK-GI-NEXT: ldr q1, [x8, :lo12:.LCPI46_0]
-; CHECK-GI-NEXT: tbl v0.16b, { v0.16b }, v1.16b
-; CHECK-GI-NEXT: ret
+; CHECK-LABEL: knownbits_sabd_and_xor_mask:
+; CHECK: // %bb.0:
+; CHECK-NEXT: adrp x8, .LCPI46_0
+; CHECK-NEXT: movi v3.2d, #0x00ffff0000ffff
+; CHECK-NEXT: ldr q2, [x8, :lo12:.LCPI46_0]
+; CHECK-NEXT: and v0.16b, v0.16b, v2.16b
+; CHECK-NEXT: and v1.16b, v1.16b, v2.16b
+; CHECK-NEXT: eor v0.16b, v0.16b, v3.16b
+; CHECK-NEXT: eor v1.16b, v1.16b, v3.16b
+; CHECK-NEXT: sabd v0.4s, v0.4s, v1.4s
+; CHECK-NEXT: zip2 v0.4s, v0.4s, v0.4s
+; CHECK-NEXT: ret
%1 = and <4 x i32> %a0, <i32 -1, i32 -1, i32 255, i32 4085>
%2 = xor <4 x i32> %1, <i32 65535, i32 65535, i32 65535, i32 65535>
%3 = and <4 x i32> %a1, <i32 -1, i32 -1, i32 255, i32 4085>
diff --git a/llvm/test/CodeGen/AArch64/arm64-zip.ll b/llvm/test/CodeGen/AArch64/arm64-zip.ll
index bf017686ecc22..b8e6feacaa2cf 100644
--- a/llvm/test/CodeGen/AArch64/arm64-zip.ll
+++ b/llvm/test/CodeGen/AArch64/arm64-zip.ll
@@ -391,23 +391,20 @@ define <4 x float> @shuffle_zip1(<4 x float> %arg) {
; CHECK-GI-LABEL: shuffle_zip1:
; CHECK-GI: // %bb.0: // %bb
; CHECK-GI-NEXT: fcmgt.4s v0, v0, #0.0
-; CHECK-GI-NEXT: fmov.4s v2, #1.00000000
-; CHECK-GI-NEXT: mov.s w8, v0[1]
-; CHECK-GI-NEXT: mov.s w9, v0[2]
-; CHECK-GI-NEXT: mov.s w10, v0[3]
-; CHECK-GI-NEXT: mov.b v0[1], w8
-; CHECK-GI-NEXT: adrp x8, .LCPI27_1
-; CHECK-GI-NEXT: ldr d1, [x8, :lo12:.LCPI27_1]
; CHECK-GI-NEXT: adrp x8, .LCPI27_0
-; CHECK-GI-NEXT: mov.b v0[2], w9
-; CHECK-GI-NEXT: mov.b v0[3], w10
+; CHECK-GI-NEXT: fmov.4s v2, #1.00000000
+; CHECK-GI-NEXT: ldr d1, [x8, :lo12:.LCPI27_0]
+; CHECK-GI-NEXT: mov.s w9, v0[1]
+; CHECK-GI-NEXT: mov.s w10, v0[2]
+; CHECK-GI-NEXT: mov.s w11, v0[3]
+; CHECK-GI-NEXT: mov.b v0[1], w9
+; CHECK-GI-NEXT: mov.b v0[2], w10
+; CHECK-GI-NEXT: mov.b v0[3], w11
; CHECK-GI-NEXT: mov.d v0[1], v0[0]
; CHECK-GI-NEXT: tbl.16b v0, { v0 }, v1
; CHECK-GI-NEXT: mov.b v1[0], v0[0]
; CHECK-GI-NEXT: mov.b v1[1], v0[1]
-; CHECK-GI-NEXT: mov.d v1[1], v0[0]
-; CHECK-GI-NEXT: ldr d0, [x8, :lo12:.LCPI27_0]
-; CHECK-GI-NEXT: tbl.16b v0, { v1 }, v0
+; CHECK-GI-NEXT: zip1.8b v0, v0, v1
; CHECK-GI-NEXT: umov.b w8, v0[0]
; CHECK-GI-NEXT: umov.b w9, v0[1]
; CHECK-GI-NEXT: fmov s1, w8
@@ -451,18 +448,15 @@ define <4 x i32> @shuffle_zip2(<4 x i32> %arg) {
; CHECK-GI-NEXT: mov.s w9, v0[2]
; CHECK-GI-NEXT: mov.s w10, v0[3]
; CHECK-GI-NEXT: mov.b v0[1], w8
-; CHECK-GI-NEXT: adrp x8, .LCPI28_1
-; CHECK-GI-NEXT: ldr d1, [x8, :lo12:.LCPI28_1]
; CHECK-GI-NEXT: adrp x8, .LCPI28_0
+; CHECK-GI-NEXT: ldr d1, [x8, :lo12:.LCPI28_0]
; CHECK-GI-NEXT: mov.b v0[2], w9
; CHECK-GI-NEXT: mov.b v0[3], w10
; CHECK-GI-NEXT: mov.d v0[1], v0[0]
; CHECK-GI-NEXT: tbl.16b v0, { v0 }, v1
; CHECK-GI-NEXT: mov.b v1[0], v0[0]
; CHECK-GI-NEXT: mov.b v1[1], v0[1]
-; CHECK-GI-NEXT: mov.d v1[1], v0[0]
-; CHECK-GI-NEXT: ldr d0, [x8, :lo12:.LCPI28_0]
-; CHECK-GI-NEXT: tbl.16b v0, { v1 }, v0
+; CHECK-GI-NEXT: zip1.8b v0, v0, v1
; CHECK-GI-NEXT: umov.b w8, v0[0]
; CHECK-GI-NEXT: umov.b w9, v0[1]
; CHECK-GI-NEXT: fmov s1, w8
@@ -501,22 +495,19 @@ define <4 x i32> @shuffle_zip3(<4 x i32> %arg) {
; CHECK-GI-LABEL: shuffle_zip3:
; CHECK-GI: // %bb.0: // %bb
; CHECK-GI-NEXT: cmgt.4s v0, v0, #0
-; CHECK-GI-NEXT: mov.s w8, v0[1]
-; CHECK-GI-NEXT: mov.s w9, v0[2]
-; CHECK-GI-NEXT: mov.s w10, v0[3]
-; CHECK-GI-NEXT: mov.b v0[1], w8
-; CHECK-GI-NEXT: adrp x8, .LCPI29_1
-; CHECK-GI-NEXT: ldr d1, [x8, :lo12:.LCPI29_1]
; CHECK-GI-NEXT: adrp x8, .LCPI29_0
-; CHECK-GI-NEXT: mov.b v0[2], w9
-; CHECK-GI-NEXT: mov.b v0[3], w10
+; CHECK-GI-NEXT: ldr d1, [x8, :lo12:.LCPI29_0]
+; CHECK-GI-NEXT: mov.s w9, v0[1]
+; CHECK-GI-NEXT: mov.s w10, v0[2]
+; CHECK-GI-NEXT: mov.s w11, v0[3]
+; CHECK-GI-NEXT: mov.b v0[1], w9
+; CHECK-GI-NEXT: mov.b v0[2], w10
+; CHECK-GI-NEXT: mov.b v0[3], w11
; CHECK-GI-NEXT: mov.d v0[1], v0[0]
; CHECK-GI-NEXT: tbl.16b v0, { v0 }, v1
; CHECK-GI-NEXT: mov.b v1[0], v0[0]
; CHECK-GI-NEXT: mov.b v1[1], v0[1]
-; CHECK-GI-NEXT: mov.d v1[1], v0[0]
-; CHECK-GI-NEXT: ldr d0, [x8, :lo12:.LCPI29_0]
-; CHECK-GI-NEXT: tbl.16b v0, { v1 }, v0
+; CHECK-GI-NEXT: zip1.8b v0, v0, v1
; CHECK-GI-NEXT: umov.b w8, v0[0]
; CHECK-GI-NEXT: umov.b w9, v0[1]
; CHECK-GI-NEXT: fmov s1, w8
``````````
</details>
https://github.com/llvm/llvm-project/pull/219226
More information about the llvm-commits
mailing list