[llvm] 2cce9ec - [GlobalISel] emit G_BITCAST in widenScalarUnmergeValues when SrcTy is float (#204541)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Aug 12 06:23:44 PDT 2026
Author: MiĆosz
Date: 2026-08-12T15:23:38+02:00
New Revision: 2cce9ec58940d26ebcf8c185d5f2992d5f47b36d
URL: https://github.com/llvm/llvm-project/commit/2cce9ec58940d26ebcf8c185d5f2992d5f47b36d
DIFF: https://github.com/llvm/llvm-project/commit/2cce9ec58940d26ebcf8c185d5f2992d5f47b36d.diff
LOG: [GlobalISel] emit G_BITCAST in widenScalarUnmergeValues when SrcTy is float (#204541)
widenScalarUnmergeValues emits G_LSHR and G_TRUNC to extract
sub-register pieces from the source. The shift amount and the shift
itself are built with SrcTy, so when the source is a floating-point
scalar (e.g. bf16) the extraction ends up in the float domain:
```
%1:_(bf16) = G_CONSTANT i16 8
%2:_(bf16) = G_LSHR %0:_(bf16), %1:_(bf16)
```
**Fix:** Before the shift/trunc extraction sequence, check if SrcTy is a
float type and bitcast it to the corresponding integer type.
Added:
llvm/test/CodeGen/AMDGPU/GlobalISel/legalize-unmerge-values-float-src.mir
Modified:
llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
llvm/test/CodeGen/AMDGPU/GlobalISel/fp-int-conversions.ll
Removed:
################################################################################
diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
index 79bd8b1b1f66f..914993a581085 100644
--- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
@@ -2421,6 +2421,11 @@ LegalizerHelper::widenScalarUnmergeValues(MachineInstr &MI, unsigned TypeIdx,
// source type
unsigned DstSize = DstTy.getSizeInBits();
+ if (SrcTy.isFloat()) {
+ SrcReg = coerceToInteger(SrcReg);
+ SrcTy = MRI.getType(SrcReg);
+ }
+
MIRBuilder.buildTrunc(Dst0Reg, SrcReg);
for (int I = 1; I != NumDst; ++I) {
auto ShiftAmt = MIRBuilder.buildConstant(SrcTy, DstSize * I);
diff --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/fp-int-conversions.ll b/llvm/test/CodeGen/AMDGPU/GlobalISel/fp-int-conversions.ll
index cdc83b0aab25e..26fab4aeb914f 100644
--- a/llvm/test/CodeGen/AMDGPU/GlobalISel/fp-int-conversions.ll
+++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/fp-int-conversions.ll
@@ -783,5 +783,47 @@ define amdgpu_ps bfloat @fptosi_v2f32_to_v2i8_bitcast_bf16(<2 x float> %v) {
%res = bitcast <2 x i8> %cvt to bfloat
ret bfloat %res
}
+
+define amdgpu_ps <2 x i8> @bitcast_f16_to_v2i8(ptr addrspace(1) %ptr) {
+; TRUE16-LABEL: bitcast_f16_to_v2i8:
+; TRUE16: ; %bb.0:
+; TRUE16: global_load_d16_b16 v0, v[0:1], off
+; TRUE16: v_lshrrev_b16 v1.l, 8, v0.l
+; TRUE16: v_readfirstlane_b32 s0, v0
+; TRUE16: v_readfirstlane_b32 s1, v1
+; TRUE16: ; return to shader part epilog
+;
+; GFX12-LABEL: bitcast_f16_to_v2i8:
+; GFX12: ; %bb.0:
+; GFX12: global_load_d16_b16 v0, v[0:1], off
+; GFX12: v_lshrrev_b16 v1.l, 8, v0.l
+; GFX12: v_readfirstlane_b32 s0, v0
+; GFX12: v_readfirstlane_b32 s1, v1
+; GFX12: ; return to shader part epilog
+ %val = load half, ptr addrspace(1) %ptr
+ %res = bitcast half %val to <2 x i8>
+ ret <2 x i8> %res
+}
+
+define amdgpu_ps <2 x i8> @bitcast_bf16_to_v2i8(ptr addrspace(1) %ptr) {
+; TRUE16-LABEL: bitcast_bf16_to_v2i8:
+; TRUE16: ; %bb.0:
+; TRUE16: global_load_d16_b16 v0, v[0:1], off
+; TRUE16: v_lshrrev_b16 v1.l, 8, v0.l
+; TRUE16: v_readfirstlane_b32 s0, v0
+; TRUE16: v_readfirstlane_b32 s1, v1
+; TRUE16: ; return to shader part epilog
+;
+; GFX12-LABEL: bitcast_bf16_to_v2i8:
+; GFX12: ; %bb.0:
+; GFX12: global_load_d16_b16 v0, v[0:1], off
+; GFX12: v_lshrrev_b16 v1.l, 8, v0.l
+; GFX12: v_readfirstlane_b32 s0, v0
+; GFX12: v_readfirstlane_b32 s1, v1
+; GFX12: ; return to shader part epilog
+ %val = load bfloat, ptr addrspace(1) %ptr
+ %res = bitcast bfloat %val to <2 x i8>
+ ret <2 x i8> %res
+}
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
; FAKE16: {{.*}}
diff --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/legalize-unmerge-values-float-src.mir b/llvm/test/CodeGen/AMDGPU/GlobalISel/legalize-unmerge-values-float-src.mir
new file mode 100644
index 0000000000000..65bd5fe5fd764
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/legalize-unmerge-values-float-src.mir
@@ -0,0 +1,72 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+# RUN: llc -mtriple=amdgpu12.00 -mattr=+real-true16 -run-pass=legalizer -verify-machineinstrs %s -o - | FileCheck %s
+# Make sure a floating-point G_UNMERGE_VALUES source is bitcast to an integer before the result pieces are extracted with shifts and truncates.
+
+---
+name: test_unmerge_i8_bf16
+body: |
+ bb.0:
+ ; CHECK-LABEL: name: test_unmerge_i8_bf16
+ ; CHECK: [[DEF:%[0-9]+]]:_(p1) = G_IMPLICIT_DEF
+ ; CHECK-NEXT: [[LOAD:%[0-9]+]]:_(bf16) = G_LOAD [[DEF]](p1) :: (load (bf16), addrspace 1)
+ ; CHECK-NEXT: [[BITCAST:%[0-9]+]]:_(i16) = G_BITCAST [[LOAD]](bf16)
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(i16) = G_CONSTANT i16 8
+ ; CHECK-NEXT: [[LSHR:%[0-9]+]]:_(i16) = G_LSHR [[BITCAST]], [[C]](i16)
+ ; CHECK-NEXT: [[ANYEXT:%[0-9]+]]:_(i32) = G_ANYEXT [[BITCAST]](i16)
+ ; CHECK-NEXT: [[ANYEXT1:%[0-9]+]]:_(i32) = G_ANYEXT [[LSHR]](i16)
+ ; CHECK-NEXT: $vgpr0 = COPY [[ANYEXT]](i32)
+ ; CHECK-NEXT: $vgpr1 = COPY [[ANYEXT1]](i32)
+ %0:_(p1) = G_IMPLICIT_DEF
+ %1:_(bf16) = G_LOAD %0 :: (load (bf16), addrspace 1)
+ %2:_(i8), %3:_(i8) = G_UNMERGE_VALUES %1
+ %4:_(i32) = G_ANYEXT %2
+ %5:_(i32) = G_ANYEXT %3
+ $vgpr0 = COPY %4
+ $vgpr1 = COPY %5
+...
+
+---
+name: test_unmerge_i8_f16
+body: |
+ bb.0:
+ ; CHECK-LABEL: name: test_unmerge_i8_f16
+ ; CHECK: [[DEF:%[0-9]+]]:_(p1) = G_IMPLICIT_DEF
+ ; CHECK-NEXT: [[LOAD:%[0-9]+]]:_(f16) = G_LOAD [[DEF]](p1) :: (load (f16), addrspace 1)
+ ; CHECK-NEXT: [[BITCAST:%[0-9]+]]:_(i16) = G_BITCAST [[LOAD]](f16)
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(i16) = G_CONSTANT i16 8
+ ; CHECK-NEXT: [[LSHR:%[0-9]+]]:_(i16) = G_LSHR [[BITCAST]], [[C]](i16)
+ ; CHECK-NEXT: [[ANYEXT:%[0-9]+]]:_(i32) = G_ANYEXT [[BITCAST]](i16)
+ ; CHECK-NEXT: [[ANYEXT1:%[0-9]+]]:_(i32) = G_ANYEXT [[LSHR]](i16)
+ ; CHECK-NEXT: $vgpr0 = COPY [[ANYEXT]](i32)
+ ; CHECK-NEXT: $vgpr1 = COPY [[ANYEXT1]](i32)
+ %0:_(p1) = G_IMPLICIT_DEF
+ %1:_(f16) = G_LOAD %0 :: (load (f16), addrspace 1)
+ %2:_(i8), %3:_(i8) = G_UNMERGE_VALUES %1
+ %4:_(i32) = G_ANYEXT %2
+ %5:_(i32) = G_ANYEXT %3
+ $vgpr0 = COPY %4
+ $vgpr1 = COPY %5
+...
+
+---
+name: test_unmerge_i4_bf16
+body: |
+ bb.0:
+ ; CHECK-LABEL: name: test_unmerge_i4_bf16
+ ; CHECK: [[DEF:%[0-9]+]]:_(p1) = G_IMPLICIT_DEF
+ ; CHECK-NEXT: [[LOAD:%[0-9]+]]:_(bf16) = G_LOAD [[DEF]](p1) :: (load (bf16), addrspace 1)
+ ; CHECK-NEXT: [[BITCAST:%[0-9]+]]:_(i16) = G_BITCAST [[LOAD]](bf16)
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(i16) = G_CONSTANT i16 12
+ ; CHECK-NEXT: [[LSHR:%[0-9]+]]:_(i16) = G_LSHR [[BITCAST]], [[C]](i16)
+ ; CHECK-NEXT: [[ANYEXT:%[0-9]+]]:_(i32) = G_ANYEXT [[BITCAST]](i16)
+ ; CHECK-NEXT: [[ANYEXT1:%[0-9]+]]:_(i32) = G_ANYEXT [[LSHR]](i16)
+ ; CHECK-NEXT: $vgpr0 = COPY [[ANYEXT]](i32)
+ ; CHECK-NEXT: $vgpr1 = COPY [[ANYEXT1]](i32)
+ %0:_(p1) = G_IMPLICIT_DEF
+ %1:_(bf16) = G_LOAD %0 :: (load (bf16), addrspace 1)
+ %2:_(i4), %3:_(i4), %4:_(i4), %5:_(i4) = G_UNMERGE_VALUES %1
+ %6:_(i32) = G_ANYEXT %2
+ %7:_(i32) = G_ANYEXT %5
+ $vgpr0 = COPY %6
+ $vgpr1 = COPY %7
+...
More information about the llvm-commits
mailing list