Skip to content

Latest commit

 

History

History
126 lines (95 loc) · 6.08 KB

File metadata and controls

126 lines (95 loc) · 6.08 KB

Representing SpirvType in Clang's Type System

Introduction

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.

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 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

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.

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 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.