[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