[llvm] [GlobalISel] Handle width mismatches in vector element value tracking (PR #223623)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 15 01:14:40 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>
`G_INSERT_VECTOR_ELT` and `G_EXTRACT_VECTOR_ELT` accept a scalar of any width; the verifier only requires a scalar or pointer. Two analyses assume the element's width:
- The known-bits case for inserts zero-extends a value narrower than the element, claiming upper bits that nothing defines. Inserting an i8 constant 3 into a `<4 x i16>` reports the lane as `0000000000000011`. SelectionDAG only defines the wider case, implicit truncation. Treat the narrower value as any-extended, giving `????????00000011`. The sign-bits case already bails on any width mismatch (#<!-- -->213480).
- `computeKnownFPClass` returns the lane's class for an extract whose result has a different width than the element, and for an insert whose value does. Bail out in both cases. These are covered by unit tests, since the value-tracking printer does not print FP classes.
Companion to #<!-- -->223554, which covers the integer analyses for extracts. Nothing in tree produces these shapes today; the AArch64 legalizer rule for inserts constrains only the vector type, so they pass legalization.
Assisted by Claude (Anthropic).
CC @<!-- -->arsenm @<!-- -->davemgreen @<!-- -->deepakshirkem
---
Full diff: https://github.com/llvm/llvm-project/pull/223623.diff
3 Files Affected:
- (modified) llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp (+14-1)
- (modified) llvm/test/CodeGen/AArch64/GlobalISel/knownbits-insert-vector.mir (+24)
- (modified) llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp (+57)
``````````diff
diff --git a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
index 4cdbeeebc39bb..f9d6ba4643228 100644
--- a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
@@ -1053,7 +1053,9 @@ void GISelValueTracking::computeKnownBitsImpl(Register R, KnownBits &Known,
Known.setAllConflict();
if (DemandedVal) {
computeKnownBitsImpl(InVal, Known2, APInt(1, 1), Depth + 1);
- Known = Known.intersectWith(Known2.zextOrTrunc(BitWidth));
+ // A wider value is implicitly truncated. A narrower one is any-extended,
+ // so its upper bits are unknown.
+ Known = Known.intersectWith(Known2.anyextOrTrunc(BitWidth));
}
if (!!DemandedVecElts) {
computeKnownBitsImpl(InVec, Known2, DemandedVecElts, Depth + 1);
@@ -2048,6 +2050,11 @@ void GISelValueTracking::computeKnownFPClass(Register R,
LLT VecTy = MRI.getType(Vec);
+ // A result of a different width than the element does not carry the
+ // lane's class.
+ if (VecTy.getScalarSizeInBits() != DstTy.getScalarSizeInBits())
+ break;
+
if (VecTy.isFixedVector()) {
unsigned NumElts = VecTy.getNumElements();
APInt DemandedVecElts = APInt::getAllOnes(NumElts);
@@ -2081,6 +2088,12 @@ void GISelValueTracking::computeKnownFPClass(Register R,
NeedsElt = DemandedElts[CIdx->getZExtValue()];
}
+ // An inserted value of a different width than the element does not carry
+ // the lane's class.
+ if (NeedsElt &&
+ MRI.getType(Elt).getScalarSizeInBits() != DstTy.getScalarSizeInBits())
+ break;
+
// Do we demand the inserted element?
if (NeedsElt) {
computeKnownFPClass(Elt, Known, InterestedClasses, Depth + 1);
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-insert-vector.mir b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-insert-vector.mir
index b80e3eba35bca..d036987179989 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-insert-vector.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-insert-vector.mir
@@ -97,3 +97,27 @@ body: |
%4:_(i8) = G_CONSTANT i8 6
%5:_(<2 x i8>) = G_INSERT_VECTOR_ELT %3, %4, %idx
...
+---
+# computeKnownBits: an inserted value narrower than the element is any-extended,
+# so the upper bits of that lane are unknown. The other lanes are unaffected.
+name: knownbits_narrower_inserted_value
+body: |
+ bb.0:
+ ; CHECK-LABEL: name: @knownbits_narrower_inserted_value
+ ; CHECK-NEXT: %c:_ KnownBits:0000000000000011 SignBits:14 IsKnownNeverZero:1
+ ; CHECK-NEXT: %v:_ KnownBits:0000000000000011 SignBits:14 IsKnownNeverZero:1
+ ; CHECK-NEXT: %val:_ KnownBits:00000011 SignBits:6 IsKnownNeverZero:1
+ ; CHECK-NEXT: %idx0:_ KnownBits:0000000000000000000000000000000000000000000000000000000000000000 SignBits:64 IsKnownNeverZero:0
+ ; CHECK-NEXT: %idx1:_ KnownBits:0000000000000000000000000000000000000000000000000000000000000001 SignBits:63 IsKnownNeverZero:1
+ ; CHECK-NEXT: %r:_ KnownBits:????????00000011 SignBits:1 IsKnownNeverZero:1
+ ; CHECK-NEXT: %e0:_ KnownBits:????????00000011 SignBits:1 IsKnownNeverZero:1
+ ; CHECK-NEXT: %e1:_ KnownBits:0000000000000011 SignBits:14 IsKnownNeverZero:1
+ %c:_(i16) = G_CONSTANT i16 3
+ %v:_(<4 x i16>) = G_BUILD_VECTOR %c, %c, %c, %c
+ %val:_(i8) = G_CONSTANT i8 3
+ %idx0:_(i64) = G_CONSTANT i64 0
+ %idx1:_(i64) = G_CONSTANT i64 1
+ %r:_(<4 x i16>) = G_INSERT_VECTOR_ELT %v, %val, %idx0
+ %e0:_(i16) = G_EXTRACT_VECTOR_ELT %r, %idx0
+ %e1:_(i16) = G_EXTRACT_VECTOR_ELT %r, %idx1
+...
diff --git a/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp b/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp
index f5ac377f4f585..522f8d2304407 100644
--- a/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp
+++ b/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp
@@ -1897,3 +1897,60 @@ TEST_F(AArch64GISelMITest, TestFPClassFMASelfSquare) {
EXPECT_EQ(fcNan | fcPosInf | fcPosNormal, Known.getKnownFPClasses());
EXPECT_EQ(std::nullopt, Known.getSignBit());
}
+
+TEST_F(AArch64GISelMITest, TestFPClassExtractVectorEltWiderResult) {
+ StringRef MIRString = R"(
+ %c0:_(s16) = G_FCONSTANT half 0xH0000
+ %c1:_(s16) = G_FCONSTANT half 0xH0000
+ %vector:_(<2 x s16>) = G_BUILD_VECTOR %c0, %c1
+ %idx:_(s64) = G_CONSTANT i64 0
+ %elt:_(s32) = G_EXTRACT_VECTOR_ELT %vector, %idx
+ %copy_elt:_(s32) = COPY %elt
+)";
+
+ setUp(MIRString);
+ if (!TM)
+ GTEST_SKIP();
+
+ Register CopyReg = Copies[Copies.size() - 1];
+ MachineInstr *FinalCopy = MRI->getVRegDef(CopyReg);
+ Register SrcReg = FinalCopy->getOperand(1).getReg();
+
+ GISelValueTracking Info(*MF);
+
+ // The result is wider than the element, so it does not carry the lane's
+ // class.
+ KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
+
+ EXPECT_EQ(fcAllFlags, Known.getKnownFPClasses());
+ EXPECT_EQ(std::nullopt, Known.getSignBit());
+}
+
+TEST_F(AArch64GISelMITest, TestFPClassInsertVectorEltNarrowerValue) {
+ StringRef MIRString = R"(
+ %c0:_(s32) = G_FCONSTANT float 0.0
+ %c1:_(s32) = G_FCONSTANT float 0.0
+ %vector:_(<2 x s32>) = G_BUILD_VECTOR %c0, %c1
+ %val:_(s16) = G_FCONSTANT half 0xH0000
+ %idx:_(s64) = G_CONSTANT i64 0
+ %ins:_(<2 x s32>) = G_INSERT_VECTOR_ELT %vector, %val, %idx
+ %copy_ins:_(<2 x s32>) = COPY %ins
+)";
+
+ setUp(MIRString);
+ if (!TM)
+ GTEST_SKIP();
+
+ Register CopyReg = Copies[Copies.size() - 1];
+ MachineInstr *FinalCopy = MRI->getVRegDef(CopyReg);
+ Register SrcReg = FinalCopy->getOperand(1).getReg();
+
+ GISelValueTracking Info(*MF);
+
+ // The inserted value is narrower than the element, so the demanded lane
+ // does not carry its class.
+ KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
+
+ EXPECT_EQ(fcAllFlags, Known.getKnownFPClasses());
+ EXPECT_EQ(std::nullopt, Known.getSignBit());
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/223623
More information about the llvm-commits
mailing list