[llvm] [GlobalISel] Add G_BITCAST to computeKnownBits (PR #216287)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Aug 14 02:45:59 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-aarch64
Author: Xaver Fabian (XFabian)
<details>
<summary>Changes</summary>
Ports the `ISD::BITCAST` case of `SelectionDAG::computeKnownBits` to
`GISelValueTracking::computeKnownBitsImpl`, one of the rows of #<!-- -->150515.
### Codegen change
`compute-known-bits-bitcast-assertion.ll` loses a redundant
`and x10, x10, #<!-- -->0x3`. The masked value reaches the `and` through a
`G_BITCAST <2 x i64> -> <8 x i16>` and a `G_EXTRACT_VECTOR_ELT`, so its high
bits are now known zero and the mask is dead.
## Notes:
- The source type check spells out `isInteger() || isIntegerVector() ||
isFloatOrFloatVector()`. An `isIntegerOrIntegerVector()` helper would
fit the existing `isPointerOrPointerVector()` /
`isFloatOrFloatVector()` pair in `LowLevelType.h`, but this is
currently the only such site in the tree. Happy to do that first if preferred.
- `ANY_SCALAR` (`sN`) and `VECTOR_ANY` sources are not handled and fall
through to unknown. `EVT::isInteger()` is true for both scalar and
vector integer types and has no untyped equivalent, so the SelectionDAG
guard has no `sN` case to port. `bitcast_anyscalar_unsupported` documents the current result.
Assisted-by: Claude Code (navigation, test design and help woth Pr description)
---
Full diff: https://github.com/llvm/llvm-project/pull/216287.diff
3 Files Affected:
- (modified) llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp (+65)
- (modified) llvm/test/CodeGen/AArch64/GlobalISel/compute-known-bits-bitcast-assertion.ll (-1)
- (added) llvm/test/CodeGen/AArch64/GlobalISel/knownbits-bitcast.mir (+164)
``````````diff
diff --git a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
index b7038765c7665..7b1a5482e1e75 100644
--- a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
@@ -1117,6 +1117,71 @@ void GISelValueTracking::computeKnownBitsImpl(Register R, KnownBits &Known,
}
break;
}
+ case TargetOpcode::G_BITCAST: {
+ if (DstTy.isScalableVector())
+ break;
+ Register SrcReg = MI.getOperand(1).getReg();
+ LLT SrcTy = MRI.getType(SrcReg);
+ unsigned SrcBitWidth = SrcTy.getScalarSizeInBits();
+ unsigned NumElts = DemandedElts.getBitWidth();
+ // Ignore bitcasts from unsupported types.
+ if (!(SrcTy.isInteger() || SrcTy.isIntegerVector() ||
+ SrcTy.isFloatOrFloatVector()))
+ break;
+
+ // Fast handling of 'identity' bitcasts.
+ if (BitWidth == SrcBitWidth) {
+ computeKnownBitsImpl(SrcReg, Known, DemandedElts, Depth + 1);
+ break;
+ }
+
+ bool IsLE = getDataLayout().isLittleEndian();
+ // Bitcast 'small element' vector to 'large element' scalar/vector.
+ if ((BitWidth % SrcBitWidth) == 0) {
+ assert(SrcTy.isVector() && "Expected bitcast from vector");
+ // Collect known bits for the (larger) output by collecting the known
+ // bits from each set of sub elements and shift these into place.
+ // We need to separately call computeKnownBits for each set of
+ // sub elements as the knownbits for each is likely to be different.
+ unsigned SubScale = BitWidth / SrcBitWidth;
+ APInt SubDemandedElts(NumElts * SubScale, 0);
+ for (unsigned i = 0; i != NumElts; ++i)
+ if (DemandedElts[i])
+ SubDemandedElts.setBit(i * SubScale);
+ for (unsigned i = 0; i != SubScale; ++i) {
+ computeKnownBitsImpl(SrcReg, Known2, SubDemandedElts.shl(i), Depth + 1);
+ unsigned Shifts = IsLE ? i : SubScale - 1 - i;
+ Known.insertBits(Known2, SrcBitWidth * Shifts);
+ }
+ }
+
+ // Bitcast 'large element' scalar/vector to 'small element' vector.
+ if ((SrcBitWidth % BitWidth) == 0) {
+ assert(DstTy.isVector() && "Expected bitcast to vector");
+
+ // Collect known bits for the (smaller) output by collecting the known
+ // bits from the overlapping larger input elements and extracting the
+ // sub sections we actually care about.
+ unsigned SubScale = SrcBitWidth / BitWidth;
+
+ APInt SubDemandedElts =
+ APIntOps::ScaleBitMask(DemandedElts, NumElts / SubScale);
+ computeKnownBitsImpl(SrcReg, Known2, SubDemandedElts, Depth + 1);
+
+ Known.setAllConflict();
+
+ for (unsigned i = 0; i != NumElts; ++i)
+ if (DemandedElts[i]) {
+ unsigned Shifts = IsLE ? i : NumElts - 1 - i;
+ unsigned Offset = (Shifts % SubScale) * BitWidth;
+ Known = Known.intersectWith(Known2.extractBits(BitWidth, Offset));
+ // If we don't know any bits, early out.
+ if (Known.isUnknown())
+ break;
+ }
+ }
+ break;
+ }
case TargetOpcode::G_ABS: {
Register SrcReg = MI.getOperand(1).getReg();
computeKnownBitsImpl(SrcReg, Known, DemandedElts, Depth + 1);
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/compute-known-bits-bitcast-assertion.ll b/llvm/test/CodeGen/AArch64/GlobalISel/compute-known-bits-bitcast-assertion.ll
index 2002eee0be690..37e4f206bb3cb 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/compute-known-bits-bitcast-assertion.ll
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/compute-known-bits-bitcast-assertion.ll
@@ -13,7 +13,6 @@ define <2 x i8> @test_bitcast_assertion(<4 x i32> %vqaddq_v2.i.i, ptr %BS_VAR_0)
; CHECK-NEXT: // =>This Inner Loop Header: Depth=1
; CHECK-NEXT: umov w10, v1.h[0]
; CHECK-NEXT: str q0, [sp]
-; CHECK-NEXT: and x10, x10, #0x3
; CHECK-NEXT: umull x10, w10, w9
; CHECK-NEXT: ldrh w10, [x8, x10]
; CHECK-NEXT: stp q1, q1, [x0, #32]
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-bitcast.mir b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-bitcast.mir
new file mode 100644
index 0000000000000..64d34f78c2db3
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-bitcast.mir
@@ -0,0 +1,164 @@
+# 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>" %s -filetype=null 2>&1 | FileCheck %s --check-prefixes=CHECK,LE
+# RUN: llc -mtriple aarch64_be -passes="print<gisel-value-tracking>" %s -filetype=null 2>&1 | FileCheck %s --check-prefixes=CHECK,BE
+
+---
+name: bitcast_splat_constant
+body: |
+ bb.0:
+ ; CHECK-LABEL: name: @bitcast_splat_constant
+ ; CHECK-NEXT: %c:_ KnownBits:00001111 SignBits:4 IsKnownNeverZero:1
+ ; CHECK-NEXT: %1:_ KnownBits:00001111 SignBits:4 IsKnownNeverZero:1
+ ; CHECK-NEXT: %2:_ KnownBits:0000111100001111 SignBits:4 IsKnownNeverZero:1
+ %c:_(i8) = G_CONSTANT i8 15
+ %1:_(<4 x i8>) = G_BUILD_VECTOR %c(i8), %c(i8), %c(i8), %c(i8)
+ %2:_(<2 x i16>) = G_BITCAST %1(<4 x i8>)
+...
+---
+name: bitcast_small_large_vector
+body: |
+ bb.0:
+ ; CHECK-LABEL: name: @bitcast_small_large_vector
+ ; CHECK-NEXT: %0:_ KnownBits:???????? SignBits:1 IsKnownNeverZero:0
+ ; CHECK-NEXT: %zext0:_ KnownBits:00000000???????? SignBits:8 IsKnownNeverZero:0
+ ; CHECK-NEXT: %2:_ KnownBits:00000000????????00000000???????? SignBits:8 IsKnownNeverZero:0
+ %0:_(<4 x i8>) = COPY $s0
+ %zext0:_(<4 x i16>) = G_ZEXT %0
+ %2:_(<2 x i32>) = G_BITCAST %zext0(<4 x i16>)
+...
+---
+name: bitcast_large_small_vector
+body: |
+ bb.0:
+ ; CHECK-LABEL: name: @bitcast_large_small_vector
+ ; CHECK-NEXT: %0:_ KnownBits:???????? SignBits:1 IsKnownNeverZero:0
+ ; CHECK-NEXT: %m:_ KnownBits:0000111100001111 SignBits:4 IsKnownNeverZero:1
+ ; CHECK-NEXT: %mv:_ KnownBits:0000111100001111 SignBits:4 IsKnownNeverZero:1
+ ; CHECK-NEXT: %zext0:_ KnownBits:00000000???????? SignBits:8 IsKnownNeverZero:0
+ ; CHECK-NEXT: %masked:_ KnownBits:000000000000???? SignBits:12 IsKnownNeverZero:0
+ ; CHECK-NEXT: %5:_ KnownBits:0000???? SignBits:4 IsKnownNeverZero:0
+ %0:_(<4 x i8>) = COPY $s0
+ %m:_(i16) = G_CONSTANT i16 3855 ; 0x0F0F
+ %mv:_(<4 x i16>) = G_BUILD_VECTOR %m(i16), %m(i16), %m(i16), %m(i16)
+ %zext0:_(<4 x i16>) = G_ZEXT %0
+ %masked:_(<4 x i16>) = G_AND %zext0, %mv
+ %5:_(<8 x i8>) = G_BITCAST %masked(<4 x i16>)
+...
+---
+name: bitcast_small_large_scalar
+body: |
+ bb.0:
+ ; CHECK-LABEL: name: @bitcast_small_large_scalar
+ ; CHECK-NEXT: %0:_ KnownBits:???????? SignBits:1 IsKnownNeverZero:0
+ ; CHECK-NEXT: %zext0:_ KnownBits:00000000???????? SignBits:8 IsKnownNeverZero:0
+ ; CHECK-NEXT: %2:_ KnownBits:00000000????????00000000????????00000000????????00000000???????? SignBits:8 IsKnownNeverZero:0
+ %0:_(<4 x i8>) = COPY $s0
+ %zext0:_(<4 x i16>) = G_ZEXT %0
+ %2:_(i64) = G_BITCAST %zext0(<4 x i16>)
+...
+---
+name: bitcast_large_small_scalar
+body: |
+ bb.0:
+ ; CHECK-LABEL: name: @bitcast_large_small_scalar
+ ; CHECK-NEXT: %m:_ KnownBits:0000111100001111 SignBits:4 IsKnownNeverZero:1
+ ; CHECK-NEXT: %1:_ KnownBits:00001111 SignBits:4 IsKnownNeverZero:1
+ %m:_(i16) = G_CONSTANT i16 3855 ; 0x0F0F
+ %1:_(<2 x i8>) = G_BITCAST %m(i16)
+...
+---
+name: bitcast_int_float_vector
+body: |
+ bb.0:
+ ; CHECK-LABEL: name: @bitcast_int_float_vector
+ ; CHECK-NEXT: %0:_ KnownBits:???????? SignBits:1 IsKnownNeverZero:0
+ ; CHECK-NEXT: %zext0:_ KnownBits:00000000???????? SignBits:8 IsKnownNeverZero:0
+ ; CHECK-NEXT: %2:_ KnownBits:00000000???????? SignBits:8 IsKnownNeverZero:0
+ %0:_(<4 x i8>) = COPY $s0
+ %zext0:_(<4 x i16>) = G_ZEXT %0
+ %2:_(<4 x f16>) = G_BITCAST %zext0(<4 x i16>)
+...
+---
+name: bitcast_int_float
+body: |
+ bb.0:
+ ; CHECK-LABEL: name: @bitcast_int_float
+ ; CHECK-NEXT: %m:_ KnownBits:0000111100001111 SignBits:4 IsKnownNeverZero:1
+ ; CHECK-NEXT: %1:_ KnownBits:0000111100001111 SignBits:4 IsKnownNeverZero:1
+ %m:_(i16) = G_CONSTANT i16 3855
+ %1:_(f16) = G_BITCAST %m(i16)
+...
+---
+name: bitcast_address_space
+body: |
+ bb.0:
+ ; CHECK-LABEL: name: @bitcast_address_space
+ ; CHECK-NEXT: %0:_ KnownBits:???????????????????????????????????????????????????????????????? SignBits:1 IsKnownNeverZero:0
+ ; CHECK-NEXT: %1:_ KnownBits:???????????????????????????????????????????????????????????????? SignBits:1 IsKnownNeverZero:0
+ %0:_(p0) = COPY $x0
+ %1:_(p1) = G_BITCAST %0(p0)
+...
+---
+name: bitcast_small_large_alternating
+body: |
+ bb.0:
+ ; LE-LABEL: name: @bitcast_small_large_alternating
+ ; LE-NEXT: %c:_ KnownBits:11111111 SignBits:8 IsKnownNeverZero:1
+ ; LE-NEXT: %d:_ KnownBits:00000000 SignBits:8 IsKnownNeverZero:0
+ ; LE-NEXT: %2:_ KnownBits:???????? SignBits:8 IsKnownNeverZero:0
+ ; LE-NEXT: %3:_ KnownBits:0000000011111111 SignBits:8 IsKnownNeverZero:1
+ ;
+ ; BE-LABEL: name: @bitcast_small_large_alternating
+ ; BE-NEXT: %c:_ KnownBits:11111111 SignBits:8 IsKnownNeverZero:1
+ ; BE-NEXT: %d:_ KnownBits:00000000 SignBits:8 IsKnownNeverZero:0
+ ; BE-NEXT: %2:_ KnownBits:???????? SignBits:8 IsKnownNeverZero:0
+ ; BE-NEXT: %3:_ KnownBits:1111111100000000 SignBits:8 IsKnownNeverZero:1
+ %c:_(i8) = G_CONSTANT i8 255
+ %d:_(i8) = G_CONSTANT i8 0
+ %1:_(<4 x i8>) = G_BUILD_VECTOR %c(i8), %d(i8), %c(i8), %d(i8)
+ %2:_(<2 x i16>) = G_BITCAST %1(<4 x i8>)
+...
+---
+name: bitcast_small_large_partial
+body: |
+ bb.0:
+ ; LE-LABEL: name: @bitcast_small_large_partial
+ ; LE-NEXT: %a:_ KnownBits:0000000011111111 SignBits:8 IsKnownNeverZero:1
+ ; LE-NEXT: %b:_ KnownBits:0000111111110000 SignBits:4 IsKnownNeverZero:1
+ ; LE-NEXT: %c:_ KnownBits:0000111100001111 SignBits:4 IsKnownNeverZero:1
+ ; LE-NEXT: %d:_ KnownBits:0011110000111100 SignBits:2 IsKnownNeverZero:1
+ ; LE-NEXT: %v:_ KnownBits:00?????????????? SignBits:2 IsKnownNeverZero:1
+ ; LE-NEXT: %r:_ KnownBits:00??11????11??000000????????1111 SignBits:2 IsKnownNeverZero:1
+ ; LE-NEXT: %i:_ KnownBits:0000000000000000000000000000000000000000000000000000000000000000 SignBits:64 IsKnownNeverZero:0
+ ; LE-NEXT: %e:_ KnownBits:00001111111100000000000011111111 SignBits:4 IsKnownNeverZero:1
+ ;
+ ; BE-LABEL: name: @bitcast_small_large_partial
+ ; BE-NEXT: %a:_ KnownBits:0000000011111111 SignBits:8 IsKnownNeverZero:1
+ ; BE-NEXT: %b:_ KnownBits:0000111111110000 SignBits:4 IsKnownNeverZero:1
+ ; BE-NEXT: %c:_ KnownBits:0000111100001111 SignBits:4 IsKnownNeverZero:1
+ ; BE-NEXT: %d:_ KnownBits:0011110000111100 SignBits:2 IsKnownNeverZero:1
+ ; BE-NEXT: %v:_ KnownBits:00?????????????? SignBits:2 IsKnownNeverZero:1
+ ; BE-NEXT: %r:_ KnownBits:0000????????111100??11????11??00 SignBits:4 IsKnownNeverZero:1
+ ; BE-NEXT: %i:_ KnownBits:0000000000000000000000000000000000000000000000000000000000000000 SignBits:64 IsKnownNeverZero:0
+ ; BE-NEXT: %e:_ KnownBits:00000000111111110000111111110000 SignBits:8 IsKnownNeverZero:1
+ %a:_(i16) = G_CONSTANT i16 255 ; 0x00FF
+ %b:_(i16) = G_CONSTANT i16 4080 ; 0x0FF0
+ %c:_(i16) = G_CONSTANT i16 3855 ; 0xF0F0
+ %d:_(i16) = G_CONSTANT i16 15420 ; 0x3C3C
+ %v:_(<4 x i16>) = G_BUILD_VECTOR %a(i16), %b(i16), %c(i16), %d(i16)
+ %r:_(<2 x i32>) = G_BITCAST %v(<4 x i16>)
+ %i:_(i64) = G_CONSTANT i64 0
+ %e:_(i32) = G_EXTRACT_VECTOR_ELT %r, %i
+...
+---
+name: bitcast_anyscalar_unsupported
+body: |
+ bb.0:
+ ; CHECK-LABEL: name: @bitcast_anyscalar_unsupported
+ ; CHECK-NEXT: %c:_ KnownBits:00001111 SignBits:4 IsKnownNeverZero:1
+ ; CHECK-NEXT: %1:_ KnownBits:00001111 SignBits:4 IsKnownNeverZero:1
+ ; CHECK-NEXT: %2:_ KnownBits:???????????????? SignBits:1 IsKnownNeverZero:0
+ %c:_(s8) = G_CONSTANT i8 15
+ %1:_(<4 x s8>) = G_BUILD_VECTOR %c(s8), %c(s8), %c(s8), %c(s8)
+ %2:_(<2 x s16>) = G_BITCAST %1(<4 x s8>)
+...
``````````
</details>
https://github.com/llvm/llvm-project/pull/216287
More information about the llvm-commits
mailing list