[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