[clang] [HLSL][SPIRV] Add HLSL type translation for spirv. (PR #114273)
Steven Perron via cfe-commits
cfe-commits at lists.llvm.org
Mon Nov 4 07:23:48 PST 2024
https://github.com/s-perron updated https://github.com/llvm/llvm-project/pull/114273
>From 215a3427acd5f5ab5fc5fb889a235c3ac7abcdfb Mon Sep 17 00:00:00 2001
From: Steven Perron <stevenperron at google.com>
Date: Tue, 1 Oct 2024 09:56:20 -0400
Subject: [PATCH 1/5] [HLSL][SPIRV] Add HLSL type translation for spirv.
This commit partially implements SPIRTargetCodeGenInfo::getHLSLType. It
can now generate the spirv type for the following HLSL types:
1. RWBuffer
2. Buffer
3. Sampler
# Conflicts:
# clang/test/CodeGenHLSL/builtins/RWBuffer-elementtype.hlsl
---
clang/lib/CodeGen/Targets/SPIR.cpp | 81 +++++++++++++++++++
.../builtins/RWBuffer-elementtype.hlsl | 45 +++++++----
2 files changed, 112 insertions(+), 14 deletions(-)
diff --git a/clang/lib/CodeGen/Targets/SPIR.cpp b/clang/lib/CodeGen/Targets/SPIR.cpp
index 7dd5c518e7149a..e6921d65084701 100644
--- a/clang/lib/CodeGen/Targets/SPIR.cpp
+++ b/clang/lib/CodeGen/Targets/SPIR.cpp
@@ -52,6 +52,10 @@ class CommonSPIRTargetCodeGenInfo : public TargetCodeGenInfo {
unsigned getOpenCLKernelCallingConv() const override;
llvm::Type *getOpenCLType(CodeGenModule &CGM, const Type *T) const override;
+ llvm::Type *getHLSLType(CodeGenModule &CGM, const Type *Ty) const override;
+ llvm::Type *getSPIRVImageTypeFromHLSLResource(
+ const HLSLAttributedResourceType::Attributes &attributes,
+ llvm::Type *ElementType, llvm::LLVMContext &Ctx) const;
};
class SPIRVTargetCodeGenInfo : public CommonSPIRTargetCodeGenInfo {
public:
@@ -323,6 +327,83 @@ llvm::Type *CommonSPIRTargetCodeGenInfo::getOpenCLType(CodeGenModule &CGM,
return nullptr;
}
+llvm::Type *CommonSPIRTargetCodeGenInfo::getHLSLType(CodeGenModule &CGM,
+ const Type *Ty) const {
+ auto *ResType = dyn_cast<HLSLAttributedResourceType>(Ty);
+ if (!ResType)
+ return nullptr;
+
+ llvm::LLVMContext &Ctx = CGM.getLLVMContext();
+ const HLSLAttributedResourceType::Attributes &ResAttrs = ResType->getAttrs();
+ switch (ResAttrs.ResourceClass) {
+ case llvm::dxil::ResourceClass::UAV:
+ case llvm::dxil::ResourceClass::SRV: {
+ // TypedBuffer and RawBuffer both need element type
+ QualType ContainedTy = ResType->getContainedType();
+ 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);
+ return getSPIRVImageTypeFromHLSLResource(ResAttrs, ElemType, Ctx);
+ }
+ case llvm::dxil::ResourceClass::CBuffer:
+ llvm_unreachable("CBuffer handles are not implemented for SPIR-V yet");
+ break;
+ case llvm::dxil::ResourceClass::Sampler:
+ return llvm::TargetExtType::get(Ctx, "spirv.Sampler");
+ }
+ return nullptr;
+}
+
+llvm::Type *CommonSPIRTargetCodeGenInfo::getSPIRVImageTypeFromHLSLResource(
+ const HLSLAttributedResourceType::Attributes &attributes,
+ llvm::Type *ElementType, llvm::LLVMContext &Ctx) const {
+
+ if (ElementType->isVectorTy()) {
+ ElementType = ElementType->getScalarType();
+ }
+
+ if (!ElementType->isIntegerTy() && !ElementType->isFloatingPointTy()) {
+ // TODO: Should there be an error message?
+ ElementType->dump();
+ assert(false && "Bad element type");
+ return nullptr;
+ }
+
+ // For HLSL types, the depth is always 2.
+ SmallVector<unsigned, 6> IntParams = {0, 2, 0, 0, 1, 0};
+
+ // Dim
+ // For now we assume everything is a buffer.
+ IntParams[0] = 5;
+
+ // Depth
+ // HLSL does not indicate if it is a depth texture or not, so we use unknown.
+ IntParams[1] = 2;
+
+ // Arrayed
+ IntParams[2] = 0;
+
+ // MS
+ IntParams[3] = 0;
+
+ // Sampled
+ IntParams[4] =
+ attributes.ResourceClass == llvm::dxil::ResourceClass::UAV ? 2 : 1;
+
+ // Image format.
+ // Setting to unknown for now.
+ IntParams[5] = 0;
+
+ return llvm::TargetExtType::get(Ctx, "spirv.Image", {ElementType}, IntParams);
+}
+
std::unique_ptr<TargetCodeGenInfo>
CodeGen::createCommonSPIRTargetCodeGenInfo(CodeGenModule &CGM) {
return std::make_unique<CommonSPIRTargetCodeGenInfo>(CGM.getTypes());
diff --git a/clang/test/CodeGenHLSL/builtins/RWBuffer-elementtype.hlsl b/clang/test/CodeGenHLSL/builtins/RWBuffer-elementtype.hlsl
index 16120a44a9e4d2..d737d76a9d8d97 100644
--- a/clang/test/CodeGenHLSL/builtins/RWBuffer-elementtype.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/RWBuffer-elementtype.hlsl
@@ -1,22 +1,39 @@
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.2-compute -finclude-default-header -fnative-half-type -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.2-compute -finclude-default-header -fnative-half-type -emit-llvm -o - %s | FileCheck %s -check-prefixes=DXIL
+// RUN: %clang_cc1 -triple spirv-pc-vulkan-compute -finclude-default-header -fnative-half-type -emit-llvm -o - %s | FileCheck %s -check-prefixes=SPIRV
// NOTE: The type name number and whether the struct is packed or not will mostly
// likely change once subscript operators are properly implemented (llvm/llvm-project#95956)
// and theinterim field of the contained type is removed.
-// CHECK: %"class.hlsl::RWBuffer" = type <{ target("dx.TypedBuffer", i16, 1, 0, 1)
-// CHECK: %"class.hlsl::RWBuffer.0" = type <{ target("dx.TypedBuffer", i16, 1, 0, 0)
-// CHECK: %"class.hlsl::RWBuffer.2" = type { target("dx.TypedBuffer", i32, 1, 0, 1)
-// CHECK: %"class.hlsl::RWBuffer.3" = type { target("dx.TypedBuffer", i32, 1, 0, 0)
-// CHECK: %"class.hlsl::RWBuffer.4" = type { target("dx.TypedBuffer", i64, 1, 0, 1)
-// CHECK: %"class.hlsl::RWBuffer.5" = type { target("dx.TypedBuffer", i64, 1, 0, 0)
-// CHECK: %"class.hlsl::RWBuffer.6" = type <{ target("dx.TypedBuffer", half, 1, 0, 0)
-// CHECK: %"class.hlsl::RWBuffer.8" = type { target("dx.TypedBuffer", float, 1, 0, 0)
-// CHECK: %"class.hlsl::RWBuffer.9" = type { target("dx.TypedBuffer", double, 1, 0, 0)
-// CHECK: %"class.hlsl::RWBuffer.10" = type { target("dx.TypedBuffer", <4 x i16>, 1, 0, 0)
-// CHECK: %"class.hlsl::RWBuffer.11" = type { target("dx.TypedBuffer", <3 x i32>, 1, 0, 0)
-// CHECK: %"class.hlsl::RWBuffer.12" = type { target("dx.TypedBuffer", <2 x half>, 1, 0, 0)
-// CHECK: %"class.hlsl::RWBuffer.13" = type { target("dx.TypedBuffer", <3 x float>, 1, 0, 0)
+// DXIL: %"class.hlsl::RWBuffer" = type <{ target("dx.TypedBuffer", i16, 1, 0, 1)
+// DXIL: %"class.hlsl::RWBuffer.0" = type <{ target("dx.TypedBuffer", i16, 1, 0, 0)
+// DXIL: %"class.hlsl::RWBuffer.2" = type { target("dx.TypedBuffer", i32, 1, 0, 1)
+// DXIL: %"class.hlsl::RWBuffer.3" = type { target("dx.TypedBuffer", i32, 1, 0, 0)
+// DXIL: %"class.hlsl::RWBuffer.4" = type { target("dx.TypedBuffer", i64, 1, 0, 1)
+// DXIL: %"class.hlsl::RWBuffer.5" = type { target("dx.TypedBuffer", i64, 1, 0, 0)
+// DXIL: %"class.hlsl::RWBuffer.6" = type <{ target("dx.TypedBuffer", half, 1, 0, 0)
+// DXIL: %"class.hlsl::RWBuffer.8" = type { target("dx.TypedBuffer", float, 1, 0, 0)
+// DXIL: %"class.hlsl::RWBuffer.9" = type { target("dx.TypedBuffer", double, 1, 0, 0)
+// DXIL: %"class.hlsl::RWBuffer.10" = type { target("dx.TypedBuffer", <4 x i16>, 1, 0, 0)
+// DXIL: %"class.hlsl::RWBuffer.11" = type { target("dx.TypedBuffer", <3 x i32>, 1, 0, 0)
+// DXIL: %"class.hlsl::RWBuffer.12" = type { target("dx.TypedBuffer", <2 x half>, 1, 0, 0)
+// DXIL: %"class.hlsl::RWBuffer.13" = type { target("dx.TypedBuffer", <3 x float>, 1, 0, 0)
+
+// SPIRV: %"class.hlsl::RWBuffer" = type <{ target("spirv.Image", i16, 5, 2, 0, 0, 2, 0), i16, [6 x i8] }>
+// SPIRV: %"class.hlsl::RWBuffer.0" = type <{ target("spirv.Image", i16, 5, 2, 0, 0, 2, 0), i16, [6 x i8] }>
+// SPIRV: %"class.hlsl::RWBuffer.2" = type <{ target("spirv.Image", i32, 5, 2, 0, 0, 2, 0), i32, [4 x i8] }>
+// SPIRV: %"class.hlsl::RWBuffer.4" = type <{ target("spirv.Image", i32, 5, 2, 0, 0, 2, 0), i32, [4 x i8] }>
+// SPIRV: %"class.hlsl::RWBuffer.6" = type { target("spirv.Image", i64, 5, 2, 0, 0, 2, 0), i64 }
+// SPIRV: %"class.hlsl::RWBuffer.7" = type { target("spirv.Image", i64, 5, 2, 0, 0, 2, 0), i64 }
+// SPIRV: %"class.hlsl::RWBuffer.8" = type <{ target("spirv.Image", half, 5, 2, 0, 0, 2, 0), half, [6 x i8] }>
+// SPIRV: %"class.hlsl::RWBuffer.10" = type <{ target("spirv.Image", float, 5, 2, 0, 0, 2, 0), float, [4 x i8] }>
+// SPIRV: %"class.hlsl::RWBuffer.12" = type { target("spirv.Image", double, 5, 2, 0, 0, 2, 0), double }
+// SPIRV: %"class.hlsl::RWBuffer.13" = type { target("spirv.Image", i16, 5, 2, 0, 0, 2, 0), <4 x i16> }
+// SPIRV: %"class.hlsl::RWBuffer.14" = type { target("spirv.Image", i32, 5, 2, 0, 0, 2, 0), <3 x i32> }
+// SPIRV: %"class.hlsl::RWBuffer.15" = type <{ target("spirv.Image", half, 5, 2, 0, 0, 2, 0), <2 x half>, [4 x i8] }>
+// SPIRV: %"class.hlsl::RWBuffer.17" = type { target("spirv.Image", float, 5, 2, 0, 0, 2, 0), <3 x float> }
+
+
RWBuffer<int16_t> BufI16;
RWBuffer<uint16_t> BufU16;
>From 6f567318f08a02866653479bdef9af02662154fd Mon Sep 17 00:00:00 2001
From: Steven Perron <stevenperron at google.com>
Date: Thu, 31 Oct 2024 09:48:10 -0400
Subject: [PATCH 2/5] Remove debugging code.
---
clang/lib/CodeGen/Targets/SPIR.cpp | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/clang/lib/CodeGen/Targets/SPIR.cpp b/clang/lib/CodeGen/Targets/SPIR.cpp
index e6921d65084701..e3ca01a2b2b6f8 100644
--- a/clang/lib/CodeGen/Targets/SPIR.cpp
+++ b/clang/lib/CodeGen/Targets/SPIR.cpp
@@ -369,12 +369,8 @@ llvm::Type *CommonSPIRTargetCodeGenInfo::getSPIRVImageTypeFromHLSLResource(
ElementType = ElementType->getScalarType();
}
- if (!ElementType->isIntegerTy() && !ElementType->isFloatingPointTy()) {
- // TODO: Should there be an error message?
- ElementType->dump();
- assert(false && "Bad element type");
- return nullptr;
- }
+ assert (!ElementType->isIntegerTy() && !ElementType->isFloatingPointTy() &&
+ "The element type for a SPIR-V resource must be a scalar integer or floating point type.");
// For HLSL types, the depth is always 2.
SmallVector<unsigned, 6> IntParams = {0, 2, 0, 0, 1, 0};
>From d62b540fa41a41ce5461fe01858fc91e9fc83b1d Mon Sep 17 00:00:00 2001
From: Steven Perron <stevenperron at google.com>
Date: Thu, 31 Oct 2024 09:53:26 -0400
Subject: [PATCH 3/5] Fix operand init.
---
clang/lib/CodeGen/Targets/SPIR.cpp | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/clang/lib/CodeGen/Targets/SPIR.cpp b/clang/lib/CodeGen/Targets/SPIR.cpp
index e3ca01a2b2b6f8..fdbd1dbb417e08 100644
--- a/clang/lib/CodeGen/Targets/SPIR.cpp
+++ b/clang/lib/CodeGen/Targets/SPIR.cpp
@@ -369,11 +369,14 @@ llvm::Type *CommonSPIRTargetCodeGenInfo::getSPIRVImageTypeFromHLSLResource(
ElementType = ElementType->getScalarType();
}
- assert (!ElementType->isIntegerTy() && !ElementType->isFloatingPointTy() &&
- "The element type for a SPIR-V resource must be a scalar integer or floating point type.");
-
- // For HLSL types, the depth is always 2.
- SmallVector<unsigned, 6> IntParams = {0, 2, 0, 0, 1, 0};
+ assert(!ElementType->isIntegerTy() && !ElementType->isFloatingPointTy() &&
+ "The element type for a SPIR-V resource must be a scalar integer or "
+ "floating point type.");
+
+ // These parameters correspond to the operands to the OpTypeImage SPIR-V
+ // instruction. See
+ // https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpTypeImage.
+ SmallVector<unsigned, 6> IntParams = {0};
// Dim
// For now we assume everything is a buffer.
>From 039f3e1146972af2d9d102cbe28c7ad97dad923f Mon Sep 17 00:00:00 2001
From: Steven Perron <stevenperron at google.com>
Date: Mon, 4 Nov 2024 09:45:36 -0500
Subject: [PATCH 4/5] Update clang/lib/CodeGen/Targets/SPIR.cpp
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Nathan Gauër <github at keenuts.net>
---
clang/lib/CodeGen/Targets/SPIR.cpp | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/clang/lib/CodeGen/Targets/SPIR.cpp b/clang/lib/CodeGen/Targets/SPIR.cpp
index fdbd1dbb417e08..ce6553ef6e22df 100644
--- a/clang/lib/CodeGen/Targets/SPIR.cpp
+++ b/clang/lib/CodeGen/Targets/SPIR.cpp
@@ -365,9 +365,8 @@ llvm::Type *CommonSPIRTargetCodeGenInfo::getSPIRVImageTypeFromHLSLResource(
const HLSLAttributedResourceType::Attributes &attributes,
llvm::Type *ElementType, llvm::LLVMContext &Ctx) const {
- if (ElementType->isVectorTy()) {
+ if (ElementType->isVectorTy())
ElementType = ElementType->getScalarType();
- }
assert(!ElementType->isIntegerTy() && !ElementType->isFloatingPointTy() &&
"The element type for a SPIR-V resource must be a scalar integer or "
>From 21f2d1f27d15e73663c852d33e568d9a99ff3456 Mon Sep 17 00:00:00 2001
From: Steven Perron <stevenperron at google.com>
Date: Mon, 4 Nov 2024 10:23:33 -0500
Subject: [PATCH 5/5] Fix assert, and vector initial size.
---
clang/lib/CodeGen/Targets/SPIR.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/lib/CodeGen/Targets/SPIR.cpp b/clang/lib/CodeGen/Targets/SPIR.cpp
index ce6553ef6e22df..a48fe9d5f1ee9c 100644
--- a/clang/lib/CodeGen/Targets/SPIR.cpp
+++ b/clang/lib/CodeGen/Targets/SPIR.cpp
@@ -368,14 +368,14 @@ llvm::Type *CommonSPIRTargetCodeGenInfo::getSPIRVImageTypeFromHLSLResource(
if (ElementType->isVectorTy())
ElementType = ElementType->getScalarType();
- assert(!ElementType->isIntegerTy() && !ElementType->isFloatingPointTy() &&
+ assert((ElementType->isIntegerTy() || ElementType->isFloatingPointTy()) &&
"The element type for a SPIR-V resource must be a scalar integer or "
"floating point type.");
// These parameters correspond to the operands to the OpTypeImage SPIR-V
// instruction. See
// https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpTypeImage.
- SmallVector<unsigned, 6> IntParams = {0};
+ SmallVector<unsigned, 6> IntParams(6, 0);
// Dim
// For now we assume everything is a buffer.
More information about the cfe-commits
mailing list