[clang] [HLSL][SPIRV] Add HLSL type translation for spirv. (PR #114273)

Steven Perron via cfe-commits cfe-commits at lists.llvm.org
Thu Oct 31 06:48:25 PDT 2024


https://github.com/s-perron updated https://github.com/llvm/llvm-project/pull/114273

>From 689f8d6be270321ffc1930162b318c134c9bb7f4 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/2] [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
---
 clang/lib/CodeGen/Targets/SPIR.cpp            | 81 +++++++++++++++++++
 .../builtins/RWBuffer-elementtype.hlsl        | 71 +++++++++-------
 2 files changed, 125 insertions(+), 27 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 fa81b53fd9bddc..374f600c75534b 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,COMMON
+// RUN: %clang_cc1 -triple spirv-pc-vulkan-compute -finclude-default-header -fnative-half-type -emit-llvm -o - %s | FileCheck %s -check-prefixes=SPIRV,COMMON
 
 // 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;
@@ -55,16 +72,16 @@ void main(int GI : SV_GroupIndex) {
   BufF32x3[GI] = 0;
 }
 
-// CHECK: !{{[0-9]+}} = !{ptr @BufI16, i32 10, i32 2,
-// CHECK: !{{[0-9]+}} = !{ptr @BufU16, i32 10, i32 3,
-// CHECK: !{{[0-9]+}} = !{ptr @BufI32, i32 10, i32 4,
-// CHECK: !{{[0-9]+}} = !{ptr @BufU32, i32 10, i32 5,
-// CHECK: !{{[0-9]+}} = !{ptr @BufI64, i32 10, i32 6,
-// CHECK: !{{[0-9]+}} = !{ptr @BufU64, i32 10, i32 7,
-// CHECK: !{{[0-9]+}} = !{ptr @BufF16, i32 10, i32 8,
-// CHECK: !{{[0-9]+}} = !{ptr @BufF32, i32 10, i32 9,
-// CHECK: !{{[0-9]+}} = !{ptr @BufF64, i32 10, i32 10,
-// CHECK: !{{[0-9]+}} = !{ptr @BufI16x4, i32 10, i32 2,
-// CHECK: !{{[0-9]+}} = !{ptr @BufU32x3, i32 10, i32 5,
-// CHECK: !{{[0-9]+}} = !{ptr @BufF16x2, i32 10, i32 8,
-// CHECK: !{{[0-9]+}} = !{ptr @BufF32x3, i32 10, i32 9,
+// COMMON: !{{[0-9]+}} = !{ptr @BufI16, i32 10, i32 2,
+// COMMON: !{{[0-9]+}} = !{ptr @BufU16, i32 10, i32 3,
+// COMMON: !{{[0-9]+}} = !{ptr @BufI32, i32 10, i32 4,
+// COMMON: !{{[0-9]+}} = !{ptr @BufU32, i32 10, i32 5,
+// COMMON: !{{[0-9]+}} = !{ptr @BufI64, i32 10, i32 6,
+// COMMON: !{{[0-9]+}} = !{ptr @BufU64, i32 10, i32 7,
+// COMMON: !{{[0-9]+}} = !{ptr @BufF16, i32 10, i32 8,
+// COMMON: !{{[0-9]+}} = !{ptr @BufF32, i32 10, i32 9,
+// COMMON: !{{[0-9]+}} = !{ptr @BufF64, i32 10, i32 10,
+// COMMON: !{{[0-9]+}} = !{ptr @BufI16x4, i32 10, i32 2,
+// COMMON: !{{[0-9]+}} = !{ptr @BufU32x3, i32 10, i32 5,
+// COMMON: !{{[0-9]+}} = !{ptr @BufF16x2, i32 10, i32 8,
+// COMMON: !{{[0-9]+}} = !{ptr @BufF32x3, i32 10, i32 9,

>From 994c9b2fd1c39dd7c19d2b4eb32bd4f79f83fb83 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/2] 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};



More information about the cfe-commits mailing list