[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