[llvm] [GlobalISel] Add G_EXTRACT_VECTOR_ELT and G_INSERT_VECTOR_ELT to computeNumSignBits (PR #213480)

via llvm-commits llvm-commits at lists.llvm.org
Sat Aug 1 12:19:46 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-aarch64

Author: Joel Walker  (Joel-Wwalker)

<details>
<summary>Changes</summary>

`computeKnownBitsImpl` already handles both opcodes, but `computeNumSignBits` fell through to the known-bits fallback, which loses sign information that is not representable as known bits (e.g. sign-extended values: an extract from a `G_SEXT`-produced vector reported 1 sign bit instead of 25).

Port the corresponding SelectionDAG cases: for extracts, demand the selected lane when the index is a known constant (all lanes otherwise) and bail when the result is wider than the element; for inserts, split the demand between the inserted value and the remaining lanes, bailing on implicitly truncated inserts. The structure mirrors the existing known-bits cases for the same opcodes.

Assisted by Claude (Anthropic).


---
Full diff: https://github.com/llvm/llvm-project/pull/213480.diff


4 Files Affected:

- (modified) llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp (+59) 
- (modified) llvm/test/CodeGen/AArch64/GlobalISel/knownbits-extract-vector.mir (+54-2) 
- (modified) llvm/test/CodeGen/AArch64/GlobalISel/knownbits-insert-vector.mir (+29) 
- (modified) llvm/test/CodeGen/AArch64/neon-extadd-extract.ll (+1-1) 


``````````diff
diff --git a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
index 7ff23d8e1bd6e..580646dc22fec 100644
--- a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
@@ -38,6 +38,7 @@
 #include "llvm/Support/KnownBits.h"
 #include "llvm/Support/KnownFPClass.h"
 #include "llvm/Target/TargetMachine.h"
+#include <limits>
 
 #define DEBUG_TYPE "gisel-known-bits"
 
@@ -2583,6 +2584,64 @@ unsigned GISelValueTracking::computeNumSignBits(Register R,
       return NumSrcSignBits - (NumSrcBits - TyBits);
     break;
   }
+  case TargetOpcode::G_EXTRACT_VECTOR_ELT: {
+    GExtractVectorElement &Extract = cast<GExtractVectorElement>(MI);
+    Register InVec = Extract.getVectorReg();
+    LLT VecVT = MRI.getType(InVec);
+    // computeNumSignBits not yet implemented for scalable vectors.
+    if (VecVT.isScalableVector())
+      break;
+
+    // If the result is wider than the element type the value is extended, and
+    // we know nothing about the extended bits.
+    const unsigned EltBitWidth = VecVT.getScalarSizeInBits();
+    if (TyBits != EltBitWidth)
+      break;
+
+    // If we know the element index, just demand that vector element, else for
+    // an unknown element index, ignore DemandedElts and demand them all.
+    const unsigned NumSrcElts = VecVT.getNumElements();
+    APInt DemandedSrcElts = APInt::getAllOnes(NumSrcElts);
+    auto ConstEltNo = getIConstantVRegVal(Extract.getIndexReg(), MRI);
+    if (ConstEltNo && ConstEltNo->ult(NumSrcElts))
+      DemandedSrcElts =
+          APInt::getOneBitSet(NumSrcElts, ConstEltNo->getZExtValue());
+
+    return computeNumSignBits(InVec, DemandedSrcElts, Depth + 1);
+  }
+  case TargetOpcode::G_INSERT_VECTOR_ELT: {
+    GInsertVectorElement &Insert = cast<GInsertVectorElement>(MI);
+    Register InVec = Insert.getVectorReg();
+    Register InVal = Insert.getElementReg();
+    LLT VecVT = MRI.getType(InVec);
+    if (VecVT.isScalableVector())
+      break;
+
+    // If we know the element index, split the demand between the inserted
+    // value and the source vector, otherwise assume we need both.
+    const unsigned NumElts = VecVT.getNumElements();
+    bool DemandedVal = true;
+    APInt DemandedVecElts = DemandedElts;
+    auto ConstEltNo = getIConstantVRegVal(Insert.getIndexReg(), MRI);
+    if (ConstEltNo && ConstEltNo->ult(NumElts)) {
+      unsigned EltIdx = ConstEltNo->getZExtValue();
+      DemandedVal = !!DemandedElts[EltIdx];
+      DemandedVecElts.clearBit(EltIdx);
+    }
+
+    unsigned Tmp = std::numeric_limits<unsigned>::max();
+    if (DemandedVal) {
+      // TODO: Handle implicit truncation of inserted elements.
+      if (MRI.getType(InVal).getSizeInBits() != TyBits)
+        break;
+      Tmp = std::min(Tmp, computeNumSignBits(InVal, APInt(1, 1), Depth + 1));
+    }
+    if (!!DemandedVecElts)
+      Tmp =
+          std::min(Tmp, computeNumSignBits(InVec, DemandedVecElts, Depth + 1));
+    assert(Tmp <= TyBits && "Failed to determine minimum sign bits");
+    return Tmp;
+  }
   case TargetOpcode::G_INTRINSIC:
   case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
   case TargetOpcode::G_INTRINSIC_CONVERGENT:
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-extract-vector.mir b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-extract-vector.mir
index 7ff593f18adc9..bfc3fa3b7ce82 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-extract-vector.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-extract-vector.mir
@@ -94,7 +94,7 @@ body: |
   ; CHECK-NEXT: %0:_ KnownBits:???????? SignBits:1
   ; CHECK-NEXT: %sext0:_ KnownBits:???????????????? SignBits:9
   ; CHECK-NEXT: %idx:_ KnownBits:0000000000000000000000000000000000000000000000000000000000000001 SignBits:63
-  ; CHECK-NEXT: %3:_ KnownBits:???????????????? SignBits:1
+  ; CHECK-NEXT: %3:_ KnownBits:???????????????? SignBits:9
     %0:_(<2 x i8>) = COPY $h0
     %sext0:_(<2 x i16>) = G_SEXT %0
     %idx:_(i64) = G_CONSTANT i64 1
@@ -108,7 +108,7 @@ body: |
   ; CHECK-NEXT: %0:_ KnownBits:???????? SignBits:1
   ; CHECK-NEXT: %sext0:_ KnownBits:???????????????? SignBits:9
   ; CHECK-NEXT: %idx:_ KnownBits:???????????????????????????????????????????????????????????????? SignBits:1
-  ; CHECK-NEXT: %3:_ KnownBits:???????????????? SignBits:1
+  ; CHECK-NEXT: %3:_ KnownBits:???????????????? SignBits:9
     %0:_(<2 x i8>) = COPY $h0
     %sext0:_(<2 x i16>) = G_SEXT %0
     %idx:_(i64) = COPY $d1
@@ -131,3 +131,55 @@ body: |
     %2:_(<2 x i8>) = G_BUILD_VECTOR %0, %1
     %idx:_(i64) = G_CONSTANT i64 1
     %3:_(i16) = G_EXTRACT_VECTOR_ELT %2, %idx
+...
+---
+name: extract_sext_elements
+body: |
+  bb.1:
+    liveins: $w0, $w1, $x2
+  ; CHECK-LABEL: name: @extract_sext_elements
+  ; CHECK-NEXT: %w0:_ KnownBits:???????????????????????????????? SignBits:1
+  ; CHECK-NEXT: %w1:_ KnownBits:???????????????????????????????? SignBits:1
+  ; CHECK-NEXT: %unk:_ KnownBits:???????????????????????????????????????????????????????????????? SignBits:1
+  ; CHECK-NEXT: %a:_ KnownBits:???????? SignBits:1
+  ; CHECK-NEXT: %s0:_ KnownBits:???????????????????????????????? SignBits:25
+  ; CHECK-NEXT: %s1:_ KnownBits:???????????????????????????????? SignBits:17
+  ; CHECK-NEXT: %v:_ KnownBits:???????????????????????????????? SignBits:17
+  ; CHECK-NEXT: %idx0:_ KnownBits:0000000000000000000000000000000000000000000000000000000000000000 SignBits:64
+  ; CHECK-NEXT: %e0:_ KnownBits:???????????????????????????????? SignBits:25
+  ; CHECK-NEXT: %eu:_ KnownBits:???????????????????????????????? SignBits:17
+    %w0:_(i32) = COPY $w0
+    %w1:_(i32) = COPY $w1
+    %unk:_(i64) = COPY $x2
+    %a:_(i8) = G_TRUNC %w0
+    %s0:_(i32) = G_SEXT %a
+    %s1:_(i32) = G_SEXT_INREG %w1, 16
+    %v:_(<2 x i32>) = G_BUILD_VECTOR %s0, %s1
+    %idx0:_(i64) = G_CONSTANT i64 0
+    %e0:_(i32) = G_EXTRACT_VECTOR_ELT %v, %idx0
+    %eu:_(i32) = G_EXTRACT_VECTOR_ELT %v, %unk
+    $w0 = COPY %e0(i32)
+    $w1 = COPY %eu(i32)
+...
+---
+name: extract_widened_result
+body: |
+  bb.1:
+    liveins: $w0, $w1
+  ; CHECK-LABEL: name: @extract_widened_result
+  ; CHECK-NEXT: %w0:_ KnownBits:???????????????????????????????? SignBits:1
+  ; CHECK-NEXT: %w1:_ KnownBits:???????????????????????????????? SignBits:1
+  ; CHECK-NEXT: %a:_ KnownBits:???????? SignBits:1
+  ; CHECK-NEXT: %b:_ KnownBits:???????? SignBits:1
+  ; CHECK-NEXT: %v:_ KnownBits:???????? SignBits:1
+  ; CHECK-NEXT: %idx0:_ KnownBits:0000000000000000000000000000000000000000000000000000000000000000 SignBits:64
+  ; CHECK-NEXT: %e:_ KnownBits:???????????????????????????????? SignBits:1
+    %w0:_(i32) = COPY $w0
+    %w1:_(i32) = COPY $w1
+    %a:_(i8) = G_TRUNC %w0
+    %b:_(i8) = G_TRUNC %w1
+    %v:_(<2 x i8>) = G_BUILD_VECTOR %a, %b
+    %idx0:_(i64) = G_CONSTANT i64 0
+    %e:_(i32) = G_EXTRACT_VECTOR_ELT %v, %idx0
+    $w0 = COPY %e(i32)
+...
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-insert-vector.mir b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-insert-vector.mir
index 5a3985a109a0c..52d022b875813 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-insert-vector.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-insert-vector.mir
@@ -97,3 +97,32 @@ body: |
     %4:_(i8) = G_CONSTANT i8 6
     %5:_(<2 x i8>) = G_INSERT_VECTOR_ELT %3, %4, %idx
 ...
+---
+name: insert_sext_elements
+body: |
+  bb.1:
+    liveins: $w0, $w1, $x2
+  ; CHECK-LABEL: name: @insert_sext_elements
+  ; CHECK-NEXT: %w0:_ KnownBits:???????????????????????????????? SignBits:1
+  ; CHECK-NEXT: %w1:_ KnownBits:???????????????????????????????? SignBits:1
+  ; CHECK-NEXT: %unk:_ KnownBits:???????????????????????????????????????????????????????????????? SignBits:1
+  ; CHECK-NEXT: %a:_ KnownBits:???????? SignBits:1
+  ; CHECK-NEXT: %s0:_ KnownBits:???????????????????????????????? SignBits:25
+  ; CHECK-NEXT: %v:_ KnownBits:???????????????????????????????? SignBits:25
+  ; CHECK-NEXT: %val:_ KnownBits:???????????????????????????????? SignBits:17
+  ; CHECK-NEXT: %idx0:_ KnownBits:0000000000000000000000000000000000000000000000000000000000000000 SignBits:64
+  ; CHECK-NEXT: %r0:_ KnownBits:???????????????????????????????? SignBits:17
+  ; CHECK-NEXT: %ru:_ KnownBits:???????????????????????????????? SignBits:17
+    %w0:_(i32) = COPY $w0
+    %w1:_(i32) = COPY $w1
+    %unk:_(i64) = COPY $x2
+    %a:_(i8) = G_TRUNC %w0
+    %s0:_(i32) = G_SEXT %a
+    %v:_(<2 x i32>) = G_BUILD_VECTOR %s0, %s0
+    %val:_(i32) = G_SEXT_INREG %w1, 16
+    %idx0:_(i64) = G_CONSTANT i64 0
+    %r0:_(<2 x i32>) = G_INSERT_VECTOR_ELT %v, %val, %idx0
+    %ru:_(<2 x i32>) = G_INSERT_VECTOR_ELT %v, %val, %unk
+    $d0 = COPY %r0(<2 x i32>)
+    $d1 = COPY %ru(<2 x i32>)
+...
diff --git a/llvm/test/CodeGen/AArch64/neon-extadd-extract.ll b/llvm/test/CodeGen/AArch64/neon-extadd-extract.ll
index b35511dd4ab69..ae21d8f339dd3 100644
--- a/llvm/test/CodeGen/AArch64/neon-extadd-extract.ll
+++ b/llvm/test/CodeGen/AArch64/neon-extadd-extract.ll
@@ -683,7 +683,7 @@ define <1 x i64> @mulls_v2i32_0(<2 x i32> %s0, <2 x i32> %s1) {
 ; CHECK-GI-NEXT:    sshll v1.2d, v1.2s, #0
 ; CHECK-GI-NEXT:    fmov x8, d0
 ; CHECK-GI-NEXT:    fmov x9, d1
-; CHECK-GI-NEXT:    mul x8, x8, x9
+; CHECK-GI-NEXT:    smull x8, w8, w9
 ; CHECK-GI-NEXT:    fmov d0, x8
 ; CHECK-GI-NEXT:    ret
 entry:

``````````

</details>


https://github.com/llvm/llvm-project/pull/213480


More information about the llvm-commits mailing list