[llvm] [GlobalISel] emit G_BITCAST in widenScalarMergeValues when DstTy does not match WideTy (PR #203014)
Kacper Doga via llvm-commits
llvm-commits at lists.llvm.org
Sun Jul 19 23:47:46 PDT 2026
https://github.com/varev-dev updated https://github.com/llvm/llvm-project/pull/203014
>From 1bbb98479dad1d35a5e8f9cf5bca5661d5fb6f28 Mon Sep 17 00:00:00 2001
From: "Doga, Kacper" <kacper.doga at intel.com>
Date: Wed, 10 Jun 2026 17:07:22 +0200
Subject: [PATCH 1/3] [GlobalISel] emit G_BITCAST in widenScalarMergeValues
when DstTy does not match WideTy
**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.
---
.../CodeGen/GlobalISel/LegalizerHelper.cpp | 2 +
.../GlobalISel/LegalizerHelperTest.cpp | 40 +++++++++++++++++++
2 files changed, 42 insertions(+)
diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
index 021f7233ce3b7..39358f5e342b5 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 41669ffb72360..d5af3228156ea 100644
--- a/llvm/unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp
+++ b/llvm/unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp
@@ -1895,6 +1895,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)
>From 25ff4c50d37d08b1de7dc742b101deead1ff1eff Mon Sep 17 00:00:00 2001
From: "Doga, Kacper" <kacper.doga at intel.com>
Date: Thu, 11 Jun 2026 08:41:32 +0200
Subject: [PATCH 2/3] add coverage for bfloat, remove redundant size comparison
---
.../CodeGen/GlobalISel/LegalizerHelper.cpp | 2 +-
.../GlobalISel/LegalizerHelperTest.cpp | 40 +++++++++++++++++++
2 files changed, 41 insertions(+), 1 deletion(-)
diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
index 39358f5e342b5..114c974c59e94 100644
--- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
@@ -2266,7 +2266,7 @@ LegalizerHelper::widenScalarMergeValues(MachineInstr &MI, unsigned TypeIdx,
MIRBuilder.buildTrunc(DstReg, ResultReg);
else if (DstTy.isPointer())
MIRBuilder.buildIntToPtr(DstReg, ResultReg);
- else if (WideSize == DstSize && DstTy != WideTy)
+ else if (DstTy != WideTy)
MIRBuilder.buildBitcast(DstReg, ResultReg);
MI.eraseFromParent();
diff --git a/llvm/unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp b/llvm/unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp
index d5af3228156ea..aee44bcdcb914 100644
--- a/llvm/unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp
+++ b/llvm/unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp
@@ -1935,6 +1935,46 @@ TEST_F(AArch64GISelMITest, WidenScalarMergeValuesFloat) {
EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF;
}
+TEST_F(AArch64GISelMITest, WidenScalarMergeValuesBFloat) {
+ 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 BF16 = LLT::bfloat16();
+
+ 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(BF16, {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]+]]:_(bf16) = G_BITCAST [[OR]]:_(i16)
+ )";
+
+ EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF;
+}
+
TEST_F(AArch64GISelMITest, WidenSEXTINREG) {
setUp();
if (!TM)
>From 6cbb2054a601aa756bb9a21550f956e577d770e1 Mon Sep 17 00:00:00 2001
From: "Doga, Kacper" <kacper.doga at intel.com>
Date: Mon, 20 Jul 2026 08:42:34 +0200
Subject: [PATCH 3/3] change llt int def
---
.../CodeGen/GlobalISel/LegalizerHelperTest.cpp | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/llvm/unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp b/llvm/unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp
index aee44bcdcb914..4204c2dcc09a4 100644
--- a/llvm/unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp
+++ b/llvm/unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp
@@ -1900,9 +1900,8 @@ TEST_F(AArch64GISelMITest, WidenScalarMergeValuesFloat) {
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 I8 = LLT::integer(8);
+ const LLT I16 = LLT::integer(16);
const LLT F16 = LLT::float16();
DefineLegalizerInfo(A, {});
@@ -1940,9 +1939,8 @@ TEST_F(AArch64GISelMITest, WidenScalarMergeValuesBFloat) {
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 I8 = LLT::integer(8);
+ const LLT I16 = LLT::integer(16);
const LLT BF16 = LLT::bfloat16();
DefineLegalizerInfo(A, {});
More information about the llvm-commits
mailing list