[llvm] [AMDGPU] Reject non-fp16 image sample data in D16 detection while lowering image (PR #213272)
Arseniy Obolenskiy via llvm-commits
llvm-commits at lists.llvm.org
Mon Aug 3 07:06:30 PDT 2026
https://github.com/aobolensk updated https://github.com/llvm/llvm-project/pull/213272
>From 29a6150c2bc4363fc32bdd266f5fed927a4757d1 Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Fri, 31 Jul 2026 15:12:45 +0200
Subject: [PATCH 1/3] [AMDGPU] Recognize bf16 image sample data in D16
detection
---
llvm/lib/Target/AMDGPU/SIISelLowering.cpp | 4 +-
.../llvm.amdgcn.image.sample.d16.dim.ll | 54 +++++++++++++++++++
2 files changed, 56 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
index b5e2a36ad9f19..dfa77ed5c2092 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -10426,7 +10426,7 @@ SDValue SITargetLowering::lowerImage(SDValue Op,
VData = Op.getOperand(2);
MVT StoreVT = VData.getSimpleValueType();
- if (StoreVT.getScalarType() == MVT::f16) {
+ if (StoreVT.getScalarSizeInBits() == 16) {
if (!Subtarget->hasD16Images() || !BaseOpcode->HasD16)
return Op; // D16 is unsupported for this instruction
@@ -10439,7 +10439,7 @@ SDValue SITargetLowering::lowerImage(SDValue Op,
// Work out the num dwords based on the dmask popcount and underlying type
// and whether packing is supported.
MVT LoadVT = ResultTypes[0].getSimpleVT();
- if (LoadVT.getScalarType() == MVT::f16) {
+ if (LoadVT.getScalarSizeInBits() == 16) {
if (!Subtarget->hasD16Images() || !BaseOpcode->HasD16)
return Op; // D16 is unsupported for this instruction
diff --git a/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.image.sample.d16.dim.ll b/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.image.sample.d16.dim.ll
index 3e9c6f4d24d83..a139e22290537 100644
--- a/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.image.sample.d16.dim.ll
+++ b/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.image.sample.d16.dim.ll
@@ -623,10 +623,64 @@ main_body:
ret <4 x float> %r
}
+define amdgpu_ps <4 x bfloat> @image_sample_2d_v4bf16(<8 x i32> inreg %rsrc, <4 x i32> inreg %samp, float %s, float %t) {
+; TONGA-LABEL: image_sample_2d_v4bf16:
+; TONGA: ; %bb.0: ; %main_body
+; TONGA-NEXT: s_mov_b64 s[12:13], exec
+; TONGA-NEXT: s_wqm_b64 exec, exec
+; TONGA-NEXT: s_and_b64 exec, exec, s[12:13]
+; TONGA-NEXT: image_sample v[0:3], v[0:1], s[0:7], s[8:11] dmask:0xf d16
+; TONGA-NEXT: s_mov_b32 s0, 0x1000504
+; TONGA-NEXT: s_waitcnt vmcnt(0)
+; TONGA-NEXT: v_perm_b32 v0, v0, v1, s0
+; TONGA-NEXT: v_perm_b32 v1, v2, v3, s0
+; TONGA-NEXT: ; return to shader part epilog
+;
+; GFX81-LABEL: image_sample_2d_v4bf16:
+; GFX81: ; %bb.0: ; %main_body
+; GFX81-NEXT: s_mov_b64 s[12:13], exec
+; GFX81-NEXT: s_wqm_b64 exec, exec
+; GFX81-NEXT: s_and_b64 exec, exec, s[12:13]
+; GFX81-NEXT: image_sample v[0:1], v[0:1], s[0:7], s[8:11] dmask:0xf d16
+; GFX81-NEXT: s_waitcnt vmcnt(0)
+; GFX81-NEXT: ; return to shader part epilog
+;
+; GFX9-LABEL: image_sample_2d_v4bf16:
+; GFX9: ; %bb.0: ; %main_body
+; GFX9-NEXT: s_mov_b64 s[12:13], exec
+; GFX9-NEXT: s_wqm_b64 exec, exec
+; GFX9-NEXT: s_and_b64 exec, exec, s[12:13]
+; GFX9-NEXT: image_sample v[0:1], v[0:1], s[0:7], s[8:11] dmask:0xf d16
+; GFX9-NEXT: s_waitcnt vmcnt(0)
+; GFX9-NEXT: ; return to shader part epilog
+;
+; GFX10PLUS-LABEL: image_sample_2d_v4bf16:
+; GFX10PLUS: ; %bb.0: ; %main_body
+; GFX10PLUS-NEXT: s_mov_b32 s12, exec_lo
+; GFX10PLUS-NEXT: s_wqm_b32 exec_lo, exec_lo
+; GFX10PLUS-NEXT: s_and_b32 exec_lo, exec_lo, s12
+; GFX10PLUS-NEXT: image_sample v[0:1], v[0:1], s[0:7], s[8:11] dmask:0xf dim:SQ_RSRC_IMG_2D d16
+; GFX10PLUS-NEXT: s_waitcnt vmcnt(0)
+; GFX10PLUS-NEXT: ; return to shader part epilog
+;
+; GFX12PLUS-LABEL: image_sample_2d_v4bf16:
+; GFX12PLUS: ; %bb.0: ; %main_body
+; GFX12PLUS-NEXT: s_mov_b32 s12, exec_lo
+; GFX12PLUS-NEXT: s_wqm_b32 exec_lo, exec_lo
+; GFX12PLUS-NEXT: s_and_b32 exec_lo, exec_lo, s12
+; GFX12PLUS-NEXT: image_sample v[0:1], [v0, v1], s[0:7], s[8:11] dmask:0xf dim:SQ_RSRC_IMG_2D d16
+; GFX12PLUS-NEXT: s_wait_samplecnt 0x0
+; GFX12PLUS-NEXT: ; return to shader part epilog
+main_body:
+ %tex = call <4 x bfloat> @llvm.amdgcn.image.sample.2d.v4bf16.f32(i32 15, float %s, float %t, <8 x i32> %rsrc, <4 x i32> %samp, i1 false, i32 0, i32 0)
+ ret <4 x bfloat> %tex
+}
+
declare half @llvm.amdgcn.image.sample.2d.f16.f32(i32, float, float, <8 x i32>, <4 x i32>, i1, i32, i32) #1
declare {half,i32} @llvm.amdgcn.image.sample.2d.f16i32.f32(i32, float, float, <8 x i32>, <4 x i32>, i1, i32, i32) #1
declare <3 x half> @llvm.amdgcn.image.sample.2d.v3f16.f32(i32, float, float, <8 x i32>, <4 x i32>, i1, i32, i32) #1
declare <4 x half> @llvm.amdgcn.image.sample.2d.v4f16.f32(i32, float, float, <8 x i32>, <4 x i32>, i1, i32, i32) #1
+declare <4 x bfloat> @llvm.amdgcn.image.sample.2d.v4bf16.f32(i32, float, float, <8 x i32>, <4 x i32>, i1, i32, i32) #1
declare {<2 x half>,i32} @llvm.amdgcn.image.sample.2d.v2f16i32.f32(i32, float, float, <8 x i32>, <4 x i32>, i1, i32, i32) #1
declare <2 x half> @llvm.amdgcn.image.sample.c.d.1d.v2f16.f32.f32(i32, float, float, float, float, <8 x i32>, <4 x i32>, i1, i32, i32) #1
declare {<2 x half>,i32} @llvm.amdgcn.image.sample.c.d.1d.v2f16i32.f32.f32(i32, float, float, float, float, <8 x i32>, <4 x i32>, i1, i32, i32) #1
>From ad564ab9acba513b9056158b8663708e4e2cdb00 Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Mon, 3 Aug 2026 08:15:29 +0200
Subject: [PATCH 2/3] Make an error on bf16 case
---
llvm/lib/Target/AMDGPU/SIISelLowering.cpp | 14 ++++-
...llvm.amdgcn.image.illegal-data-type.err.ll | 28 ++++++++++
.../llvm.amdgcn.image.sample.d16.dim.ll | 54 -------------------
3 files changed, 40 insertions(+), 56 deletions(-)
create mode 100644 llvm/test/CodeGen/AMDGPU/llvm.amdgcn.image.illegal-data-type.err.ll
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
index 8995e2672a844..192cc1696e69a 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -10440,7 +10440,12 @@ SDValue SITargetLowering::lowerImage(SDValue Op,
VData = Op.getOperand(2);
MVT StoreVT = VData.getSimpleValueType();
- if (StoreVT.getScalarSizeInBits() == 16) {
+ if (StoreVT.getScalarType().getSizeInBits() == 16 &&
+ StoreVT.getScalarType() != MVT::f16) {
+ return diagnoseUnsupportedImage(DAG, Op, OrigResultTypes, DL,
+ "unsupported image store data type");
+ }
+ if (StoreVT.getScalarType() == MVT::f16) {
if (!Subtarget->hasD16Images() || !BaseOpcode->HasD16)
return Op; // D16 is unsupported for this instruction
@@ -10453,7 +10458,12 @@ SDValue SITargetLowering::lowerImage(SDValue Op,
// Work out the num dwords based on the dmask popcount and underlying type
// and whether packing is supported.
MVT LoadVT = ResultTypes[0].getSimpleVT();
- if (LoadVT.getScalarSizeInBits() == 16) {
+ if (LoadVT.getScalarType().getSizeInBits() == 16 &&
+ LoadVT.getScalarType() != MVT::f16) {
+ return diagnoseUnsupportedImage(DAG, Op, OrigResultTypes, DL,
+ "unsupported image load data type");
+ }
+ if (LoadVT.getScalarType() == MVT::f16) {
if (!Subtarget->hasD16Images() || !BaseOpcode->HasD16)
return Op; // D16 is unsupported for this instruction
diff --git a/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.image.illegal-data-type.err.ll b/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.image.illegal-data-type.err.ll
new file mode 100644
index 0000000000000..fbc455d52c0d4
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.image.illegal-data-type.err.ll
@@ -0,0 +1,28 @@
+; RUN: not llc -mtriple=amdgpu9.0a -filetype=null %s 2>&1 | FileCheck %s
+
+; llvm.amdgcn.image.{sample,load,store} support 32-bit and 64-bit
+; data, plus f16 under the D16 hardware conversion. Other 16-bit
+; scalar types (bf16, i16) are not valid D16 data and must be
+; rejected instead of silently mis-lowered or crashing.
+
+; CHECK: error: {{.*}}unsupported image load data type
+define amdgpu_ps <4 x bfloat> @sample_2d_v4bf16(<8 x i32> inreg %rsrc, <4 x i32> inreg %samp, float %s, float %t) {
+ %v = call <4 x bfloat> @llvm.amdgcn.image.sample.2d.v4bf16.f32(i32 15, float %s, float %t, <8 x i32> %rsrc, <4 x i32> %samp, i1 false, i32 0, i32 0)
+ ret <4 x bfloat> %v
+}
+
+; CHECK: error: {{.*}}unsupported image load data type
+define amdgpu_ps <4 x i16> @load_2d_v4i16(<8 x i32> inreg %rsrc, i32 %s, i32 %t) {
+ %v = call <4 x i16> @llvm.amdgcn.image.load.2d.v4i16.i32(i32 15, i32 %s, i32 %t, <8 x i32> %rsrc, i32 0, i32 0)
+ ret <4 x i16> %v
+}
+
+; CHECK: error: {{.*}}unsupported image store data type
+define amdgpu_ps void @store_2d_v4bf16(<8 x i32> inreg %rsrc, <4 x bfloat> %data, i32 %s, i32 %t) {
+ call void @llvm.amdgcn.image.store.2d.v4bf16.i32(<4 x bfloat> %data, i32 15, i32 %s, i32 %t, <8 x i32> %rsrc, i32 0, i32 0)
+ ret void
+}
+
+declare <4 x bfloat> @llvm.amdgcn.image.sample.2d.v4bf16.f32(i32, float, float, <8 x i32>, <4 x i32>, i1, i32, i32)
+declare <4 x i16> @llvm.amdgcn.image.load.2d.v4i16.i32(i32, i32, i32, <8 x i32>, i32, i32)
+declare void @llvm.amdgcn.image.store.2d.v4bf16.i32(<4 x bfloat>, i32, i32, i32, <8 x i32>, i32, i32)
diff --git a/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.image.sample.d16.dim.ll b/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.image.sample.d16.dim.ll
index a139e22290537..3e9c6f4d24d83 100644
--- a/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.image.sample.d16.dim.ll
+++ b/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.image.sample.d16.dim.ll
@@ -623,64 +623,10 @@ main_body:
ret <4 x float> %r
}
-define amdgpu_ps <4 x bfloat> @image_sample_2d_v4bf16(<8 x i32> inreg %rsrc, <4 x i32> inreg %samp, float %s, float %t) {
-; TONGA-LABEL: image_sample_2d_v4bf16:
-; TONGA: ; %bb.0: ; %main_body
-; TONGA-NEXT: s_mov_b64 s[12:13], exec
-; TONGA-NEXT: s_wqm_b64 exec, exec
-; TONGA-NEXT: s_and_b64 exec, exec, s[12:13]
-; TONGA-NEXT: image_sample v[0:3], v[0:1], s[0:7], s[8:11] dmask:0xf d16
-; TONGA-NEXT: s_mov_b32 s0, 0x1000504
-; TONGA-NEXT: s_waitcnt vmcnt(0)
-; TONGA-NEXT: v_perm_b32 v0, v0, v1, s0
-; TONGA-NEXT: v_perm_b32 v1, v2, v3, s0
-; TONGA-NEXT: ; return to shader part epilog
-;
-; GFX81-LABEL: image_sample_2d_v4bf16:
-; GFX81: ; %bb.0: ; %main_body
-; GFX81-NEXT: s_mov_b64 s[12:13], exec
-; GFX81-NEXT: s_wqm_b64 exec, exec
-; GFX81-NEXT: s_and_b64 exec, exec, s[12:13]
-; GFX81-NEXT: image_sample v[0:1], v[0:1], s[0:7], s[8:11] dmask:0xf d16
-; GFX81-NEXT: s_waitcnt vmcnt(0)
-; GFX81-NEXT: ; return to shader part epilog
-;
-; GFX9-LABEL: image_sample_2d_v4bf16:
-; GFX9: ; %bb.0: ; %main_body
-; GFX9-NEXT: s_mov_b64 s[12:13], exec
-; GFX9-NEXT: s_wqm_b64 exec, exec
-; GFX9-NEXT: s_and_b64 exec, exec, s[12:13]
-; GFX9-NEXT: image_sample v[0:1], v[0:1], s[0:7], s[8:11] dmask:0xf d16
-; GFX9-NEXT: s_waitcnt vmcnt(0)
-; GFX9-NEXT: ; return to shader part epilog
-;
-; GFX10PLUS-LABEL: image_sample_2d_v4bf16:
-; GFX10PLUS: ; %bb.0: ; %main_body
-; GFX10PLUS-NEXT: s_mov_b32 s12, exec_lo
-; GFX10PLUS-NEXT: s_wqm_b32 exec_lo, exec_lo
-; GFX10PLUS-NEXT: s_and_b32 exec_lo, exec_lo, s12
-; GFX10PLUS-NEXT: image_sample v[0:1], v[0:1], s[0:7], s[8:11] dmask:0xf dim:SQ_RSRC_IMG_2D d16
-; GFX10PLUS-NEXT: s_waitcnt vmcnt(0)
-; GFX10PLUS-NEXT: ; return to shader part epilog
-;
-; GFX12PLUS-LABEL: image_sample_2d_v4bf16:
-; GFX12PLUS: ; %bb.0: ; %main_body
-; GFX12PLUS-NEXT: s_mov_b32 s12, exec_lo
-; GFX12PLUS-NEXT: s_wqm_b32 exec_lo, exec_lo
-; GFX12PLUS-NEXT: s_and_b32 exec_lo, exec_lo, s12
-; GFX12PLUS-NEXT: image_sample v[0:1], [v0, v1], s[0:7], s[8:11] dmask:0xf dim:SQ_RSRC_IMG_2D d16
-; GFX12PLUS-NEXT: s_wait_samplecnt 0x0
-; GFX12PLUS-NEXT: ; return to shader part epilog
-main_body:
- %tex = call <4 x bfloat> @llvm.amdgcn.image.sample.2d.v4bf16.f32(i32 15, float %s, float %t, <8 x i32> %rsrc, <4 x i32> %samp, i1 false, i32 0, i32 0)
- ret <4 x bfloat> %tex
-}
-
declare half @llvm.amdgcn.image.sample.2d.f16.f32(i32, float, float, <8 x i32>, <4 x i32>, i1, i32, i32) #1
declare {half,i32} @llvm.amdgcn.image.sample.2d.f16i32.f32(i32, float, float, <8 x i32>, <4 x i32>, i1, i32, i32) #1
declare <3 x half> @llvm.amdgcn.image.sample.2d.v3f16.f32(i32, float, float, <8 x i32>, <4 x i32>, i1, i32, i32) #1
declare <4 x half> @llvm.amdgcn.image.sample.2d.v4f16.f32(i32, float, float, <8 x i32>, <4 x i32>, i1, i32, i32) #1
-declare <4 x bfloat> @llvm.amdgcn.image.sample.2d.v4bf16.f32(i32, float, float, <8 x i32>, <4 x i32>, i1, i32, i32) #1
declare {<2 x half>,i32} @llvm.amdgcn.image.sample.2d.v2f16i32.f32(i32, float, float, <8 x i32>, <4 x i32>, i1, i32, i32) #1
declare <2 x half> @llvm.amdgcn.image.sample.c.d.1d.v2f16.f32.f32(i32, float, float, float, float, <8 x i32>, <4 x i32>, i1, i32, i32) #1
declare {<2 x half>,i32} @llvm.amdgcn.image.sample.c.d.1d.v2f16i32.f32.f32(i32, float, float, float, float, <8 x i32>, <4 x i32>, i1, i32, i32) #1
>From dbe61f59c17def9fb2ab39de8bff46249cb0b6c3 Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Mon, 3 Aug 2026 16:06:07 +0200
Subject: [PATCH 3/3] rewrite condition
---
llvm/lib/Target/AMDGPU/SIISelLowering.cpp | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
index 192cc1696e69a..169b95b229aff 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -10440,12 +10440,13 @@ SDValue SITargetLowering::lowerImage(SDValue Op,
VData = Op.getOperand(2);
MVT StoreVT = VData.getSimpleValueType();
- if (StoreVT.getScalarType().getSizeInBits() == 16 &&
- StoreVT.getScalarType() != MVT::f16) {
+ MVT StoreScalarVT = StoreVT.getScalarType();
+ if (StoreScalarVT != MVT::f16 && StoreScalarVT.getSizeInBits() != 32 &&
+ StoreScalarVT.getSizeInBits() != 64) {
return diagnoseUnsupportedImage(DAG, Op, OrigResultTypes, DL,
"unsupported image store data type");
}
- if (StoreVT.getScalarType() == MVT::f16) {
+ if (StoreScalarVT == MVT::f16) {
if (!Subtarget->hasD16Images() || !BaseOpcode->HasD16)
return Op; // D16 is unsupported for this instruction
@@ -10458,12 +10459,13 @@ SDValue SITargetLowering::lowerImage(SDValue Op,
// Work out the num dwords based on the dmask popcount and underlying type
// and whether packing is supported.
MVT LoadVT = ResultTypes[0].getSimpleVT();
- if (LoadVT.getScalarType().getSizeInBits() == 16 &&
- LoadVT.getScalarType() != MVT::f16) {
+ MVT LoadScalarVT = LoadVT.getScalarType();
+ if (LoadScalarVT != MVT::f16 && LoadScalarVT.getSizeInBits() != 32 &&
+ LoadScalarVT.getSizeInBits() != 64) {
return diagnoseUnsupportedImage(DAG, Op, OrigResultTypes, DL,
"unsupported image load data type");
}
- if (LoadVT.getScalarType() == MVT::f16) {
+ if (LoadScalarVT == MVT::f16) {
if (!Subtarget->hasD16Images() || !BaseOpcode->HasD16)
return Op; // D16 is unsupported for this instruction
More information about the llvm-commits
mailing list