[llvm] [AMDGPU] Reject sub-dword format buffer loads and stores (PR #209703)

Arseniy Obolenskiy via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 15 04:24:16 PDT 2026


https://github.com/aobolensk updated https://github.com/llvm/llvm-project/pull/209703

>From 78216605324834d7266dce271814ee973cf297f3 Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Wed, 15 Jul 2026 12:16:09 +0200
Subject: [PATCH 1/2] [AMDGPU] Reject sub-dword format buffer loads and stores

An i8 buffer.{load,store}.format has no corresponding hardware instruction so diagnose it in SelectionDAG and fail legalization in GlobalISel instead of emitting invalid format opcodes
---
 .../lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp |  6 +++++
 llvm/lib/Target/AMDGPU/SIISelLowering.cpp     | 22 +++++++++++++++++++
 ...mdgcn.struct.ptr.buffer.format.i8.xfail.ll | 20 +++++++++++++++++
 3 files changed, 48 insertions(+)
 create mode 100644 llvm/test/CodeGen/AMDGPU/llvm.amdgcn.struct.ptr.buffer.format.i8.xfail.ll

diff --git a/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp b/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp
index 2180ce67d576f..307d0a1cf9626 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp
@@ -6701,6 +6701,9 @@ bool AMDGPULegalizerInfo::legalizeBufferStore(MachineInstr &MI,
   const int MemSize = MMO->getSize().getValue();
   LLT MemTy = MMO->getMemoryType();
 
+  if (IsFormat && !IsTyped && !IsD16 && MemTy.getSizeInBits() < 32)
+    return false;
+
   VData = fixStoreSourceType(B, VData, MemTy, IsFormat);
 
   castBufferRsrcArgToV4I32(MI, B, 2);
@@ -6871,6 +6874,9 @@ bool AMDGPULegalizerInfo::legalizeBufferLoad(MachineInstr &MI,
   const bool IsD16 = IsFormat && (EltTy.getSizeInBits() == 16);
   const bool Unpacked = ST.hasUnpackedD16VMem();
 
+  if (IsFormat && !IsTyped && !IsD16 && MemTy.getSizeInBits() < 32)
+    return false;
+
   std::tie(VOffset, ImmOffset) = splitBufferOffsets(B, VOffset);
 
   unsigned Opc;
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
index 9cf33b4ccbb87..4819e0ef38ba1 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -7813,6 +7813,13 @@ SDValue SITargetLowering::lowerIntrinsicLoad(MemSDNode *M, bool IsFormat,
 
   bool IsD16 = IsFormat && (EltType.getSizeInBits() == 16);
 
+  if (IsFormat && !IsD16 && EltType.getSizeInBits() < 32) {
+    DAG.getContext()->diagnose(DiagnosticInfoUnsupported(
+        DAG.getMachineFunction().getFunction(),
+        "unsupported sub-dword format buffer load", DL.getDebugLoc()));
+    return DAG.getMergeValues({DAG.getPOISON(LoadVT), M->getOperand(0)}, DL);
+  }
+
   assert(M->getNumValues() == 2 || M->getNumValues() == 3);
   bool IsTFE = M->getNumValues() == 3;
 
@@ -12371,6 +12378,14 @@ SDValue SITargetLowering::LowerINTRINSIC_VOID(SDValue Op,
     EVT VDataVT = VData.getValueType();
     EVT EltType = VDataVT.getScalarType();
     bool IsD16 = IsFormat && (EltType.getSizeInBits() == 16);
+
+    if (IsFormat && !IsD16 && EltType.getSizeInBits() < 32) {
+      DAG.getContext()->diagnose(DiagnosticInfoUnsupported(
+          DAG.getMachineFunction().getFunction(),
+          "unsupported sub-dword format buffer store", DL.getDebugLoc()));
+      return Chain;
+    }
+
     if (IsD16) {
       VData = handleD16VData(VData, DAG);
       VDataVT = VData.getValueType();
@@ -12422,6 +12437,13 @@ SDValue SITargetLowering::LowerINTRINSIC_VOID(SDValue Op,
     EVT EltType = VDataVT.getScalarType();
     bool IsD16 = IsFormat && (EltType.getSizeInBits() == 16);
 
+    if (IsFormat && !IsD16 && EltType.getSizeInBits() < 32) {
+      DAG.getContext()->diagnose(DiagnosticInfoUnsupported(
+          DAG.getMachineFunction().getFunction(),
+          "unsupported sub-dword format buffer store", DL.getDebugLoc()));
+      return Chain;
+    }
+
     if (IsD16) {
       VData = handleD16VData(VData, DAG);
       VDataVT = VData.getValueType();
diff --git a/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.struct.ptr.buffer.format.i8.xfail.ll b/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.struct.ptr.buffer.format.i8.xfail.ll
new file mode 100644
index 0000000000000..2dec0c5364449
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.struct.ptr.buffer.format.i8.xfail.ll
@@ -0,0 +1,20 @@
+; RUN: not llc -mtriple=amdgcn -mcpu=gfx900 -filetype=null %s 2>&1 | FileCheck -check-prefix=SDAG %s
+; RUN: not llc -global-isel -mtriple=amdgcn -mcpu=gfx900 -filetype=null %s 2>&1 | FileCheck -check-prefix=GISEL %s
+
+; An i8 buffer.load.format / buffer.store.format has no corresponding real
+; instruction (no byte-granularity format access exists in hardware), so both
+; SelectionDAG and GlobalISel must refuse to lower it.
+
+; SDAG: error: {{.*}}unsupported sub-dword format buffer load
+define amdgpu_ps float @load_i8(ptr addrspace(8) inreg %rsrc) {
+  %data = call i8 @llvm.amdgcn.struct.ptr.buffer.load.format.i8(ptr addrspace(8) %rsrc, i32 0, i32 0, i32 0, i32 0)
+  %zext = zext i8 %data to i32
+  %fdata = bitcast i32 %zext to float
+  ret float %fdata
+}
+
+; GISEL: LLVM ERROR: unable to legalize instruction
+define amdgpu_ps void @store_i8(ptr addrspace(8) inreg %rsrc, i8 %data, i32 %index) {
+  call void @llvm.amdgcn.struct.ptr.buffer.store.format.i8(i8 %data, ptr addrspace(8) %rsrc, i32 %index, i32 0, i32 0, i32 0)
+  ret void
+}

>From 532bde3fa8d149139acabf485a42531bcccb5833 Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Wed, 15 Jul 2026 13:24:04 +0200
Subject: [PATCH 2/2] unify errors

---
 .../lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp | 21 +++++++++++++++----
 ...mdgcn.struct.ptr.buffer.format.i8.xfail.ll |  8 +++----
 2 files changed, 21 insertions(+), 8 deletions(-)

diff --git a/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp b/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp
index 307d0a1cf9626..cd2e9dd55247f 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp
@@ -6701,8 +6701,13 @@ bool AMDGPULegalizerInfo::legalizeBufferStore(MachineInstr &MI,
   const int MemSize = MMO->getSize().getValue();
   LLT MemTy = MMO->getMemoryType();
 
-  if (IsFormat && !IsTyped && !IsD16 && MemTy.getSizeInBits() < 32)
-    return false;
+  if (IsFormat && !IsTyped && !IsD16 && MemTy.getSizeInBits() < 32) {
+    const Function &Fn = B.getMF().getFunction();
+    Fn.getContext().diagnose(DiagnosticInfoUnsupported(
+        Fn, "unsupported sub-dword format buffer store", MI.getDebugLoc()));
+    MI.eraseFromParent();
+    return true;
+  }
 
   VData = fixStoreSourceType(B, VData, MemTy, IsFormat);
 
@@ -6874,8 +6879,16 @@ bool AMDGPULegalizerInfo::legalizeBufferLoad(MachineInstr &MI,
   const bool IsD16 = IsFormat && (EltTy.getSizeInBits() == 16);
   const bool Unpacked = ST.hasUnpackedD16VMem();
 
-  if (IsFormat && !IsTyped && !IsD16 && MemTy.getSizeInBits() < 32)
-    return false;
+  if (IsFormat && !IsTyped && !IsD16 && MemTy.getSizeInBits() < 32) {
+    const Function &Fn = B.getMF().getFunction();
+    Fn.getContext().diagnose(DiagnosticInfoUnsupported(
+        Fn, "unsupported sub-dword format buffer load", MI.getDebugLoc()));
+    B.buildUndef(Dst);
+    if (IsTFE)
+      B.buildUndef(StatusDst);
+    MI.eraseFromParent();
+    return true;
+  }
 
   std::tie(VOffset, ImmOffset) = splitBufferOffsets(B, VOffset);
 
diff --git a/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.struct.ptr.buffer.format.i8.xfail.ll b/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.struct.ptr.buffer.format.i8.xfail.ll
index 2dec0c5364449..28c4669e978e5 100644
--- a/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.struct.ptr.buffer.format.i8.xfail.ll
+++ b/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.struct.ptr.buffer.format.i8.xfail.ll
@@ -1,11 +1,11 @@
-; RUN: not llc -mtriple=amdgcn -mcpu=gfx900 -filetype=null %s 2>&1 | FileCheck -check-prefix=SDAG %s
-; RUN: not llc -global-isel -mtriple=amdgcn -mcpu=gfx900 -filetype=null %s 2>&1 | FileCheck -check-prefix=GISEL %s
+; RUN: not llc -mtriple=amdgcn -mcpu=gfx900 -filetype=null %s 2>&1 | FileCheck %s
+; RUN: not llc -global-isel -mtriple=amdgcn -mcpu=gfx900 -filetype=null %s 2>&1 | FileCheck %s
 
 ; An i8 buffer.load.format / buffer.store.format has no corresponding real
 ; instruction (no byte-granularity format access exists in hardware), so both
 ; SelectionDAG and GlobalISel must refuse to lower it.
 
-; SDAG: error: {{.*}}unsupported sub-dword format buffer load
+; CHECK: error: {{.*}}unsupported sub-dword format buffer load
 define amdgpu_ps float @load_i8(ptr addrspace(8) inreg %rsrc) {
   %data = call i8 @llvm.amdgcn.struct.ptr.buffer.load.format.i8(ptr addrspace(8) %rsrc, i32 0, i32 0, i32 0, i32 0)
   %zext = zext i8 %data to i32
@@ -13,7 +13,7 @@ define amdgpu_ps float @load_i8(ptr addrspace(8) inreg %rsrc) {
   ret float %fdata
 }
 
-; GISEL: LLVM ERROR: unable to legalize instruction
+; CHECK: error: {{.*}}unsupported sub-dword format buffer store
 define amdgpu_ps void @store_i8(ptr addrspace(8) inreg %rsrc, i8 %data, i32 %index) {
   call void @llvm.amdgcn.struct.ptr.buffer.store.format.i8(i8 %data, ptr addrspace(8) %rsrc, i32 %index, i32 0, i32 0, i32 0)
   ret void



More information about the llvm-commits mailing list