[llvm] [AMDGPU] Emit format opcodes for i8 buffer.{load, store}.format in SDAG (PR #209703)

via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 15 02:05:52 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-amdgpu

Author: Arseniy Obolenskiy (aobolensk)

<details>
<summary>Changes</summary>

Select the format opcodes, matching GlobalISel behavior

Currently they are missing in Selection DAG handling scenario

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


4 Files Affected:

- (modified) llvm/lib/Target/AMDGPU/SIISelLowering.cpp (+14-9) 
- (modified) llvm/lib/Target/AMDGPU/SIISelLowering.h (+4-4) 
- (modified) llvm/test/CodeGen/AMDGPU/llvm.amdgcn.struct.ptr.buffer.load.format.ll (+40) 
- (modified) llvm/test/CodeGen/AMDGPU/llvm.amdgcn.struct.ptr.buffer.store.format.ll (+11) 


``````````diff
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
index 9cf33b4ccbb87..38acddfd7141b 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -7828,7 +7828,7 @@ SDValue SITargetLowering::lowerIntrinsicLoad(MemSDNode *M, bool IsFormat,
   // Handle BUFFER_LOAD_BYTE/UBYTE/SHORT/USHORT overloaded intrinsics
   if (!IsD16 && !LoadVT.isVector() && EltType.getSizeInBits() < 32)
     return handleByteShortBufferLoads(DAG, LoadVT, DL, Ops, M->getMemOperand(),
-                                      IsTFE);
+                                      IsTFE, IsFormat);
 
   if (isTypeLegal(LoadVT)) {
     return getMemIntrinsicNode(Opc, DL, M->getVTList(), Ops, IntVT,
@@ -12403,7 +12403,7 @@ SDValue SITargetLowering::LowerINTRINSIC_VOID(SDValue Op,
 
     // Handle BUFFER_STORE_BYTE/SHORT overloaded intrinsics
     if (!IsD16 && !VDataVT.isVector() && EltType.getSizeInBits() < 32)
-      return handleByteShortBufferStores(DAG, VDataVT, DL, Ops, M);
+      return handleByteShortBufferStores(DAG, VDataVT, DL, Ops, M, IsFormat);
 
     return DAG.getMemIntrinsicNode(Opc, DL, Op->getVTList(), Ops,
                                    M->getMemoryVT(), M->getMemOperand());
@@ -12455,7 +12455,7 @@ SDValue SITargetLowering::LowerINTRINSIC_VOID(SDValue Op,
     // Handle BUFFER_STORE_BYTE/SHORT overloaded intrinsics
     EVT VDataType = VData.getValueType().getScalarType();
     if (!IsD16 && !VDataVT.isVector() && EltType.getSizeInBits() < 32)
-      return handleByteShortBufferStores(DAG, VDataType, DL, Ops, M);
+      return handleByteShortBufferStores(DAG, VDataType, DL, Ops, M, IsFormat);
 
     return DAG.getMemIntrinsicNode(Opc, DL, Op->getVTList(), Ops,
                                    M->getMemoryVT(), M->getMemOperand());
@@ -13022,11 +13022,13 @@ SDValue SITargetLowering::handleByteShortBufferLoads(SelectionDAG &DAG,
                                                      EVT LoadVT, SDLoc DL,
                                                      ArrayRef<SDValue> Ops,
                                                      MachineMemOperand *MMO,
-                                                     bool IsTFE) const {
+                                                     bool IsTFE,
+                                                     bool IsFormat) const {
   EVT IntVT = LoadVT.changeTypeToInteger();
 
   if (IsTFE) {
-    unsigned Opc = (LoadVT.getScalarType() == MVT::i8)
+    unsigned Opc = IsFormat ? AMDGPUISD::BUFFER_LOAD_FORMAT_TFE
+                   : (LoadVT.getScalarType() == MVT::i8)
                        ? AMDGPUISD::BUFFER_LOAD_UBYTE_TFE
                        : AMDGPUISD::BUFFER_LOAD_USHORT_TFE;
     MachineFunction &MF = DAG.getMachineFunction();
@@ -13042,7 +13044,8 @@ SDValue SITargetLowering::handleByteShortBufferLoads(SelectionDAG &DAG,
     return DAG.getMergeValues({Value, Status, SDValue(Op.getNode(), 1)}, DL);
   }
 
-  unsigned Opc = LoadVT.getScalarType() == MVT::i8
+  unsigned Opc = IsFormat ? AMDGPUISD::BUFFER_LOAD_FORMAT
+                 : LoadVT.getScalarType() == MVT::i8
                      ? AMDGPUISD::BUFFER_LOAD_UBYTE
                      : AMDGPUISD::BUFFER_LOAD_USHORT;
 
@@ -13059,14 +13062,16 @@ SDValue SITargetLowering::handleByteShortBufferLoads(SelectionDAG &DAG,
 SDValue SITargetLowering::handleByteShortBufferStores(SelectionDAG &DAG,
                                                       EVT VDataType, SDLoc DL,
                                                       SDValue Ops[],
-                                                      MemSDNode *M) const {
+                                                      MemSDNode *M,
+                                                      bool IsFormat) const {
   if (VDataType == MVT::f16 || VDataType == MVT::bf16)
     Ops[1] = DAG.getNode(ISD::BITCAST, DL, MVT::i16, Ops[1]);
 
   SDValue BufferStoreExt = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i32, Ops[1]);
   Ops[1] = BufferStoreExt;
-  unsigned Opc = (VDataType == MVT::i8) ? AMDGPUISD::BUFFER_STORE_BYTE
-                                        : AMDGPUISD::BUFFER_STORE_SHORT;
+  unsigned Opc = IsFormat ? AMDGPUISD::BUFFER_STORE_FORMAT
+                 : (VDataType == MVT::i8) ? AMDGPUISD::BUFFER_STORE_BYTE
+                                          : AMDGPUISD::BUFFER_STORE_SHORT;
   ArrayRef<SDValue> OpsRef = ArrayRef(&Ops[0], 9);
   return DAG.getMemIntrinsicNode(Opc, DL, M->getVTList(), OpsRef, VDataType,
                                  M->getMemOperand());
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.h b/llvm/lib/Target/AMDGPU/SIISelLowering.h
index a181fa072d534..1005ad0999d4b 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.h
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.h
@@ -313,13 +313,13 @@ class SITargetLowering final : public AMDGPUTargetLowering {
   // Handle 8 bit and 16 bit buffer loads
   SDValue handleByteShortBufferLoads(SelectionDAG &DAG, EVT LoadVT, SDLoc DL,
                                      ArrayRef<SDValue> Ops,
-                                     MachineMemOperand *MMO,
-                                     bool IsTFE = false) const;
+                                     MachineMemOperand *MMO, bool IsTFE = false,
+                                     bool IsFormat = false) const;
 
   // Handle 8 bit and 16 bit buffer stores
   SDValue handleByteShortBufferStores(SelectionDAG &DAG, EVT VDataType,
-                                      SDLoc DL, SDValue Ops[],
-                                      MemSDNode *M) const;
+                                      SDLoc DL, SDValue Ops[], MemSDNode *M,
+                                      bool IsFormat = false) const;
 
 public:
   SITargetLowering(const TargetMachine &tm, const GCNSubtarget &STI);
diff --git a/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.struct.ptr.buffer.load.format.ll b/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.struct.ptr.buffer.load.format.ll
index 2f319fd8d01f4..31e98ef05416f 100644
--- a/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.struct.ptr.buffer.load.format.ll
+++ b/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.struct.ptr.buffer.load.format.ll
@@ -608,6 +608,45 @@ main_body:
   ret float %fdata
 }
 
+define amdgpu_ps float @buffer_load_x_i8(ptr addrspace(8) inreg %rsrc) {
+; GFX6-LABEL: buffer_load_x_i8:
+; GFX6:       ; %bb.0: ; %main_body
+; GFX6-NEXT:    v_mov_b32_e32 v0, 0
+; GFX6-NEXT:    buffer_load_format_x v0, v0, s[0:3], 0 idxen
+; GFX6-NEXT:    s_waitcnt vmcnt(0)
+; GFX6-NEXT:    v_and_b32_e32 v0, 0xff, v0
+; GFX6-NEXT:    ; return to shader part epilog
+;
+; GFX8PLUS-LABEL: buffer_load_x_i8:
+; GFX8PLUS:       ; %bb.0: ; %main_body
+; GFX8PLUS-NEXT:    v_mov_b32_e32 v0, 0
+; GFX8PLUS-NEXT:    buffer_load_format_x v0, v0, s[0:3], 0 idxen
+; GFX8PLUS-NEXT:    s_waitcnt vmcnt(0)
+; GFX8PLUS-NEXT:    v_and_b32_e32 v0, 0xff, v0
+; GFX8PLUS-NEXT:    ; return to shader part epilog
+;
+; GFX11-LABEL: buffer_load_x_i8:
+; GFX11:       ; %bb.0: ; %main_body
+; GFX11-NEXT:    v_mov_b32_e32 v0, 0
+; GFX11-NEXT:    buffer_load_format_x v0, v0, s[0:3], 0 idxen
+; GFX11-NEXT:    s_waitcnt vmcnt(0)
+; GFX11-NEXT:    v_and_b32_e32 v0, 0xff, v0
+; GFX11-NEXT:    ; return to shader part epilog
+;
+; NOPRT-LABEL: buffer_load_x_i8:
+; NOPRT:       ; %bb.0: ; %main_body
+; NOPRT-NEXT:    v_mov_b32_e32 v0, 0
+; NOPRT-NEXT:    buffer_load_format_x v0, v0, s[0:3], 0 idxen
+; NOPRT-NEXT:    s_waitcnt vmcnt(0)
+; NOPRT-NEXT:    v_and_b32_e32 v0, 0xff, v0
+; NOPRT-NEXT:    ; return to shader part epilog
+main_body:
+  %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
+}
+
 define amdgpu_ps <2 x float> @buffer_load_xy(ptr addrspace(8) inreg %rsrc) {
 ; GFX6-LABEL: buffer_load_xy:
 ; GFX6:       ; %bb.0: ; %main_body
@@ -1117,6 +1156,7 @@ declare float @llvm.amdgcn.struct.ptr.buffer.load.format.f32(ptr addrspace(8), i
 declare <2 x float> @llvm.amdgcn.struct.ptr.buffer.load.format.v2f32(ptr addrspace(8), i32, i32, i32, i32) #0
 declare <4 x float> @llvm.amdgcn.struct.ptr.buffer.load.format.v4f32(ptr addrspace(8), i32, i32, i32, i32) #0
 declare i32 @llvm.amdgcn.struct.ptr.buffer.load.format.i32(ptr addrspace(8), i32, i32, i32, i32) #0
+declare i8 @llvm.amdgcn.struct.ptr.buffer.load.format.i8(ptr addrspace(8), i32, i32, i32, i32) #0
 declare { <4 x i32>, i32 } @llvm.amdgcn.struct.ptr.buffer.load.format.sl_v4i32i32s(ptr addrspace(8), i32, i32, i32, i32 immarg) #0
 declare { <4 x float>, i32 } @llvm.amdgcn.struct.ptr.buffer.load.format.sl_v4f32i32s(ptr addrspace(8), i32, i32, i32, i32 immarg) #0
 declare { <3 x i32>, i32 } @llvm.amdgcn.struct.ptr.buffer.load.format.sl_v3i32i32s(ptr addrspace(8), i32, i32, i32, i32 immarg) #0
diff --git a/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.struct.ptr.buffer.store.format.ll b/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.struct.ptr.buffer.store.format.ll
index 51840ae5ba1f8..6ce7dff66a1a7 100644
--- a/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.struct.ptr.buffer.store.format.ll
+++ b/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.struct.ptr.buffer.store.format.ll
@@ -118,6 +118,16 @@ main_body:
   ret void
 }
 
+define amdgpu_ps void @buffer_store_x1_i8(ptr addrspace(8) inreg %rsrc, i8 %data, i32 %index) {
+; CHECK-LABEL: buffer_store_x1_i8:
+; CHECK:       ; %bb.0: ; %main_body
+; CHECK-NEXT:    buffer_store_format_x v0, v1, s[0:3], 0 idxen
+; CHECK-NEXT:    s_endpgm
+main_body:
+  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
+}
+
 define amdgpu_ps void @buffer_store_x2(ptr addrspace(8) inreg %rsrc, <2 x float> %data, i32 %index) {
 ; CHECK-LABEL: buffer_store_x2:
 ; CHECK:       ; %bb.0: ; %main_body
@@ -132,6 +142,7 @@ declare void @llvm.amdgcn.struct.ptr.buffer.store.format.f32(float, ptr addrspac
 declare void @llvm.amdgcn.struct.ptr.buffer.store.format.v2f32(<2 x float>, ptr addrspace(8), i32, i32, i32, i32) #0
 declare void @llvm.amdgcn.struct.ptr.buffer.store.format.v4f32(<4 x float>, ptr addrspace(8), i32, i32, i32, i32) #0
 declare void @llvm.amdgcn.struct.ptr.buffer.store.format.i32(i32, ptr addrspace(8), i32, i32, i32, i32) #0
+declare void @llvm.amdgcn.struct.ptr.buffer.store.format.i8(i8, ptr addrspace(8), i32, i32, i32, i32) #0
 declare <4 x float> @llvm.amdgcn.struct.ptr.buffer.load.format.v4f32(ptr addrspace(8), i32, i32, i32, i32) #1
 
 attributes #0 = { nounwind }

``````````

</details>


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


More information about the llvm-commits mailing list