From d010b4974a8902dbd3ebed51cfeaeb8e9e05f991 Mon Sep 17 00:00:00 2001 From: Cassandra Beckley Date: Fri, 21 Feb 2025 15:49:43 -0800 Subject: [PATCH 1/2] [SPIR-V] Representing SpirvType in Clang's Type System This describes an approach to representing `SpirvType` in Clang. --- proposals/NNNN-spirv-types-in-clang.md | 113 +++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 proposals/NNNN-spirv-types-in-clang.md diff --git a/proposals/NNNN-spirv-types-in-clang.md b/proposals/NNNN-spirv-types-in-clang.md new file mode 100644 index 0000000..b475045 --- /dev/null +++ b/proposals/NNNN-spirv-types-in-clang.md @@ -0,0 +1,113 @@ + + +# Representing SpirvType in Clang's Type System + +- Proposal: [NNNN](NNNN-spirv-types-in-clang.md) +- Author(s): [Cassandra Beckley](https://github.com/cassiebeckley) +- Status: **Design In Progress** + +## Introduction + +We are implementing `SpirvType` and `SpirvOpaqueType` defined in +[Inline SPIR-V (HLSL proposal 0011)](https://github.com/microsoft/hlsl-specs/blob/main/proposals/0011-inline-spirv.md#types). +In order to support this feature, we need a way to represent inline SPIR-V types +in the Clang type system. To facilitate this, I am proposing +`HLSLInlineSpirvType` as a new `Type` subclass, and `__hlsl_spirv_type` as a new +builtin template to create such a type. + +## Motivation + +In DXC, we represented `SpirvType` as a template for a struct. This was simple +to implement, since in DXC we lower the AST directly to SPIR-V without going +through LLVM codegen, and could add special cases handling structs that were +`SpirvType` specializations while lowering types. However, this approach does +not interact well with Sema and the rest of Clang, resulting in at least several +bugs in handling template arguments and other areas. In order to take the same +approach in Clang, we would need to add special case handling while lowering +struct types, as well as for calculating size and alignment and anywhere else +structs are interacted with in Clang. Struct types are already processed +separately from all other types while lowering, and adding special cases for +`SpirvType` would complicate their handling even more. + +Finally, a struct is not a good semantic representation of a `SpirvType`. +`SpirvType` is fundamentally a new kind of type for Clang that is different from +all existing types—it represents a low-level target type specified by the user. + +## Proposed solution + +### Type Representation + +Describe your solution to the problem. Provide examples and describe how they +work. Show how your solution is better than current workarounds: is it cleaner, +safer, or more efficient? + +`HLSLInlineSpirvType` is a subclass of `clang::Type`, which has the properties + +| Property | Optional | Type | +| ----------- | -------- | ---------------------- | +| `Operand` | no | `uint32_t` | +| `Size` | yes | `uint32_t` | +| `Alignment` | yes | `uint32_t` | +| `Operands` | no | array of`SpirvOperand` | + +A value of type `HLSLInlineSpirvType` is always canonical. + +#### Operands + +Each operand in `Operands` is a value of the nested class +`HLSLInlineSpirvType::SpirvOperand`, which can be one of the following kinds: + +| Kind | Description | Has Result Type | Has Integral Value | +| ------------ | ---------------------------------------------------------------------------------- | --------------- | ------------------ | +| `ConstantId` | Represents a value to be passed in as the ID of a SPIR-V `OpConstant` instruction. | yes | yes | +| `Literal` | Represents a value to be passed in as an immediate literal. | no | yes | +| `TypeId` | Represents a type to be passed in as the ID of a SPIR-V `OpType*` instruction | yes | no | + +### Type Declaration + +Since `HLSLInlineSpirvType` types should only be created using the `SpirvType` +and `SpirvOpaqueType` templates, we do not need to provide special syntax for +their declaration. In order to implement these templates, and to avoid the +necessity of creating an additional dependent type, these types will be created +using a `vk::__hlsl_spirv_type` builtin template. + +```C++ +template +using __hlsl_spirv_type = ...; +``` + +Operands will be interpreted as specified in +[Inline SPIR-V](https://github.com/microsoft/hlsl-specs/blob/main/proposals/0011-inline-spirv.md#types). +To specify an opaque type, `Size` and `Alignment` can be set to zero. + + + + From b37b1d0edbaac23dca762e6d792a85ff72167567 Mon Sep 17 00:00:00 2001 From: Cassandra Beckley Date: Wed, 26 Feb 2025 10:00:20 -0800 Subject: [PATCH 2/2] Address feedback --- proposals/NNNN-spirv-types-in-clang.md | 49 ++++++++++++++++---------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/proposals/NNNN-spirv-types-in-clang.md b/proposals/NNNN-spirv-types-in-clang.md index b475045..ebbb544 100644 --- a/proposals/NNNN-spirv-types-in-clang.md +++ b/proposals/NNNN-spirv-types-in-clang.md @@ -21,34 +21,32 @@ In DXC, we represented `SpirvType` as a template for a struct. This was simple to implement, since in DXC we lower the AST directly to SPIR-V without going through LLVM codegen, and could add special cases handling structs that were `SpirvType` specializations while lowering types. However, this approach does -not interact well with Sema and the rest of Clang, resulting in at least several -bugs in handling template arguments and other areas. In order to take the same -approach in Clang, we would need to add special case handling while lowering -struct types, as well as for calculating size and alignment and anywhere else -structs are interacted with in Clang. Struct types are already processed -separately from all other types while lowering, and adding special cases for -`SpirvType` would complicate their handling even more. +not interact well with Sema and the rest of Clang, resulting in several bugs in +handling template arguments and other areas. In order to take the same approach +in Clang, we would need to add special case handling while lowering struct +types, as well as for calculating size and alignment and anywhere else structs +are interacted with in Clang. Struct types are already processed separately from +all other types while lowering, and adding special cases for `SpirvType` would +complicate their handling even more. Finally, a struct is not a good semantic representation of a `SpirvType`. `SpirvType` is fundamentally a new kind of type for Clang that is different from all existing types—it represents a low-level target type specified by the user. +This type is opaque and cannot be represented as a struct because Clang does not +treat structs as opaque. ## Proposed solution ### Type Representation -Describe your solution to the problem. Provide examples and describe how they -work. Show how your solution is better than current workarounds: is it cleaner, -safer, or more efficient? - `HLSLInlineSpirvType` is a subclass of `clang::Type`, which has the properties -| Property | Optional | Type | -| ----------- | -------- | ---------------------- | -| `Operand` | no | `uint32_t` | -| `Size` | yes | `uint32_t` | -| `Alignment` | yes | `uint32_t` | -| `Operands` | no | array of`SpirvOperand` | +| Property | Description | Optional | Type | +| ----------- | -------------------------------------------------------------------------------------------------------- | -------- | ---------------------- | +| `Opcode` | [SPIR-V opcode enumerant](https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#_instructions_3) | no | `uint32_t` | +| `Size` | Number of bytes a single value of the type occupies | yes | `uint32_t` | +| `Alignment` | A power of two that the value will be aligned to in memory | yes | `uint32_t` | +| `Operands` | List of arguments to the SPIR-V type instruction | no | array of`SpirvOperand` | A value of type `HLSLInlineSpirvType` is always canonical. @@ -69,7 +67,7 @@ Since `HLSLInlineSpirvType` types should only be created using the `SpirvType` and `SpirvOpaqueType` templates, we do not need to provide special syntax for their declaration. In order to implement these templates, and to avoid the necessity of creating an additional dependent type, these types will be created -using a `vk::__hlsl_spirv_type` builtin template. +using a `vk::__hlsl_spirv_type` template. ```C++ template + using SpirvType = __hlsl_spirv_type; + + template + using SpirvOpaqueType = __hlsl_spirv_type; +} +``` + Operands will be interpreted as specified in [Inline SPIR-V](https://github.com/microsoft/hlsl-specs/blob/main/proposals/0011-inline-spirv.md#types). To specify an opaque type, `Size` and `Alignment` can be set to zero.