[llvm] [AArch64][GlobalISel] Add known bits for G_DUP, G_VASHR and G_VLSHR (PR #210503)
via llvm-commits
llvm-commits at lists.llvm.org
Sat Jul 18 04:38:52 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-globalisel
Author: Joel Walker (Joel-Wwalker)
<details>
<summary>Changes</summary>
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).
---
Full diff: https://github.com/llvm/llvm-project/pull/210503.diff
7 Files Affected:
- (modified) llvm/lib/Target/AArch64/AArch64ISelLowering.cpp (+43)
- (modified) llvm/lib/Target/AArch64/AArch64ISelLowering.h (+6)
- (added) llvm/test/CodeGen/AArch64/GlobalISel/knownbits-dup.mir (+35)
- (modified) llvm/test/CodeGen/AArch64/GlobalISel/knownbits-vashr.mir (+18)
- (added) llvm/test/CodeGen/AArch64/GlobalISel/knownbits-vlshr.mir (+33)
- (modified) llvm/test/CodeGen/AArch64/arm64-neon-aba-abd.ll (+4-19)
- (modified) llvm/test/CodeGen/AArch64/shuffle-slide-to-shift.ll (+2-4)
``````````diff
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,
``````````
</details>
https://github.com/llvm/llvm-project/pull/210503
More information about the llvm-commits
mailing list