[llvm] [AArch64][GlobalISel] Add known bits for G_DUP, G_VASHR and G_VLSHR (PR #210503)
Joel Walker via llvm-commits
llvm-commits at lists.llvm.org
Sat Jul 18 04:38:19 PDT 2026
https://github.com/Joel-Wwalker created https://github.com/llvm/llvm-project/pull/210503
Adds AArch64's GlobalISel `computeKnownBitsForTargetInstr` hook (the target previously had none, unlike its SelectionDAG counterpart) with the first three cases:
- `G_DUP`: the known bits of the scalar operand, truncated to the element width when the operand is implicitly truncated.
- `G_VASHR` / `G_VLSHR`: `KnownBits::ashr`/`lshr` of the source by the immediate. A shift by the full element width is legal for these instructions but is poison for the IR shifts the KnownBits helpers model, so that case conservatively stays unknown.
All three mirror the corresponding cases in `computeKnownBitsForTargetNode`. Follow-up to #210269, which added sign bits for `G_VASHR`.
Assisted by Claude (Anthropic).
>From f3101f64fa77c687ad363f4a7c913701b6b411e0 Mon Sep 17 00:00:00 2001
From: Joel-Wwalker <theagingboy05 at gmail.com>
Date: Sat, 18 Jul 2026 07:38:04 -0400
Subject: [PATCH] [AArch64][GlobalISel] Add known bits for G_DUP, G_VASHR and
G_VLSHR
Adds AArch64's computeKnownBitsForTargetInstr hook (previously absent,
unlike its SelectionDAG counterpart) with the first three cases:
- G_DUP: the known bits of the scalar operand, truncated to the element
width when the operand is implicitly truncated.
- G_VASHR/G_VLSHR: KnownBits::ashr/lshr of the source by the immediate.
A shift by the full element width is legal for these instructions but
is poison for the IR shifts the KnownBits helpers model, so that case
conservatively stays unknown.
All three mirror the corresponding cases in computeKnownBitsForTargetNode.
The arm64-neon-aba-abd.ll changes fold the knownbits_sabd test functions
to constants, matching what SelectionDAG already proves; the
shuffle-slide-to-shift.ll change drops a redundant zero materialization.
Follow-up to #210269.
---
.../Target/AArch64/AArch64ISelLowering.cpp | 43 +++++++++++++++++++
llvm/lib/Target/AArch64/AArch64ISelLowering.h | 6 +++
.../AArch64/GlobalISel/knownbits-dup.mir | 35 +++++++++++++++
.../AArch64/GlobalISel/knownbits-vashr.mir | 18 ++++++++
.../AArch64/GlobalISel/knownbits-vlshr.mir | 33 ++++++++++++++
.../CodeGen/AArch64/arm64-neon-aba-abd.ll | 23 ++--------
.../CodeGen/AArch64/shuffle-slide-to-shift.ll | 6 +--
7 files changed, 141 insertions(+), 23 deletions(-)
create mode 100644 llvm/test/CodeGen/AArch64/GlobalISel/knownbits-dup.mir
create mode 100644 llvm/test/CodeGen/AArch64/GlobalISel/knownbits-vlshr.mir
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index a1cf0fd66feb1..595e6c28f0e49 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -3087,6 +3087,49 @@ unsigned AArch64TargetLowering::ComputeNumSignBitsForTargetNode(
return 1;
}
+void AArch64TargetLowering::computeKnownBitsForTargetInstr(
+ GISelValueTracking &Analysis, Register R, KnownBits &Known,
+ const APInt &DemandedElts, const MachineRegisterInfo &MRI,
+ unsigned Depth) const {
+ const MachineInstr *MI = MRI.getVRegDef(R);
+ if (!MI)
+ return;
+
+ switch (MI->getOpcode()) {
+ case AArch64::G_DUP: {
+ Register Src = MI->getOperand(1).getReg();
+ unsigned SrcBits = MRI.getType(Src).getSizeInBits();
+ KnownBits SrcKnown(SrcBits);
+ Analysis.computeKnownBitsImpl(Src, SrcKnown, APInt(1, 1), Depth + 1);
+ unsigned EltBits = MRI.getType(R).getScalarSizeInBits();
+ if (SrcBits != EltBits) {
+ assert(SrcBits > EltBits && "Expected DUP implicit truncation");
+ SrcKnown = SrcKnown.trunc(EltBits);
+ }
+ Known = SrcKnown;
+ break;
+ }
+ case AArch64::G_VASHR:
+ case AArch64::G_VLSHR: {
+ unsigned BitWidth = MRI.getType(R).getScalarSizeInBits();
+ uint64_t Shift = MI->getOperand(2).getImm();
+ // A shift by the full element width is legal for these instructions, but
+ // KnownBits::ashr/lshr model IR shifts, for which it is poison. Leave the
+ // result unknown in that case.
+ if (Shift >= BitWidth)
+ break;
+ KnownBits SrcKnown(BitWidth);
+ Analysis.computeKnownBitsImpl(MI->getOperand(1).getReg(), SrcKnown,
+ DemandedElts, Depth + 1);
+ KnownBits ShiftKnown = KnownBits::makeConstant(APInt(BitWidth, Shift));
+ Known = MI->getOpcode() == AArch64::G_VASHR
+ ? KnownBits::ashr(SrcKnown, ShiftKnown)
+ : KnownBits::lshr(SrcKnown, ShiftKnown);
+ break;
+ }
+ }
+}
+
unsigned AArch64TargetLowering::computeNumSignBitsForTargetInstr(
GISelValueTracking &Analysis, Register R, const APInt &DemandedElts,
const MachineRegisterInfo &MRI, unsigned Depth) const {
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.h b/llvm/lib/Target/AArch64/AArch64ISelLowering.h
index 5cc4e9fa1b063..dbad4ae506920 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.h
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.h
@@ -91,6 +91,12 @@ class AArch64TargetLowering : public TargetLowering {
const SelectionDAG &DAG,
unsigned Depth) const override;
+ void computeKnownBitsForTargetInstr(GISelValueTracking &Analysis, Register R,
+ KnownBits &Known,
+ const APInt &DemandedElts,
+ const MachineRegisterInfo &MRI,
+ unsigned Depth = 0) const override;
+
unsigned computeNumSignBitsForTargetInstr(GISelValueTracking &Analysis,
Register R,
const APInt &DemandedElts,
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-dup.mir b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-dup.mir
new file mode 100644
index 0000000000000..6a32304496042
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-dup.mir
@@ -0,0 +1,35 @@
+# NOTE: Assertions have been autogenerated by utils/update_givaluetracking_test_checks.py UTC_ARGS: --version 5
+# RUN: llc -mtriple=aarch64 -passes="print<gisel-value-tracking>" -filetype=null %s 2>&1 | FileCheck %s
+
+---
+name: DUP
+body: |
+ bb.1:
+ liveins: $w0
+ ; CHECK-LABEL: name: @DUP
+ ; CHECK-NEXT: %0:_ KnownBits:???????????????????????????????? SignBits:1
+ ; CHECK-NEXT: %1:_ KnownBits:00000000000000000000000000001111 SignBits:28
+ ; CHECK-NEXT: %2:_ KnownBits:0000000000000000000000000000???? SignBits:28
+ ; CHECK-NEXT: %3:fpr KnownBits:0000000000000000000000000000???? SignBits:28
+ %0:_(i32) = COPY $w0
+ %1:_(i32) = G_CONSTANT i32 15
+ %2:_(i32) = G_AND %0, %1
+ %3:fpr(<4 x i32>) = G_DUP %2(i32)
+ $q0 = COPY %3:fpr(<4 x i32>)
+...
+---
+name: DUP_implicit_trunc
+body: |
+ bb.1:
+ liveins: $w0
+ ; CHECK-LABEL: name: @DUP_implicit_trunc
+ ; CHECK-NEXT: %0:_ KnownBits:???????????????????????????????? SignBits:1
+ ; CHECK-NEXT: %1:_ KnownBits:00000000000000000000000000001000 SignBits:28
+ ; CHECK-NEXT: %2:_ KnownBits:????????????????????????????1??? SignBits:1
+ ; CHECK-NEXT: %3:fpr KnownBits:????????????1??? SignBits:1
+ %0:_(i32) = COPY $w0
+ %1:_(i32) = G_CONSTANT i32 8
+ %2:_(i32) = G_OR %0, %1
+ %3:fpr(<8 x i16>) = G_DUP %2(i32)
+ $q0 = COPY %3:fpr(<8 x i16>)
+...
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-vashr.mir b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-vashr.mir
index 436e03ef1a065..ecb2784c470ed 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-vashr.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-vashr.mir
@@ -55,3 +55,21 @@ body: |
%3:fpr(<4 x i32>) = G_VASHR %2, 5
$q0 = COPY %3:fpr(<4 x i32>)
...
+---
+name: VASHR_known_sign_bits
+body: |
+ bb.1:
+ liveins: $q0
+ ; CHECK-LABEL: name: @VASHR_known_sign_bits
+ ; CHECK-NEXT: %0:fpr KnownBits:???????????????? SignBits:1
+ ; CHECK-NEXT: %1:_ KnownBits:1000000000000000 SignBits:1
+ ; CHECK-NEXT: %2:fpr KnownBits:1000000000000000 SignBits:1
+ ; CHECK-NEXT: %3:fpr KnownBits:1??????????????? SignBits:1
+ ; CHECK-NEXT: %4:fpr KnownBits:11111??????????? SignBits:5
+ %0:fpr(<8 x i16>) = COPY $q0
+ %1:_(i16) = G_CONSTANT i16 -32768
+ %2:fpr(<8 x i16>) = G_BUILD_VECTOR %1, %1, %1, %1, %1, %1, %1, %1
+ %3:fpr(<8 x i16>) = G_OR %0, %2
+ %4:fpr(<8 x i16>) = G_VASHR %3, 4
+ $q0 = COPY %4:fpr(<8 x i16>)
+...
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-vlshr.mir b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-vlshr.mir
new file mode 100644
index 0000000000000..1de36c8f6e2cf
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-vlshr.mir
@@ -0,0 +1,33 @@
+# NOTE: Assertions have been autogenerated by utils/update_givaluetracking_test_checks.py UTC_ARGS: --version 5
+# RUN: llc -mtriple=aarch64 -passes="print<gisel-value-tracking>" -filetype=null %s 2>&1 | FileCheck %s
+
+---
+name: VLSHR
+body: |
+ bb.1:
+ liveins: $q0
+ ; CHECK-LABEL: name: @VLSHR
+ ; CHECK-NEXT: %0:fpr KnownBits:???????????????? SignBits:1
+ ; CHECK-NEXT: %1:_ KnownBits:0000000011110000 SignBits:8
+ ; CHECK-NEXT: %2:fpr KnownBits:0000000011110000 SignBits:8
+ ; CHECK-NEXT: %3:fpr KnownBits:00000000????0000 SignBits:8
+ ; CHECK-NEXT: %4:fpr KnownBits:000000000000???? SignBits:12
+ %0:fpr(<8 x i16>) = COPY $q0
+ %1:_(i16) = G_CONSTANT i16 240
+ %2:fpr(<8 x i16>) = G_BUILD_VECTOR %1, %1, %1, %1, %1, %1, %1, %1
+ %3:fpr(<8 x i16>) = G_AND %0, %2
+ %4:fpr(<8 x i16>) = G_VLSHR %3, 4
+ $q0 = COPY %4:fpr(<8 x i16>)
+...
+---
+name: VLSHR_by_element_width
+body: |
+ bb.1:
+ liveins: $q0
+ ; CHECK-LABEL: name: @VLSHR_by_element_width
+ ; CHECK-NEXT: %0:fpr KnownBits:???????????????? SignBits:1
+ ; CHECK-NEXT: %1:fpr KnownBits:???????????????? SignBits:1
+ %0:fpr(<8 x i16>) = COPY $q0
+ %1:fpr(<8 x i16>) = G_VLSHR %0, 16
+ $q0 = COPY %1:fpr(<8 x i16>)
+...
diff --git a/llvm/test/CodeGen/AArch64/arm64-neon-aba-abd.ll b/llvm/test/CodeGen/AArch64/arm64-neon-aba-abd.ll
index e6f2d4248084f..ef8855247d84f 100644
--- a/llvm/test/CodeGen/AArch64/arm64-neon-aba-abd.ll
+++ b/llvm/test/CodeGen/AArch64/arm64-neon-aba-abd.ll
@@ -539,17 +539,9 @@ 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: 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: ldr q0, [x8, :lo12:.LCPI45_0]
+; CHECK-GI-NEXT: tbl v0.16b, { v0.16b }, v0.16b
; 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>
@@ -605,16 +597,9 @@ define <4 x i32> @knownbits_sabd_and_shl_mask(<4 x i32> %a0, <4 x i32> %a1) {
;
; CHECK-GI-LABEL: knownbits_sabd_and_shl_mask:
; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: adrp x8, .LCPI47_1
-; CHECK-GI-NEXT: ldr q2, [x8, :lo12:.LCPI47_1]
; CHECK-GI-NEXT: adrp x8, .LCPI47_0
-; CHECK-GI-NEXT: and v0.16b, v0.16b, v2.16b
-; CHECK-GI-NEXT: and v1.16b, v1.16b, v2.16b
-; CHECK-GI-NEXT: shl v0.4s, v0.4s, #17
-; CHECK-GI-NEXT: shl v1.4s, v1.4s, #17
-; CHECK-GI-NEXT: sabd v0.4s, v0.4s, v1.4s
-; CHECK-GI-NEXT: ldr q1, [x8, :lo12:.LCPI47_0]
-; CHECK-GI-NEXT: tbl v0.16b, { v0.16b }, v1.16b
+; CHECK-GI-NEXT: ldr q0, [x8, :lo12:.LCPI47_0]
+; CHECK-GI-NEXT: tbl v0.16b, { v0.16b }, v0.16b
; CHECK-GI-NEXT: ret
%1 = and <4 x i32> %a0, <i32 -65536, i32 -7, i32 -7, i32 -65536>
%2 = shl <4 x i32> %1, <i32 17, i32 17, i32 17, i32 17>
diff --git a/llvm/test/CodeGen/AArch64/shuffle-slide-to-shift.ll b/llvm/test/CodeGen/AArch64/shuffle-slide-to-shift.ll
index b9d70a98553da..7ae32d6678951 100644
--- a/llvm/test/CodeGen/AArch64/shuffle-slide-to-shift.ll
+++ b/llvm/test/CodeGen/AArch64/shuffle-slide-to-shift.ll
@@ -156,12 +156,10 @@ define <4 x i8> @slide_right_v4i8(<4 x i8> %v) {
;
; CHECK-GI-LABEL: slide_right_v4i8:
; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: movi v1.2d, #0000000000000000
; CHECK-GI-NEXT: uzp1 v0.8b, v0.8b, v0.8b
; CHECK-GI-NEXT: adrp x8, .LCPI8_0
-; CHECK-GI-NEXT: mov v1.d[1], v0.d[0]
-; CHECK-GI-NEXT: ldr d0, [x8, :lo12:.LCPI8_0]
-; CHECK-GI-NEXT: tbl v0.16b, { v1.16b }, v0.16b
+; CHECK-GI-NEXT: ldr d1, [x8, :lo12:.LCPI8_0]
+; CHECK-GI-NEXT: tbl v0.16b, { v0.16b }, v1.16b
; CHECK-GI-NEXT: zip1 v0.8b, v0.8b, v0.8b
; CHECK-GI-NEXT: ret
%r = shufflevector <4 x i8> zeroinitializer, <4 x i8> %v,
More information about the llvm-commits
mailing list