[llvm] [GlobalISel] Add G_BITCAST to computeKnownBits (PR #217841)

Deepak Shirke via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 21 01:17:01 PDT 2026


https://github.com/deepakshirkem created https://github.com/llvm/llvm-project/pull/217841

Port the SDAG BITCAST computeKnownBits handling to GlobalISel.
- Identity bitcast (same bit width): propagate known bits directly
- Small element vector to large element scalar/vector: combine known bits from sub-elements
- Large element scalar/vector to small element vector: extract known bits per element

Part of #150515.

>From d532587dc4611edc1b7225488df45657cf0440cf Mon Sep 17 00:00:00 2001
From: deepakshirkem <deepakshirke509 at gmail.com>
Date: Fri, 21 Aug 2026 13:43:22 +0530
Subject: [PATCH] [GlobalISel] Add G_BITCAST to computeKnownBits

Port the SDAG BITCAST computeKnownBits handling to GlobalISel.
Handles three cases:
- Identity bitcast (same bit width): propagate known bits directly
- Small element vector to large element scalar/vector: combine known
  bits from sub-elements using insertBits
- Large element scalar/vector to small element vector: extract known
  bits per element using extractBits
---
 .../CodeGen/GlobalISel/GISelValueTracking.cpp | 62 +++++++++++++++++++
 .../AArch64/GlobalISel/knownbits-bitcast.mir  | 57 +++++++++++++++++
 2 files changed, 119 insertions(+)
 create mode 100644 llvm/test/CodeGen/AArch64/GlobalISel/knownbits-bitcast.mir

diff --git a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
index 0672cfffc6eac..132606499bdd7 100644
--- a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
@@ -879,6 +879,68 @@ void GISelValueTracking::computeKnownBitsImpl(Register R, KnownBits &Known,
     Known = Known.reverseBits();
     break;
   }
+  case TargetOpcode::G_BITCAST: {
+    Register SrcReg = MI.getOperand(1).getReg();
+    LLT SrcTy = MRI.getType(SrcReg);
+
+    // Ignore bitcasts involving scalable vectors.
+    if (SrcTy.isScalableVector() || DstTy.isScalableVector())
+      break;
+
+    unsigned SrcBitWidth = SrcTy.getScalarSizeInBits();
+
+    // Ignore bitcasts from unsupported types.
+    if (!SrcTy.isInteger() && !SrcTy.isFloat() && !SrcTy.isIntegerVector() &&
+        !SrcTy.isFloatVector())
+      break;
+
+    // Fast handling of identity bitcasts (same bit width).
+    if (BitWidth == SrcBitWidth) {
+      computeKnownBitsImpl(SrcReg, Known, DemandedElts, Depth + 1);
+      break;
+    }
+
+    bool IsLE = DL.isLittleEndian();
+    unsigned NumElts = DstTy.isVector() ? DstTy.getNumElements() : 1;
+
+    // Bitcast 'small element' vector to 'large element' scalar/vector.
+    if ((BitWidth % SrcBitWidth) == 0) {
+      assert(SrcTy.isVector() && "Expected bitcast from vector");
+      unsigned SubScale = BitWidth / SrcBitWidth;
+      unsigned NumSrcElts = SrcTy.getNumElements();
+      APInt SubDemandedElts(NumSrcElts, 0);
+      for (unsigned i = 0; i != NumElts; ++i)
+        if (DemandedElts[i])
+          SubDemandedElts.setBit(i * SubScale);
+      for (unsigned i = 0; i != SubScale; ++i) {
+        KnownBits SubKnown(SrcBitWidth);
+        computeKnownBitsImpl(SrcReg, SubKnown, SubDemandedElts.shl(i),
+                             Depth + 1);
+        unsigned Shifts = IsLE ? i : SubScale - 1 - i;
+        Known.insertBits(SubKnown, SrcBitWidth * Shifts);
+      }
+    }
+
+    // Bitcast 'large element' scalar/vector to 'small element' vector.
+    if ((SrcBitWidth % BitWidth) == 0) {
+      assert(DstTy.isVector() && "Expected bitcast to vector");
+      unsigned SubScale = SrcBitWidth / BitWidth;
+      APInt SubDemandedElts =
+          APIntOps::ScaleBitMask(DemandedElts, NumElts / SubScale);
+      // Use SrcBitWidth for Known2 since source is wider than destination
+      KnownBits SrcKnown(SrcBitWidth);
+      computeKnownBitsImpl(SrcReg, SrcKnown, 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(SrcKnown.extractBits(BitWidth, Offset));
+        }
+      }
+    }
+    break;
+  }
   case TargetOpcode::G_CTPOP: {
     computeKnownBitsImpl(MI.getOperand(1).getReg(), Known2, DemandedElts,
                          Depth + 1);
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..f78c4120e1987
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-bitcast.mir
@@ -0,0 +1,57 @@
+# NOTE: Assertions have been autogenerated by utils/update_givaluetracking_test_checks.py UTC_ARGS: --version 6
+# RUN: llc -mtriple aarch64 -passes="print<gisel-value-tracking>" %s -filetype=null 2>&1 | FileCheck %s
+---
+# Identity bitcast i32->f32->i32, known bits preserved
+name: Bitcast_Identity
+body: |
+  bb.0:
+  ; CHECK-LABEL: name: @Bitcast_Identity
+  ; CHECK-NEXT: %0:_ KnownBits:00000000000000000000000000001111 SignBits:28 IsKnownNeverZero:1
+  ; CHECK-NEXT: %1:_ KnownBits:00000000000000000000000000001111 SignBits:28 IsKnownNeverZero:1
+  ; CHECK-NEXT: %2:_ KnownBits:00000000000000000000000000001111 SignBits:28 IsKnownNeverZero:1
+    %0:_(i32) = G_CONSTANT i32 15
+    %1:_(f32) = G_BITCAST %0
+    %2:_(i32) = G_BITCAST %1
+...
+---
+# Large->Small: i32 with known zero high 16 bits -> <2 x i16>
+# Element 1 (high i16) should be known zero
+# Verified via G_EXTRACT_VECTOR_ELT which demands only element 1
+name: Bitcast_LargeToSmall_HighElt_KnownZero
+body: |
+  bb.0:
+  ; CHECK-LABEL: name: @Bitcast_LargeToSmall_HighElt_KnownZero
+  ; CHECK-NEXT: %0:_ KnownBits:???????????????????????????????? SignBits:1 IsKnownNeverZero:0
+  ; CHECK-NEXT: %1:_ KnownBits:00000000000000001111111111111111 SignBits:16 IsKnownNeverZero:1
+  ; CHECK-NEXT: %2:_ KnownBits:0000000000000000???????????????? SignBits:16 IsKnownNeverZero:0
+  ; CHECK-NEXT: %3:_ KnownBits:???????????????? SignBits:1 IsKnownNeverZero:0
+  ; CHECK-NEXT: %4:_ KnownBits:0000000000000000000000000000000000000000000000000000000000000001 SignBits:63 IsKnownNeverZero:1
+  ; CHECK-NEXT: %5:_ KnownBits:0000000000000000 SignBits:16 IsKnownNeverZero:0
+    %0:_(i32) = COPY $w0
+    %1:_(i32) = G_CONSTANT i32 65535
+    %2:_(i32) = G_AND %0, %1
+    %3:_(<2 x i16>) = G_BITCAST %2
+    %4:_(i64) = G_CONSTANT i64 1
+    %5:_(i16) = G_EXTRACT_VECTOR_ELT %3, %4
+...
+---
+# Small->Large: <2 x i16> with known zero high bytes -> i32
+name: Bitcast_SmallToLarge_KnownZero
+body: |
+  bb.0:
+  ; CHECK-LABEL: name: @Bitcast_SmallToLarge_KnownZero
+  ; CHECK-NEXT: %0:_ KnownBits:???????????????? SignBits:1 IsKnownNeverZero:0
+  ; CHECK-NEXT: %1:_ KnownBits:0000000011111111 SignBits:8 IsKnownNeverZero:1
+  ; CHECK-NEXT: %2:_ KnownBits:00000000???????? SignBits:8 IsKnownNeverZero:0
+  ; CHECK-NEXT: %3:_ KnownBits:???????????????? SignBits:1 IsKnownNeverZero:0
+  ; CHECK-NEXT: %4:_ KnownBits:00000000???????? SignBits:8 IsKnownNeverZero:0
+  ; CHECK-NEXT: %5:_ KnownBits:00000000???????? SignBits:8 IsKnownNeverZero:0
+  ; CHECK-NEXT: %6:_ KnownBits:00000000????????00000000???????? SignBits:8 IsKnownNeverZero:0
+    %0:_(i16) = COPY $h0
+    %1:_(i16) = G_CONSTANT i16 255
+    %2:_(i16) = G_AND %0, %1
+    %3:_(i16) = COPY $h1
+    %4:_(i16) = G_AND %3, %1
+    %5:_(<2 x i16>) = G_BUILD_VECTOR %2, %4
+    %6:_(i32) = G_BITCAST %5
+...



More information about the llvm-commits mailing list