- Proposal: NNNN
- Author(s): Cassandra Beckley
- Status: Design In Progress
We are implementing SpirvType and SpirvOpaqueType defined in
Inline SPIR-V (HLSL proposal 0011).
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.
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 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.
HLSLInlineSpirvType is a subclass of clang::Type, which has the properties
| Property | Description | Optional | Type |
|---|---|---|---|
Opcode |
SPIR-V opcode enumerant | 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 ofSpirvOperand |
A value of type HLSLInlineSpirvType is always canonical.
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 |
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 template.
template <uint32_t Opcode, uint32_t Size, uint32_t Alignment,
typename... Operands>
using __hlsl_spirv_type = ...;The implementation of this struct, represented above as ..., will be provided
as a
Clang builtin type alias.
This builtin can then be used to implement SpirvType and SpirvOpaqueType:
namespace vk {
template <uint Opcode, uint Size, uint Alignment, typename... Operands>
using SpirvType = __hlsl_spirv_type<Opcode, Size, Alignment, Operands...>;
template <uint Opcode, typename... Operands>
using SpirvOpaqueType = __hlsl_spirv_type<Opcode, 0, 0, Operands...>;
}Operands will be interpreted as specified in
Inline SPIR-V.
To specify an opaque type, Size and Alignment can be set to zero.