[clang] [HLSL] Add SPIR-V target type for RWStructuredBuffers (PR #133468)
Steven Perron via cfe-commits
cfe-commits at lists.llvm.org
Fri Mar 28 11:33:56 PDT 2025
https://github.com/s-perron updated https://github.com/llvm/llvm-project/pull/133468
>From 7838678ca8ec5870cd8df81b109f9e1b30699f4e Mon Sep 17 00:00:00 2001
From: Steven Perron <stevenperron at google.com>
Date: Fri, 24 Jan 2025 13:04:29 -0500
Subject: [PATCH 1/2] [HLSL] Add SPIR-V target type for RWStructuredBuffers
This PR adds the target type for main storage for HLSL raw buffer types.
It does not handle the counter variables that are associated with those
buffers.
This is implementing part of https://github.com/llvm/wg-hlsl/blob/main/proposals/0018-spirv-resource-representation.md.
We do not handle other HLSL raw buffer types.
---
clang/lib/CodeGen/Targets/SPIR.cpp | 15 +++-
.../StructuredBuffers-constructors.hlsl | 69 +++++++++++--------
2 files changed, 52 insertions(+), 32 deletions(-)
diff --git a/clang/lib/CodeGen/Targets/SPIR.cpp b/clang/lib/CodeGen/Targets/SPIR.cpp
index 43f511e572d37..8e8c46ef74041 100644
--- a/clang/lib/CodeGen/Targets/SPIR.cpp
+++ b/clang/lib/CodeGen/Targets/SPIR.cpp
@@ -386,13 +386,22 @@ llvm::Type *CommonSPIRTargetCodeGenInfo::getHLSLType(
if (ContainedTy.isNull())
return nullptr;
- assert(!ResAttrs.RawBuffer &&
- "Raw buffers handles are not implemented for SPIR-V yet");
assert(!ResAttrs.IsROV &&
"Rasterizer order views not implemented for SPIR-V yet");
- // convert element type
llvm::Type *ElemType = CGM.getTypes().ConvertType(ContainedTy);
+ if (ResAttrs.RawBuffer) {
+ llvm::ArrayType *RuntimeArrayType = llvm::ArrayType::get(ElemType, 0);
+
+ uint32_t StorageClass = /* StorageBuffer storage class */ 12;
+ bool IsWritable =
+ ResAttrs.ResourceClass == llvm::dxil::ResourceClass::UAV;
+ return llvm::TargetExtType::get(Ctx, "spirv.VulkanBuffer",
+ {RuntimeArrayType},
+ {StorageClass, IsWritable});
+ }
+
+ // convert element type
return getSPIRVImageTypeFromHLSLResource(ResAttrs, ElemType, Ctx);
}
case llvm::dxil::ResourceClass::CBuffer:
diff --git a/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl b/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl
index 04534c5550252..8a1429fd1a6fc 100644
--- a/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl
@@ -1,59 +1,70 @@
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-DXIL
-// RUN-DISABLED: %clang_cc1 -triple spirv-vulkan-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV
+// RUN: %clang_cc1 -triple spirv-vulkan-library -x hlsl -emit-llvm -DSPIRV -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV
-// NOTE: SPIRV codegen for resource types is not yet implemented
StructuredBuffer<float> Buf : register(t10);
RWStructuredBuffer<float> Buf2 : register(u5, space1);
+
+#ifndef SPIRV
+// NOTE: SPIRV codegen for these resource types is not implemented yet.
AppendStructuredBuffer<float> Buf3 : register(u3);
ConsumeStructuredBuffer<float> Buf4 : register(u4);
RasterizerOrderedStructuredBuffer<float> Buf5 : register(u1, space2);
+#endif
+
+// CHECK-DXIL: %"class.hlsl::StructuredBuffer" = type { target("dx.RawBuffer", float, 0, 0) }
+// CHECK-DXIL: %"class.hlsl::RWStructuredBuffer" = type { target("dx.RawBuffer", float, 1, 0) }
+// CHECK-DXIL: %"class.hlsl::AppendStructuredBuffer" = type { target("dx.RawBuffer", float, 1, 0) }
+// CHECK-DXIL: %"class.hlsl::ConsumeStructuredBuffer" = type { target("dx.RawBuffer", float, 1, 0) }
+// CHECK-DXIL: %"class.hlsl::RasterizerOrderedStructuredBuffer" = type { target("dx.RawBuffer", float, 1, 1) }
+
+// CHECK-SPIRV: %"class.hlsl::StructuredBuffer" = type { target("spirv.VulkanBuffer", [0 x float], 12, 0) }
+// CHECK-SPIRV: %"class.hlsl::RWStructuredBuffer" = type { target("spirv.VulkanBuffer", [0 x float], 12, 1) }
-// CHECK: %"class.hlsl::StructuredBuffer" = type { target("dx.RawBuffer", float, 0, 0) }
-// CHECK: %"class.hlsl::RWStructuredBuffer" = type { target("dx.RawBuffer", float, 1, 0) }
-// CHECK: %"class.hlsl::AppendStructuredBuffer" = type { target("dx.RawBuffer", float, 1, 0) }
-// CHECK: %"class.hlsl::ConsumeStructuredBuffer" = type { target("dx.RawBuffer", float, 1, 0) }
-// CHECK: %"class.hlsl::RasterizerOrderedStructuredBuffer" = type { target("dx.RawBuffer", float, 1, 1) }
-// CHECK: @_ZL3Buf = internal global %"class.hlsl::StructuredBuffer" poison, align 4
-// CHECK: @_ZL4Buf2 = internal global %"class.hlsl::RWStructuredBuffer" poison, align 4
-// CHECK: @_ZL4Buf3 = internal global %"class.hlsl::AppendStructuredBuffer" poison, align 4
-// CHECK: @_ZL4Buf4 = internal global %"class.hlsl::ConsumeStructuredBuffer" poison, align 4
-// CHECK: @_ZL4Buf5 = internal global %"class.hlsl::RasterizerOrderedStructuredBuffer" poison, align 4
+// CHECK: @_ZL3Buf = internal global %"class.hlsl::StructuredBuffer" poison
+// CHECK: @_ZL4Buf2 = internal global %"class.hlsl::RWStructuredBuffer" poison
+// CHECK-DXIL: @_ZL4Buf3 = internal global %"class.hlsl::AppendStructuredBuffer" poison, align 4
+// CHECK-DXIL: @_ZL4Buf4 = internal global %"class.hlsl::ConsumeStructuredBuffer" poison, align 4
+// CHECK-DXIL: @_ZL4Buf5 = internal global %"class.hlsl::RasterizerOrderedStructuredBuffer" poison, align 4
// CHECK: define internal void @_init_resource__ZL3Buf()
// CHECK-DXIL: [[H:%.*]] = call target("dx.RawBuffer", float, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_0_0t(i32 0, i32 10, i32 1, i32 0, i1 false)
// CHECK-DXIL: store target("dx.RawBuffer", float, 0, 0) [[H]], ptr @_ZL3Buf, align 4
+// CHECK-SPIRV: [[H:%.*]] = call target("spirv.VulkanBuffer", [0 x float], 12, 0) @llvm.spv.resource.handlefrombinding.tspirv.VulkanBuffer_a0f32_12_0t(i32 0, i32 10, i32 1, i32 0, i1 false)
+// CHECK-SPIRV: store target("spirv.VulkanBuffer", [0 x float], 12, 0) [[H]], ptr @_ZL3Buf, align 8
// CHECK: define internal void @_init_resource__ZL4Buf2()
// CHECK-DXIL: [[H:%.*]] = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 1, i32 5, i32 1, i32 0, i1 false)
// CHECK-DXIL: store target("dx.RawBuffer", float, 1, 0) [[H]], ptr @_ZL4Buf2, align 4
+// CHECK-SPIRV: [[H:%.*]] = call target("spirv.VulkanBuffer", [0 x float], 12, 1) @llvm.spv.resource.handlefrombinding.tspirv.VulkanBuffer_a0f32_12_1t(i32 1, i32 5, i32 1, i32 0, i1 false)
+// CHECK-SPIRV: store target("spirv.VulkanBuffer", [0 x float], 12, 1) [[H]], ptr @_ZL4Buf2, align 8
-// CHECK: define internal void @_init_resource__ZL4Buf3()
+// CHECK-DXIL: define internal void @_init_resource__ZL4Buf3()
// CHECK-DXIL: [[H:%.*]] = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 0, i32 3, i32 1, i32 0, i1 false)
// CHECK-DXIL: store target("dx.RawBuffer", float, 1, 0) [[H]], ptr @_ZL4Buf3, align 4
-// CHECK: define internal void @_init_resource__ZL4Buf4()
+// CHECK-DXIL: define internal void @_init_resource__ZL4Buf4()
// CHECK-DXIL: [[H:%.*]] = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 0, i32 4, i32 1, i32 0, i1 false)
// CHECK-DXIL: store target("dx.RawBuffer", float, 1, 0) [[H]], ptr @_ZL4Buf4, align 4
-// CHECK: define internal void @_init_resource__ZL4Buf5()
+// CHECK-DXIL: define internal void @_init_resource__ZL4Buf5()
// CHECK-DXIL: [[H:%.*]] = call target("dx.RawBuffer", float, 1, 1) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_1t(i32 2, i32 1, i32 1, i32 0, i1 false)
// CHECK-DXIL: store target("dx.RawBuffer", float, 1, 1) [[H]], ptr @_ZL4Buf5, align 4
-// CHECK: define linkonce_odr void @_ZN4hlsl16StructuredBufferIfEC2Ev(ptr noundef nonnull align 4 dereferenceable(4) %this)
-// CHECK-NEXT: entry:
-// CHECK: define linkonce_odr void @_ZN4hlsl18RWStructuredBufferIfEC2Ev(ptr noundef nonnull align 4 dereferenceable(4) %this)
-// CHECK-NEXT: entry:
-// CHECK: define linkonce_odr void @_ZN4hlsl22AppendStructuredBufferIfEC2Ev(ptr noundef nonnull align 4 dereferenceable(4) %this)
-// CHECK-NEXT: entry:
-// CHECK: define linkonce_odr void @_ZN4hlsl23ConsumeStructuredBufferIfEC2Ev(ptr noundef nonnull align 4 dereferenceable(4) %this)
-// CHECK: define linkonce_odr void @_ZN4hlsl33RasterizerOrderedStructuredBufferIfEC2Ev(ptr noundef nonnull align 4 dereferenceable(4) %this)
+// CHECK: define linkonce_odr void @_ZN4hlsl16StructuredBufferIfEC2Ev(ptr noundef nonnull align {{[48]}} dereferenceable({{[48]}}) %this)
// CHECK-NEXT: entry:
+// CHECK-DXIL: define linkonce_odr void @_ZN4hlsl18RWStructuredBufferIfEC2Ev(ptr noundef nonnull align 4 dereferenceable(4) %this)
+// CHECK-DXIL-NEXT: entry:
+// CHECK-DXIL: define linkonce_odr void @_ZN4hlsl22AppendStructuredBufferIfEC2Ev(ptr noundef nonnull align 4 dereferenceable(4) %this)
+// CHECK-DXIL-NEXT: entry:
+// CHECK-DXIL: define linkonce_odr void @_ZN4hlsl23ConsumeStructuredBufferIfEC2Ev(ptr noundef nonnull align 4 dereferenceable(4) %this)
+// CHECK-DXIL: define linkonce_odr void @_ZN4hlsl33RasterizerOrderedStructuredBufferIfEC2Ev(ptr noundef nonnull align 4 dereferenceable(4) %this)
+// CHECK-DXIL-NEXT: entry:
-// CHECK: define internal void @_GLOBAL__sub_I_StructuredBuffers_constructors.hlsl()
-// CHECK: call void @_init_resource__ZL3Buf()
-// CHECK: call void @_init_resource__ZL4Buf2()
-// CHECK: call void @_init_resource__ZL4Buf3()
-// CHECK: call void @_init_resource__ZL4Buf4()
-// CHECK: call void @_init_resource__ZL4Buf5()
+// CHECK: define {{.*}} void @_GLOBAL__sub_I_StructuredBuffers_constructors.hlsl()
+// CHECK: call {{.*}} @_init_resource__ZL3Buf()
+// CHECK: call {{.*}} @_init_resource__ZL4Buf2()
+// CHECK-DXIL: call void @_init_resource__ZL4Buf3()
+// CHECK-DXIL: call void @_init_resource__ZL4Buf4()
+// CHECK-DXIL: call void @_init_resource__ZL4Buf5()
>From 9902dfd4b7d29356cb6311135466f43aa6826ffb Mon Sep 17 00:00:00 2001
From: Steven Perron <stevenperron at google.com>
Date: Fri, 28 Mar 2025 14:33:38 -0400
Subject: [PATCH 2/2] Invert if-statement to reduce indent level of larget
block.
---
clang/lib/CodeGen/Targets/SPIR.cpp | 20 +++++++++-----------
1 file changed, 9 insertions(+), 11 deletions(-)
diff --git a/clang/lib/CodeGen/Targets/SPIR.cpp b/clang/lib/CodeGen/Targets/SPIR.cpp
index 8e8c46ef74041..225d9dfbd980b 100644
--- a/clang/lib/CodeGen/Targets/SPIR.cpp
+++ b/clang/lib/CodeGen/Targets/SPIR.cpp
@@ -390,19 +390,17 @@ llvm::Type *CommonSPIRTargetCodeGenInfo::getHLSLType(
"Rasterizer order views not implemented for SPIR-V yet");
llvm::Type *ElemType = CGM.getTypes().ConvertType(ContainedTy);
- if (ResAttrs.RawBuffer) {
- llvm::ArrayType *RuntimeArrayType = llvm::ArrayType::get(ElemType, 0);
-
- uint32_t StorageClass = /* StorageBuffer storage class */ 12;
- bool IsWritable =
- ResAttrs.ResourceClass == llvm::dxil::ResourceClass::UAV;
- return llvm::TargetExtType::get(Ctx, "spirv.VulkanBuffer",
- {RuntimeArrayType},
- {StorageClass, IsWritable});
+ if (!ResAttrs.RawBuffer) {
+ // convert element type
+ return getSPIRVImageTypeFromHLSLResource(ResAttrs, ElemType, Ctx);
}
- // convert element type
- return getSPIRVImageTypeFromHLSLResource(ResAttrs, ElemType, Ctx);
+ llvm::ArrayType *RuntimeArrayType = llvm::ArrayType::get(ElemType, 0);
+ uint32_t StorageClass = /* StorageBuffer storage class */ 12;
+ bool IsWritable = ResAttrs.ResourceClass == llvm::dxil::ResourceClass::UAV;
+ return llvm::TargetExtType::get(Ctx, "spirv.VulkanBuffer",
+ {RuntimeArrayType},
+ {StorageClass, IsWritable});
}
case llvm::dxil::ResourceClass::CBuffer:
llvm_unreachable("CBuffer handles are not implemented for SPIR-V yet");
More information about the cfe-commits
mailing list