[llvm] [AArch64] Lower extends of boolean vector loads via scalar load (PR #203394)
Weiwen He via llvm-commits
llvm-commits at lists.llvm.org
Thu Jun 11 13:49:48 PDT 2026
https://github.com/he-weiwen created https://github.com/llvm/llvm-project/pull/203394
Replace a `load <N x i1>` under a sext/zext with a scalar load + bitcast, so the `combineToExtendBoolVectorInReg` helper can apply, avoiding scalarization.
Optimisation for the SVE case with a predicate load to be added in a follow up.
Fixes #200325
>From de4ec955aad4dcfe8be3484908d4772609b0360d Mon Sep 17 00:00:00 2001
From: Weiwen He <he.weiwen at outlook.com>
Date: Thu, 11 Jun 2026 19:13:16 +0100
Subject: [PATCH 1/2] [AArch64] Add tests for extending boolean vector loads
(NFC)
---
.../AArch64/extend-bool-vector-load.ll | 354 ++++++++++++++++++
1 file changed, 354 insertions(+)
create mode 100644 llvm/test/CodeGen/AArch64/extend-bool-vector-load.ll
diff --git a/llvm/test/CodeGen/AArch64/extend-bool-vector-load.ll b/llvm/test/CodeGen/AArch64/extend-bool-vector-load.ll
new file mode 100644
index 0000000000000..e4e757069d9e1
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/extend-bool-vector-load.ll
@@ -0,0 +1,354 @@
+; 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-LE
+; RUN: llc -mtriple=aarch64_be-linux-gnu < %s | FileCheck %s --check-prefixes=CHECK,CHECK-BE
+
+define <16 x i8> @sext_v16i1_v16i8(ptr %p) {
+; CHECK-LE-LABEL: sext_v16i1_v16i8:
+; CHECK-LE: // %bb.0:
+; CHECK-LE-NEXT: ldrh w8, [x0]
+; CHECK-LE-NEXT: sbfx w9, w8, #0, #1
+; CHECK-LE-NEXT: sbfx w10, w8, #1, #1
+; CHECK-LE-NEXT: fmov s0, w9
+; CHECK-LE-NEXT: sbfx w9, w8, #2, #1
+; CHECK-LE-NEXT: mov v0.b[1], w10
+; CHECK-LE-NEXT: mov v0.b[2], w9
+; CHECK-LE-NEXT: sbfx w9, w8, #3, #1
+; CHECK-LE-NEXT: mov v0.b[3], w9
+; CHECK-LE-NEXT: sbfx w9, w8, #4, #1
+; CHECK-LE-NEXT: mov v0.b[4], w9
+; CHECK-LE-NEXT: sbfx w9, w8, #5, #1
+; CHECK-LE-NEXT: mov v0.b[5], w9
+; CHECK-LE-NEXT: sbfx w9, w8, #6, #1
+; CHECK-LE-NEXT: mov v0.b[6], w9
+; CHECK-LE-NEXT: sbfx w9, w8, #7, #1
+; CHECK-LE-NEXT: mov v0.b[7], w9
+; CHECK-LE-NEXT: sbfx w9, w8, #8, #1
+; CHECK-LE-NEXT: mov v0.b[8], w9
+; CHECK-LE-NEXT: sbfx w9, w8, #9, #1
+; CHECK-LE-NEXT: mov v0.b[9], w9
+; CHECK-LE-NEXT: sbfx w9, w8, #10, #1
+; CHECK-LE-NEXT: mov v0.b[10], w9
+; CHECK-LE-NEXT: sbfx w9, w8, #11, #1
+; CHECK-LE-NEXT: mov v0.b[11], w9
+; CHECK-LE-NEXT: sbfx w9, w8, #12, #1
+; CHECK-LE-NEXT: mov v0.b[12], w9
+; CHECK-LE-NEXT: sbfx w9, w8, #13, #1
+; CHECK-LE-NEXT: mov v0.b[13], w9
+; CHECK-LE-NEXT: sbfx w9, w8, #14, #1
+; CHECK-LE-NEXT: sbfx w8, w8, #15, #1
+; CHECK-LE-NEXT: mov v0.b[14], w9
+; CHECK-LE-NEXT: mov v0.b[15], w8
+; CHECK-LE-NEXT: ret
+;
+; CHECK-BE-LABEL: sext_v16i1_v16i8:
+; CHECK-BE: // %bb.0:
+; CHECK-BE-NEXT: ldrh w8, [x0]
+; CHECK-BE-NEXT: sbfx w9, w8, #15, #1
+; CHECK-BE-NEXT: sbfx w10, w8, #14, #1
+; CHECK-BE-NEXT: fmov s0, w9
+; CHECK-BE-NEXT: sbfx w9, w8, #13, #1
+; CHECK-BE-NEXT: mov v0.b[1], w10
+; CHECK-BE-NEXT: mov v0.b[2], w9
+; CHECK-BE-NEXT: sbfx w9, w8, #12, #1
+; CHECK-BE-NEXT: mov v0.b[3], w9
+; CHECK-BE-NEXT: sbfx w9, w8, #11, #1
+; CHECK-BE-NEXT: mov v0.b[4], w9
+; CHECK-BE-NEXT: sbfx w9, w8, #10, #1
+; CHECK-BE-NEXT: mov v0.b[5], w9
+; CHECK-BE-NEXT: sbfx w9, w8, #9, #1
+; CHECK-BE-NEXT: mov v0.b[6], w9
+; CHECK-BE-NEXT: sbfx w9, w8, #8, #1
+; CHECK-BE-NEXT: mov v0.b[7], w9
+; CHECK-BE-NEXT: sbfx w9, w8, #7, #1
+; CHECK-BE-NEXT: mov v0.b[8], w9
+; CHECK-BE-NEXT: sbfx w9, w8, #6, #1
+; CHECK-BE-NEXT: mov v0.b[9], w9
+; CHECK-BE-NEXT: sbfx w9, w8, #5, #1
+; CHECK-BE-NEXT: mov v0.b[10], w9
+; CHECK-BE-NEXT: sbfx w9, w8, #4, #1
+; CHECK-BE-NEXT: mov v0.b[11], w9
+; CHECK-BE-NEXT: sbfx w9, w8, #3, #1
+; CHECK-BE-NEXT: mov v0.b[12], w9
+; CHECK-BE-NEXT: sbfx w9, w8, #2, #1
+; CHECK-BE-NEXT: mov v0.b[13], w9
+; CHECK-BE-NEXT: sbfx w9, w8, #1, #1
+; CHECK-BE-NEXT: sbfx w8, w8, #0, #1
+; CHECK-BE-NEXT: mov v0.b[14], w9
+; CHECK-BE-NEXT: mov v0.b[15], w8
+; CHECK-BE-NEXT: rev64 v0.16b, v0.16b
+; CHECK-BE-NEXT: ext v0.16b, v0.16b, v0.16b, #8
+; CHECK-BE-NEXT: ret
+ %l = load <16 x i1>, ptr %p, align 4
+ %e = sext <16 x i1> %l to <16 x i8>
+ ret <16 x i8> %e
+}
+
+define <16 x i8> @zext_v16i1_v16i8(ptr %p) {
+; CHECK-LE-LABEL: zext_v16i1_v16i8:
+; CHECK-LE: // %bb.0:
+; CHECK-LE-NEXT: ldrh w8, [x0]
+; CHECK-LE-NEXT: and w10, w8, #0x1
+; CHECK-LE-NEXT: ubfx w9, w8, #1, #1
+; CHECK-LE-NEXT: fmov s0, w10
+; CHECK-LE-NEXT: mov v0.b[1], w9
+; CHECK-LE-NEXT: ubfx w9, w8, #2, #1
+; CHECK-LE-NEXT: mov v0.b[2], w9
+; CHECK-LE-NEXT: ubfx w9, w8, #3, #1
+; CHECK-LE-NEXT: mov v0.b[3], w9
+; CHECK-LE-NEXT: ubfx w9, w8, #4, #1
+; CHECK-LE-NEXT: mov v0.b[4], w9
+; CHECK-LE-NEXT: ubfx w9, w8, #5, #1
+; CHECK-LE-NEXT: mov v0.b[5], w9
+; CHECK-LE-NEXT: ubfx w9, w8, #6, #1
+; CHECK-LE-NEXT: mov v0.b[6], w9
+; CHECK-LE-NEXT: ubfx w9, w8, #7, #1
+; CHECK-LE-NEXT: mov v0.b[7], w9
+; CHECK-LE-NEXT: ubfx w9, w8, #8, #1
+; CHECK-LE-NEXT: mov v0.b[8], w9
+; CHECK-LE-NEXT: ubfx w9, w8, #9, #1
+; CHECK-LE-NEXT: mov v0.b[9], w9
+; CHECK-LE-NEXT: ubfx w9, w8, #10, #1
+; CHECK-LE-NEXT: mov v0.b[10], w9
+; CHECK-LE-NEXT: ubfx w9, w8, #11, #1
+; CHECK-LE-NEXT: mov v0.b[11], w9
+; CHECK-LE-NEXT: ubfx w9, w8, #12, #1
+; CHECK-LE-NEXT: mov v0.b[12], w9
+; CHECK-LE-NEXT: ubfx w9, w8, #13, #1
+; CHECK-LE-NEXT: mov v0.b[13], w9
+; CHECK-LE-NEXT: ubfx w9, w8, #14, #1
+; CHECK-LE-NEXT: lsr w8, w8, #15
+; CHECK-LE-NEXT: mov v0.b[14], w9
+; CHECK-LE-NEXT: mov v0.b[15], w8
+; CHECK-LE-NEXT: ret
+;
+; CHECK-BE-LABEL: zext_v16i1_v16i8:
+; CHECK-BE: // %bb.0:
+; CHECK-BE-NEXT: ldrh w8, [x0]
+; CHECK-BE-NEXT: lsr w9, w8, #15
+; CHECK-BE-NEXT: ubfx w10, w8, #14, #1
+; CHECK-BE-NEXT: fmov s0, w9
+; CHECK-BE-NEXT: ubfx w9, w8, #13, #1
+; CHECK-BE-NEXT: mov v0.b[1], w10
+; CHECK-BE-NEXT: mov v0.b[2], w9
+; CHECK-BE-NEXT: ubfx w9, w8, #12, #1
+; CHECK-BE-NEXT: mov v0.b[3], w9
+; CHECK-BE-NEXT: ubfx w9, w8, #11, #1
+; CHECK-BE-NEXT: mov v0.b[4], w9
+; CHECK-BE-NEXT: ubfx w9, w8, #10, #1
+; CHECK-BE-NEXT: mov v0.b[5], w9
+; CHECK-BE-NEXT: ubfx w9, w8, #9, #1
+; CHECK-BE-NEXT: mov v0.b[6], w9
+; CHECK-BE-NEXT: ubfx w9, w8, #8, #1
+; CHECK-BE-NEXT: mov v0.b[7], w9
+; CHECK-BE-NEXT: ubfx w9, w8, #7, #1
+; CHECK-BE-NEXT: mov v0.b[8], w9
+; CHECK-BE-NEXT: ubfx w9, w8, #6, #1
+; CHECK-BE-NEXT: mov v0.b[9], w9
+; CHECK-BE-NEXT: ubfx w9, w8, #5, #1
+; CHECK-BE-NEXT: mov v0.b[10], w9
+; CHECK-BE-NEXT: ubfx w9, w8, #4, #1
+; CHECK-BE-NEXT: mov v0.b[11], w9
+; CHECK-BE-NEXT: ubfx w9, w8, #3, #1
+; CHECK-BE-NEXT: mov v0.b[12], w9
+; CHECK-BE-NEXT: ubfx w9, w8, #2, #1
+; CHECK-BE-NEXT: mov v0.b[13], w9
+; CHECK-BE-NEXT: ubfx w9, w8, #1, #1
+; CHECK-BE-NEXT: and w8, w8, #0x1
+; CHECK-BE-NEXT: mov v0.b[14], w9
+; CHECK-BE-NEXT: mov v0.b[15], w8
+; CHECK-BE-NEXT: rev64 v0.16b, v0.16b
+; CHECK-BE-NEXT: ext v0.16b, v0.16b, v0.16b, #8
+; CHECK-BE-NEXT: ret
+ %l = load <16 x i1>, ptr %p, align 4
+ %e = zext <16 x i1> %l to <16 x i8>
+ ret <16 x i8> %e
+}
+
+define <4 x i32> @sext_v4i1_v4i32(ptr %p) {
+; CHECK-LE-LABEL: sext_v4i1_v4i32:
+; CHECK-LE: // %bb.0:
+; CHECK-LE-NEXT: ldrb w8, [x0]
+; CHECK-LE-NEXT: sbfx w9, w8, #0, #1
+; CHECK-LE-NEXT: sbfx w10, w8, #1, #1
+; CHECK-LE-NEXT: fmov s0, w9
+; CHECK-LE-NEXT: sbfx w9, w8, #2, #1
+; CHECK-LE-NEXT: sbfx w8, w8, #3, #1
+; CHECK-LE-NEXT: mov v0.s[1], w10
+; CHECK-LE-NEXT: mov v0.s[2], w9
+; CHECK-LE-NEXT: mov v0.s[3], w8
+; CHECK-LE-NEXT: ret
+;
+; CHECK-BE-LABEL: sext_v4i1_v4i32:
+; CHECK-BE: // %bb.0:
+; CHECK-BE-NEXT: ldrb w8, [x0]
+; CHECK-BE-NEXT: sbfx w9, w8, #3, #1
+; CHECK-BE-NEXT: sbfx w10, w8, #2, #1
+; CHECK-BE-NEXT: fmov s0, w9
+; CHECK-BE-NEXT: sbfx w9, w8, #1, #1
+; CHECK-BE-NEXT: sbfx w8, w8, #0, #1
+; CHECK-BE-NEXT: mov v0.s[1], w10
+; CHECK-BE-NEXT: mov v0.s[2], w9
+; CHECK-BE-NEXT: mov v0.s[3], w8
+; CHECK-BE-NEXT: rev64 v0.4s, v0.4s
+; CHECK-BE-NEXT: ext v0.16b, v0.16b, v0.16b, #8
+; CHECK-BE-NEXT: ret
+ %l = load <4 x i1>, ptr %p, align 4
+ %e = sext <4 x i1> %l to <4 x i32>
+ ret <4 x i32> %e
+}
+
+define <16 x i8> @sext_v16i1_volatile(ptr %p) {
+; CHECK-LE-LABEL: sext_v16i1_volatile:
+; CHECK-LE: // %bb.0:
+; CHECK-LE-NEXT: ldrh w8, [x0]
+; CHECK-LE-NEXT: and w10, w8, #0x1
+; CHECK-LE-NEXT: ubfx w9, w8, #1, #1
+; CHECK-LE-NEXT: fmov s0, w10
+; CHECK-LE-NEXT: mov v0.b[1], w9
+; CHECK-LE-NEXT: ubfx w9, w8, #2, #1
+; CHECK-LE-NEXT: mov v0.b[2], w9
+; CHECK-LE-NEXT: ubfx w9, w8, #3, #1
+; CHECK-LE-NEXT: mov v0.b[3], w9
+; CHECK-LE-NEXT: ubfx w9, w8, #4, #1
+; CHECK-LE-NEXT: mov v0.b[4], w9
+; CHECK-LE-NEXT: ubfx w9, w8, #5, #1
+; CHECK-LE-NEXT: mov v0.b[5], w9
+; CHECK-LE-NEXT: ubfx w9, w8, #6, #1
+; CHECK-LE-NEXT: mov v0.b[6], w9
+; CHECK-LE-NEXT: ubfx w9, w8, #7, #1
+; CHECK-LE-NEXT: mov v0.b[7], w9
+; CHECK-LE-NEXT: ubfx w9, w8, #8, #1
+; CHECK-LE-NEXT: mov v0.b[8], w9
+; CHECK-LE-NEXT: ubfx w9, w8, #9, #1
+; CHECK-LE-NEXT: mov v0.b[9], w9
+; CHECK-LE-NEXT: ubfx w9, w8, #10, #1
+; CHECK-LE-NEXT: mov v0.b[10], w9
+; CHECK-LE-NEXT: ubfx w9, w8, #11, #1
+; CHECK-LE-NEXT: mov v0.b[11], w9
+; CHECK-LE-NEXT: ubfx w9, w8, #12, #1
+; CHECK-LE-NEXT: mov v0.b[12], w9
+; CHECK-LE-NEXT: ubfx w9, w8, #13, #1
+; CHECK-LE-NEXT: mov v0.b[13], w9
+; CHECK-LE-NEXT: ubfx w9, w8, #14, #1
+; CHECK-LE-NEXT: lsr w8, w8, #15
+; CHECK-LE-NEXT: mov v0.b[14], w9
+; CHECK-LE-NEXT: mov v0.b[15], w8
+; CHECK-LE-NEXT: shl v0.16b, v0.16b, #7
+; CHECK-LE-NEXT: cmlt v0.16b, v0.16b, #0
+; CHECK-LE-NEXT: ret
+;
+; CHECK-BE-LABEL: sext_v16i1_volatile:
+; CHECK-BE: // %bb.0:
+; CHECK-BE-NEXT: ldrh w8, [x0]
+; CHECK-BE-NEXT: lsr w9, w8, #15
+; CHECK-BE-NEXT: ubfx w10, w8, #14, #1
+; CHECK-BE-NEXT: fmov s0, w9
+; CHECK-BE-NEXT: ubfx w9, w8, #13, #1
+; CHECK-BE-NEXT: mov v0.b[1], w10
+; CHECK-BE-NEXT: mov v0.b[2], w9
+; CHECK-BE-NEXT: ubfx w9, w8, #12, #1
+; CHECK-BE-NEXT: mov v0.b[3], w9
+; CHECK-BE-NEXT: ubfx w9, w8, #11, #1
+; CHECK-BE-NEXT: mov v0.b[4], w9
+; CHECK-BE-NEXT: ubfx w9, w8, #10, #1
+; CHECK-BE-NEXT: mov v0.b[5], w9
+; CHECK-BE-NEXT: ubfx w9, w8, #9, #1
+; CHECK-BE-NEXT: mov v0.b[6], w9
+; CHECK-BE-NEXT: ubfx w9, w8, #8, #1
+; CHECK-BE-NEXT: mov v0.b[7], w9
+; CHECK-BE-NEXT: ubfx w9, w8, #7, #1
+; CHECK-BE-NEXT: mov v0.b[8], w9
+; CHECK-BE-NEXT: ubfx w9, w8, #6, #1
+; CHECK-BE-NEXT: mov v0.b[9], w9
+; CHECK-BE-NEXT: ubfx w9, w8, #5, #1
+; CHECK-BE-NEXT: mov v0.b[10], w9
+; CHECK-BE-NEXT: ubfx w9, w8, #4, #1
+; CHECK-BE-NEXT: mov v0.b[11], w9
+; CHECK-BE-NEXT: ubfx w9, w8, #3, #1
+; CHECK-BE-NEXT: mov v0.b[12], w9
+; CHECK-BE-NEXT: ubfx w9, w8, #2, #1
+; CHECK-BE-NEXT: mov v0.b[13], w9
+; CHECK-BE-NEXT: ubfx w9, w8, #1, #1
+; CHECK-BE-NEXT: and w8, w8, #0x1
+; CHECK-BE-NEXT: mov v0.b[14], w9
+; CHECK-BE-NEXT: mov v0.b[15], w8
+; CHECK-BE-NEXT: shl v0.16b, v0.16b, #7
+; CHECK-BE-NEXT: cmlt v0.16b, v0.16b, #0
+; CHECK-BE-NEXT: rev64 v0.16b, v0.16b
+; CHECK-BE-NEXT: ext v0.16b, v0.16b, v0.16b, #8
+; CHECK-BE-NEXT: ret
+ %l = load volatile <16 x i1>, ptr %p, align 4
+ %e = sext <16 x i1> %l to <16 x i8>
+ ret <16 x i8> %e
+}
+
+define <12 x i8> @sext_v12i1_v12i8(ptr %p) {
+; CHECK-LE-LABEL: sext_v12i1_v12i8:
+; CHECK-LE: // %bb.0:
+; CHECK-LE-NEXT: ldrh w8, [x0]
+; CHECK-LE-NEXT: and w10, w8, #0x1
+; CHECK-LE-NEXT: ubfx w9, w8, #1, #1
+; CHECK-LE-NEXT: fmov s0, w10
+; CHECK-LE-NEXT: mov v0.b[1], w9
+; CHECK-LE-NEXT: ubfx w9, w8, #2, #1
+; CHECK-LE-NEXT: mov v0.b[2], w9
+; CHECK-LE-NEXT: ubfx w9, w8, #3, #1
+; CHECK-LE-NEXT: mov v0.b[3], w9
+; CHECK-LE-NEXT: ubfx w9, w8, #4, #1
+; CHECK-LE-NEXT: mov v0.b[4], w9
+; CHECK-LE-NEXT: ubfx w9, w8, #5, #1
+; CHECK-LE-NEXT: mov v0.b[5], w9
+; CHECK-LE-NEXT: ubfx w9, w8, #6, #1
+; CHECK-LE-NEXT: mov v0.b[6], w9
+; CHECK-LE-NEXT: ubfx w9, w8, #7, #1
+; CHECK-LE-NEXT: mov v0.b[7], w9
+; CHECK-LE-NEXT: ubfx w9, w8, #8, #1
+; CHECK-LE-NEXT: mov v0.b[8], w9
+; CHECK-LE-NEXT: ubfx w9, w8, #9, #1
+; CHECK-LE-NEXT: mov v0.b[9], w9
+; CHECK-LE-NEXT: ubfx w9, w8, #10, #1
+; CHECK-LE-NEXT: lsr w8, w8, #11
+; CHECK-LE-NEXT: mov v0.b[10], w9
+; CHECK-LE-NEXT: mov v0.b[11], w8
+; CHECK-LE-NEXT: shl v0.16b, v0.16b, #7
+; CHECK-LE-NEXT: cmlt v0.16b, v0.16b, #0
+; CHECK-LE-NEXT: ret
+;
+; CHECK-BE-LABEL: sext_v12i1_v12i8:
+; CHECK-BE: // %bb.0:
+; CHECK-BE-NEXT: ldrh w8, [x0]
+; CHECK-BE-NEXT: lsr w9, w8, #11
+; CHECK-BE-NEXT: ubfx w10, w8, #10, #1
+; CHECK-BE-NEXT: fmov s0, w9
+; CHECK-BE-NEXT: ubfx w9, w8, #9, #1
+; CHECK-BE-NEXT: mov v0.b[1], w10
+; CHECK-BE-NEXT: mov v0.b[2], w9
+; CHECK-BE-NEXT: ubfx w9, w8, #8, #1
+; CHECK-BE-NEXT: mov v0.b[3], w9
+; CHECK-BE-NEXT: ubfx w9, w8, #7, #1
+; CHECK-BE-NEXT: mov v0.b[4], w9
+; CHECK-BE-NEXT: ubfx w9, w8, #6, #1
+; CHECK-BE-NEXT: mov v0.b[5], w9
+; CHECK-BE-NEXT: ubfx w9, w8, #5, #1
+; CHECK-BE-NEXT: mov v0.b[6], w9
+; CHECK-BE-NEXT: ubfx w9, w8, #4, #1
+; CHECK-BE-NEXT: mov v0.b[7], w9
+; CHECK-BE-NEXT: ubfx w9, w8, #3, #1
+; CHECK-BE-NEXT: mov v0.b[8], w9
+; CHECK-BE-NEXT: ubfx w9, w8, #2, #1
+; CHECK-BE-NEXT: mov v0.b[9], w9
+; CHECK-BE-NEXT: ubfx w9, w8, #1, #1
+; CHECK-BE-NEXT: and w8, w8, #0x1
+; CHECK-BE-NEXT: mov v0.b[10], w9
+; CHECK-BE-NEXT: mov v0.b[11], w8
+; CHECK-BE-NEXT: shl v0.16b, v0.16b, #7
+; CHECK-BE-NEXT: cmlt v0.16b, v0.16b, #0
+; CHECK-BE-NEXT: rev64 v0.16b, v0.16b
+; CHECK-BE-NEXT: ext v0.16b, v0.16b, v0.16b, #8
+; CHECK-BE-NEXT: ret
+ %l = load <12 x i1>, ptr %p, align 4
+ %e = sext <12 x i1> %l to <12 x i8>
+ ret <12 x i8> %e
+}
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK: {{.*}}
>From 383f548db8807aa10d0bbeda35af6f0304952ae5 Mon Sep 17 00:00:00 2001
From: Weiwen He <he.weiwen at outlook.com>
Date: Thu, 11 Jun 2026 21:14:32 +0100
Subject: [PATCH 2/2] [AArch64] Lower extends of boolean vector loads via
scalar load
---
.../Target/AArch64/AArch64ISelLowering.cpp | 47 +++++
.../AArch64/extend-bool-vector-load.ll | 197 +++++-------------
2 files changed, 94 insertions(+), 150 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 57a2d73e00f57..6bc6dbc5ecfbf 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -24852,6 +24852,50 @@ static SDValue performExtendDuplaneTruncCombine(SDNode *N, SelectionDAG &DAG) {
return DAG.getNode(NewDupOpc, SDLoc(N), DstVT, Src, Dup.getOperand(1));
}
+static SDValue
+performExtendToBoolVectorLoadCombine(SDNode *N, SelectionDAG &DAG,
+ TargetLowering::DAGCombinerInfo &DCI,
+ const AArch64Subtarget &Subtarget) {
+ EVT VT = N->getValueType(0);
+ SDValue N0 = N->getOperand(0);
+ auto *LN0 = dyn_cast<LoadSDNode>(N0);
+ // Match an extend of a normal load from a boolean vector (<N x i1>) to a
+ // fixed-length integer vector.
+ if (!LN0 || !ISD::isNormalLoad(LN0) ||
+ N0.getValueType().getScalarType() != MVT::i1 || !VT.isFixedLengthVector())
+ return SDValue();
+
+ // Only fold a load with a single use that is simple (not volatile or atomic),
+ // so it is safe to replace with a scalar load of the same bytes.
+ if (!N0.hasOneUse() || !LN0->isSimple())
+ return SDValue();
+
+ SDLoc DL(N);
+ unsigned NumElts = LN0->getValueType(0).getVectorNumElements();
+ unsigned EltSizeInBits = VT.getScalarSizeInBits();
+ // Load <N x i1> as a scalar iN, then bitcast it back to <N x i1> so the
+ // generic combineToExtendBoolVectorInReg helper can apply. That helper
+ // requires the scalar to be broadcast across the result elements, so only
+ // proceed when that precondition holds.
+ // TODO: Use a predicate load for SVE vectors.
+ bool CanSplatOrSplit =
+ NumElts <= EltSizeInBits || NumElts % EltSizeInBits == 0;
+ if (Subtarget.isNeonAvailable() && CanSplatOrSplit) {
+ EVT ScalarVT = EVT::getIntegerVT(*DAG.getContext(), NumElts);
+ SDValue ScalarLd = DAG.getLoad(ScalarVT, DL, LN0->getChain(),
+ LN0->getBasePtr(), LN0->getMemOperand());
+ SDValue Bitcast = DAG.getBitcast(LN0->getValueType(0), ScalarLd);
+ if (SDValue V = combineToExtendBoolVectorInReg(
+ N->getOpcode(), DL, VT, Bitcast, DAG, DCI, Subtarget)) {
+ // Redirect the old load's chain users to the new scalar load.
+ DAG.ReplaceAllUsesOfValueWith(SDValue(LN0, 1), ScalarLd.getValue(1));
+ return V;
+ }
+ }
+
+ return SDValue();
+}
+
static SDValue performExtendCombine(SDNode *N,
TargetLowering::DAGCombinerInfo &DCI,
SelectionDAG &DAG,
@@ -24885,6 +24929,9 @@ static SDValue performExtendCombine(SDNode *N,
DAG, DCI, *Subtarget))
return V;
+ if (SDValue V = performExtendToBoolVectorLoadCombine(N, DAG, DCI, *Subtarget))
+ return V;
+
if (N->getValueType(0).isFixedLengthVector() &&
N->getOpcode() == ISD::SIGN_EXTEND &&
N->getOperand(0)->getOpcode() == ISD::SETCC)
diff --git a/llvm/test/CodeGen/AArch64/extend-bool-vector-load.ll b/llvm/test/CodeGen/AArch64/extend-bool-vector-load.ll
index e4e757069d9e1..c01b820444575 100644
--- a/llvm/test/CodeGen/AArch64/extend-bool-vector-load.ll
+++ b/llvm/test/CodeGen/AArch64/extend-bool-vector-load.ll
@@ -5,76 +5,27 @@
define <16 x i8> @sext_v16i1_v16i8(ptr %p) {
; CHECK-LE-LABEL: sext_v16i1_v16i8:
; CHECK-LE: // %bb.0:
-; CHECK-LE-NEXT: ldrh w8, [x0]
-; CHECK-LE-NEXT: sbfx w9, w8, #0, #1
-; CHECK-LE-NEXT: sbfx w10, w8, #1, #1
-; CHECK-LE-NEXT: fmov s0, w9
-; CHECK-LE-NEXT: sbfx w9, w8, #2, #1
-; CHECK-LE-NEXT: mov v0.b[1], w10
-; CHECK-LE-NEXT: mov v0.b[2], w9
-; CHECK-LE-NEXT: sbfx w9, w8, #3, #1
-; CHECK-LE-NEXT: mov v0.b[3], w9
-; CHECK-LE-NEXT: sbfx w9, w8, #4, #1
-; CHECK-LE-NEXT: mov v0.b[4], w9
-; CHECK-LE-NEXT: sbfx w9, w8, #5, #1
-; CHECK-LE-NEXT: mov v0.b[5], w9
-; CHECK-LE-NEXT: sbfx w9, w8, #6, #1
-; CHECK-LE-NEXT: mov v0.b[6], w9
-; CHECK-LE-NEXT: sbfx w9, w8, #7, #1
-; CHECK-LE-NEXT: mov v0.b[7], w9
-; CHECK-LE-NEXT: sbfx w9, w8, #8, #1
-; CHECK-LE-NEXT: mov v0.b[8], w9
-; CHECK-LE-NEXT: sbfx w9, w8, #9, #1
-; CHECK-LE-NEXT: mov v0.b[9], w9
-; CHECK-LE-NEXT: sbfx w9, w8, #10, #1
-; CHECK-LE-NEXT: mov v0.b[10], w9
-; CHECK-LE-NEXT: sbfx w9, w8, #11, #1
-; CHECK-LE-NEXT: mov v0.b[11], w9
-; CHECK-LE-NEXT: sbfx w9, w8, #12, #1
-; CHECK-LE-NEXT: mov v0.b[12], w9
-; CHECK-LE-NEXT: sbfx w9, w8, #13, #1
-; CHECK-LE-NEXT: mov v0.b[13], w9
-; CHECK-LE-NEXT: sbfx w9, w8, #14, #1
-; CHECK-LE-NEXT: sbfx w8, w8, #15, #1
-; CHECK-LE-NEXT: mov v0.b[14], w9
-; CHECK-LE-NEXT: mov v0.b[15], w8
+; CHECK-LE-NEXT: adrp x8, .LCPI0_0
+; CHECK-LE-NEXT: ldr h1, [x0]
+; CHECK-LE-NEXT: ldr q0, [x8, :lo12:.LCPI0_0]
+; CHECK-LE-NEXT: adrp x8, .LCPI0_1
+; CHECK-LE-NEXT: tbl v0.16b, { v1.16b }, v0.16b
+; CHECK-LE-NEXT: ldr q1, [x8, :lo12:.LCPI0_1]
+; CHECK-LE-NEXT: cmtst v0.16b, v0.16b, v1.16b
; CHECK-LE-NEXT: ret
;
; CHECK-BE-LABEL: sext_v16i1_v16i8:
; CHECK-BE: // %bb.0:
-; CHECK-BE-NEXT: ldrh w8, [x0]
-; CHECK-BE-NEXT: sbfx w9, w8, #15, #1
-; CHECK-BE-NEXT: sbfx w10, w8, #14, #1
-; CHECK-BE-NEXT: fmov s0, w9
-; CHECK-BE-NEXT: sbfx w9, w8, #13, #1
-; CHECK-BE-NEXT: mov v0.b[1], w10
-; CHECK-BE-NEXT: mov v0.b[2], w9
-; CHECK-BE-NEXT: sbfx w9, w8, #12, #1
-; CHECK-BE-NEXT: mov v0.b[3], w9
-; CHECK-BE-NEXT: sbfx w9, w8, #11, #1
-; CHECK-BE-NEXT: mov v0.b[4], w9
-; CHECK-BE-NEXT: sbfx w9, w8, #10, #1
-; CHECK-BE-NEXT: mov v0.b[5], w9
-; CHECK-BE-NEXT: sbfx w9, w8, #9, #1
-; CHECK-BE-NEXT: mov v0.b[6], w9
-; CHECK-BE-NEXT: sbfx w9, w8, #8, #1
-; CHECK-BE-NEXT: mov v0.b[7], w9
-; CHECK-BE-NEXT: sbfx w9, w8, #7, #1
-; CHECK-BE-NEXT: mov v0.b[8], w9
-; CHECK-BE-NEXT: sbfx w9, w8, #6, #1
-; CHECK-BE-NEXT: mov v0.b[9], w9
-; CHECK-BE-NEXT: sbfx w9, w8, #5, #1
-; CHECK-BE-NEXT: mov v0.b[10], w9
-; CHECK-BE-NEXT: sbfx w9, w8, #4, #1
-; CHECK-BE-NEXT: mov v0.b[11], w9
-; CHECK-BE-NEXT: sbfx w9, w8, #3, #1
-; CHECK-BE-NEXT: mov v0.b[12], w9
-; CHECK-BE-NEXT: sbfx w9, w8, #2, #1
-; CHECK-BE-NEXT: mov v0.b[13], w9
-; CHECK-BE-NEXT: sbfx w9, w8, #1, #1
-; CHECK-BE-NEXT: sbfx w8, w8, #0, #1
-; CHECK-BE-NEXT: mov v0.b[14], w9
-; CHECK-BE-NEXT: mov v0.b[15], w8
+; CHECK-BE-NEXT: ldr h0, [x0]
+; CHECK-BE-NEXT: adrp x8, .LCPI0_0
+; CHECK-BE-NEXT: add x8, x8, :lo12:.LCPI0_0
+; CHECK-BE-NEXT: ld1 { v1.16b }, [x8]
+; CHECK-BE-NEXT: adrp x8, .LCPI0_1
+; CHECK-BE-NEXT: add x8, x8, :lo12:.LCPI0_1
+; CHECK-BE-NEXT: rev16 v0.16b, v0.16b
+; CHECK-BE-NEXT: tbl v0.16b, { v0.16b }, v1.16b
+; CHECK-BE-NEXT: ld1 { v1.16b }, [x8]
+; CHECK-BE-NEXT: cmtst v0.16b, v0.16b, v1.16b
; CHECK-BE-NEXT: rev64 v0.16b, v0.16b
; CHECK-BE-NEXT: ext v0.16b, v0.16b, v0.16b, #8
; CHECK-BE-NEXT: ret
@@ -86,76 +37,29 @@ define <16 x i8> @sext_v16i1_v16i8(ptr %p) {
define <16 x i8> @zext_v16i1_v16i8(ptr %p) {
; CHECK-LE-LABEL: zext_v16i1_v16i8:
; CHECK-LE: // %bb.0:
-; CHECK-LE-NEXT: ldrh w8, [x0]
-; CHECK-LE-NEXT: and w10, w8, #0x1
-; CHECK-LE-NEXT: ubfx w9, w8, #1, #1
-; CHECK-LE-NEXT: fmov s0, w10
-; CHECK-LE-NEXT: mov v0.b[1], w9
-; CHECK-LE-NEXT: ubfx w9, w8, #2, #1
-; CHECK-LE-NEXT: mov v0.b[2], w9
-; CHECK-LE-NEXT: ubfx w9, w8, #3, #1
-; CHECK-LE-NEXT: mov v0.b[3], w9
-; CHECK-LE-NEXT: ubfx w9, w8, #4, #1
-; CHECK-LE-NEXT: mov v0.b[4], w9
-; CHECK-LE-NEXT: ubfx w9, w8, #5, #1
-; CHECK-LE-NEXT: mov v0.b[5], w9
-; CHECK-LE-NEXT: ubfx w9, w8, #6, #1
-; CHECK-LE-NEXT: mov v0.b[6], w9
-; CHECK-LE-NEXT: ubfx w9, w8, #7, #1
-; CHECK-LE-NEXT: mov v0.b[7], w9
-; CHECK-LE-NEXT: ubfx w9, w8, #8, #1
-; CHECK-LE-NEXT: mov v0.b[8], w9
-; CHECK-LE-NEXT: ubfx w9, w8, #9, #1
-; CHECK-LE-NEXT: mov v0.b[9], w9
-; CHECK-LE-NEXT: ubfx w9, w8, #10, #1
-; CHECK-LE-NEXT: mov v0.b[10], w9
-; CHECK-LE-NEXT: ubfx w9, w8, #11, #1
-; CHECK-LE-NEXT: mov v0.b[11], w9
-; CHECK-LE-NEXT: ubfx w9, w8, #12, #1
-; CHECK-LE-NEXT: mov v0.b[12], w9
-; CHECK-LE-NEXT: ubfx w9, w8, #13, #1
-; CHECK-LE-NEXT: mov v0.b[13], w9
-; CHECK-LE-NEXT: ubfx w9, w8, #14, #1
-; CHECK-LE-NEXT: lsr w8, w8, #15
-; CHECK-LE-NEXT: mov v0.b[14], w9
-; CHECK-LE-NEXT: mov v0.b[15], w8
+; CHECK-LE-NEXT: adrp x8, .LCPI1_0
+; CHECK-LE-NEXT: ldr h1, [x0]
+; CHECK-LE-NEXT: ldr q0, [x8, :lo12:.LCPI1_0]
+; CHECK-LE-NEXT: adrp x8, .LCPI1_1
+; CHECK-LE-NEXT: tbl v0.16b, { v1.16b }, v0.16b
+; CHECK-LE-NEXT: ldr q1, [x8, :lo12:.LCPI1_1]
+; CHECK-LE-NEXT: cmtst v0.16b, v0.16b, v1.16b
+; CHECK-LE-NEXT: ushr v0.16b, v0.16b, #7
; CHECK-LE-NEXT: ret
;
; CHECK-BE-LABEL: zext_v16i1_v16i8:
; CHECK-BE: // %bb.0:
-; CHECK-BE-NEXT: ldrh w8, [x0]
-; CHECK-BE-NEXT: lsr w9, w8, #15
-; CHECK-BE-NEXT: ubfx w10, w8, #14, #1
-; CHECK-BE-NEXT: fmov s0, w9
-; CHECK-BE-NEXT: ubfx w9, w8, #13, #1
-; CHECK-BE-NEXT: mov v0.b[1], w10
-; CHECK-BE-NEXT: mov v0.b[2], w9
-; CHECK-BE-NEXT: ubfx w9, w8, #12, #1
-; CHECK-BE-NEXT: mov v0.b[3], w9
-; CHECK-BE-NEXT: ubfx w9, w8, #11, #1
-; CHECK-BE-NEXT: mov v0.b[4], w9
-; CHECK-BE-NEXT: ubfx w9, w8, #10, #1
-; CHECK-BE-NEXT: mov v0.b[5], w9
-; CHECK-BE-NEXT: ubfx w9, w8, #9, #1
-; CHECK-BE-NEXT: mov v0.b[6], w9
-; CHECK-BE-NEXT: ubfx w9, w8, #8, #1
-; CHECK-BE-NEXT: mov v0.b[7], w9
-; CHECK-BE-NEXT: ubfx w9, w8, #7, #1
-; CHECK-BE-NEXT: mov v0.b[8], w9
-; CHECK-BE-NEXT: ubfx w9, w8, #6, #1
-; CHECK-BE-NEXT: mov v0.b[9], w9
-; CHECK-BE-NEXT: ubfx w9, w8, #5, #1
-; CHECK-BE-NEXT: mov v0.b[10], w9
-; CHECK-BE-NEXT: ubfx w9, w8, #4, #1
-; CHECK-BE-NEXT: mov v0.b[11], w9
-; CHECK-BE-NEXT: ubfx w9, w8, #3, #1
-; CHECK-BE-NEXT: mov v0.b[12], w9
-; CHECK-BE-NEXT: ubfx w9, w8, #2, #1
-; CHECK-BE-NEXT: mov v0.b[13], w9
-; CHECK-BE-NEXT: ubfx w9, w8, #1, #1
-; CHECK-BE-NEXT: and w8, w8, #0x1
-; CHECK-BE-NEXT: mov v0.b[14], w9
-; CHECK-BE-NEXT: mov v0.b[15], w8
+; CHECK-BE-NEXT: ldr h0, [x0]
+; CHECK-BE-NEXT: adrp x8, .LCPI1_0
+; CHECK-BE-NEXT: add x8, x8, :lo12:.LCPI1_0
+; CHECK-BE-NEXT: ld1 { v1.16b }, [x8]
+; CHECK-BE-NEXT: adrp x8, .LCPI1_1
+; CHECK-BE-NEXT: add x8, x8, :lo12:.LCPI1_1
+; CHECK-BE-NEXT: rev16 v0.16b, v0.16b
+; CHECK-BE-NEXT: tbl v0.16b, { v0.16b }, v1.16b
+; CHECK-BE-NEXT: ld1 { v1.16b }, [x8]
+; CHECK-BE-NEXT: cmtst v0.16b, v0.16b, v1.16b
+; CHECK-BE-NEXT: ushr v0.16b, v0.16b, #7
; CHECK-BE-NEXT: rev64 v0.16b, v0.16b
; CHECK-BE-NEXT: ext v0.16b, v0.16b, v0.16b, #8
; CHECK-BE-NEXT: ret
@@ -167,28 +71,21 @@ define <16 x i8> @zext_v16i1_v16i8(ptr %p) {
define <4 x i32> @sext_v4i1_v4i32(ptr %p) {
; CHECK-LE-LABEL: sext_v4i1_v4i32:
; CHECK-LE: // %bb.0:
-; CHECK-LE-NEXT: ldrb w8, [x0]
-; CHECK-LE-NEXT: sbfx w9, w8, #0, #1
-; CHECK-LE-NEXT: sbfx w10, w8, #1, #1
-; CHECK-LE-NEXT: fmov s0, w9
-; CHECK-LE-NEXT: sbfx w9, w8, #2, #1
-; CHECK-LE-NEXT: sbfx w8, w8, #3, #1
-; CHECK-LE-NEXT: mov v0.s[1], w10
-; CHECK-LE-NEXT: mov v0.s[2], w9
-; CHECK-LE-NEXT: mov v0.s[3], w8
+; CHECK-LE-NEXT: ldr b0, [x0]
+; CHECK-LE-NEXT: adrp x8, .LCPI2_0
+; CHECK-LE-NEXT: ldr q1, [x8, :lo12:.LCPI2_0]
+; CHECK-LE-NEXT: dup v0.4s, v0.s[0]
+; CHECK-LE-NEXT: cmtst v0.4s, v0.4s, v1.4s
; CHECK-LE-NEXT: ret
;
; CHECK-BE-LABEL: sext_v4i1_v4i32:
; CHECK-BE: // %bb.0:
-; CHECK-BE-NEXT: ldrb w8, [x0]
-; CHECK-BE-NEXT: sbfx w9, w8, #3, #1
-; CHECK-BE-NEXT: sbfx w10, w8, #2, #1
-; CHECK-BE-NEXT: fmov s0, w9
-; CHECK-BE-NEXT: sbfx w9, w8, #1, #1
-; CHECK-BE-NEXT: sbfx w8, w8, #0, #1
-; CHECK-BE-NEXT: mov v0.s[1], w10
-; CHECK-BE-NEXT: mov v0.s[2], w9
-; CHECK-BE-NEXT: mov v0.s[3], w8
+; CHECK-BE-NEXT: ldr b0, [x0]
+; CHECK-BE-NEXT: adrp x8, .LCPI2_0
+; CHECK-BE-NEXT: add x8, x8, :lo12:.LCPI2_0
+; CHECK-BE-NEXT: ld1 { v1.4s }, [x8]
+; CHECK-BE-NEXT: dup v0.4s, v0.s[0]
+; CHECK-BE-NEXT: cmtst v0.4s, v0.4s, v1.4s
; CHECK-BE-NEXT: rev64 v0.4s, v0.4s
; CHECK-BE-NEXT: ext v0.16b, v0.16b, v0.16b, #8
; CHECK-BE-NEXT: ret
More information about the llvm-commits
mailing list