[llvm] [GlobalISel] emit G_BITCAST in widenScalarMergeValues when DstTy does not match WideTy (PR #203014)

via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 10 08:27:32 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-globalisel

Author: Kacper Doga (varev-dev)

<details>
<summary>Changes</summary>

**Problem:**
`LegalizerHelper::widenScalarMergeValues` does not handle the case where the destination register type is a floating-point type but the widen operation produces an integer type of the same size.

For example, given:
```
%0:_(i8) = G_CONSTANT i8 0
%1:_(i8) = G_CONSTANT i8 1
%2:_(f16) = G_MERGE_VALUES %0:_(i8), %1_:(i8)
```
With a `minScalarOrElt` rule widening the source type to I16, `widenScalarMergeValues` enters the `WideSize >= DstSize` path and assigns the result to a new virtual register. The condition used to assign directly to DstReg uses type equality (WideTy == DstTy), which fails when DstTy = f16. As a result, DstReg is left without a definition.

**Fix:**
After the OR-reduction loop, add a check for the case where DstTy and WideTy have equal sizes but different types, and emit a G_BITCAST.

**Testing:**
No currently upstream target exercises `G_MERGE_VALUES` with a floating-point destination type through this widen path, as most targets promote f16 to s16 before legalization. The fix is therefore covered by a unit test in `LegalizerHelperTest.cpp`, modeled after the existing `WidenScalarMergeValuesPointer` test, which directly invokes widenScalar on a manually constructed `f16 = G_MERGE_VALUES i8, i8` instruction and verifies that a `G_BITCAST` is emitted as the final instruction.

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


2 Files Affected:

- (modified) llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp (+2) 
- (modified) llvm/unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp (+40) 


``````````diff
diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
index afe93f617a119..ee0ced14f5361 100644
--- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
@@ -2266,6 +2266,8 @@ LegalizerHelper::widenScalarMergeValues(MachineInstr &MI, unsigned TypeIdx,
       MIRBuilder.buildTrunc(DstReg, ResultReg);
     else if (DstTy.isPointer())
       MIRBuilder.buildIntToPtr(DstReg, ResultReg);
+    else if (WideSize == DstSize && DstTy != WideTy)
+      MIRBuilder.buildBitcast(DstReg, ResultReg);
 
     MI.eraseFromParent();
     return Legalized;
diff --git a/llvm/unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp b/llvm/unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp
index 809d8880faaed..0992d6219b91d 100644
--- a/llvm/unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp
+++ b/llvm/unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp
@@ -1897,6 +1897,46 @@ TEST_F(AArch64GISelMITest, WidenScalarMergeValuesPointer) {
   EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF;
 }
 
+TEST_F(AArch64GISelMITest, WidenScalarMergeValuesFloat) {
+  setUp();
+  if (!TM)
+    GTEST_SKIP();
+
+  constexpr ElementCount EC0 = ElementCount::getFixed(0);
+  const LLT I8 = LLT(LLT::Kind::INTEGER, EC0, 8);
+  const LLT I16 = LLT(LLT::Kind::INTEGER, EC0, 16);
+  const LLT F16 = LLT::float16();
+
+  DefineLegalizerInfo(A, {});
+
+  AInfo Info(MF->getSubtarget());
+  DummyGISelObserver Observer;
+  LegalizerHelper Helper(*MF, Info, Observer, B);
+  B.setInsertPt(*EntryMBB, EntryMBB->end());
+
+  auto Lo = B.buildTrunc(I8, Copies[0]);
+  auto Hi = B.buildTrunc(I8, Copies[1]);
+
+  auto Merge = B.buildMergeLikeInstr(F16, {Lo, Hi});
+
+  B.setInstr(*Merge);
+  EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized,
+            Helper.widenScalar(*Merge, 1, I16));
+
+  const auto *CheckStr = R"(
+  CHECK: [[TRUNC0:%[0-9]+]]:_(i8) = G_TRUNC
+  CHECK: [[TRUNC1:%[0-9]+]]:_(i8) = G_TRUNC
+  CHECK: [[ZEXT_TRUNC0:%[0-9]+]]:_(i16) = G_ZEXT [[TRUNC0]]
+  CHECK: [[ZEXT_TRUNC1:%[0-9]+]]:_(i16) = G_ZEXT [[TRUNC1]]
+  CHECK: [[SHIFT_AMT:%[0-9]+]]:_(i16) = G_CONSTANT i16 8
+  CHECK: [[SHL:%[0-9]+]]:_(i16) = G_SHL [[ZEXT_TRUNC1]]:_, [[SHIFT_AMT]]
+  CHECK: [[OR:%[0-9]+]]:_(i16) = G_OR [[ZEXT_TRUNC0]]:_, [[SHL]]
+  CHECK: [[BITCAST:%[0-9]+]]:_(f16) = G_BITCAST [[OR]]:_(i16)
+  )";
+
+  EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF;
+}
+
 TEST_F(AArch64GISelMITest, WidenSEXTINREG) {
   setUp();
   if (!TM)

``````````

</details>


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


More information about the llvm-commits mailing list