Skip to content

Inline SPIR‐V

Cassandra Beckley edited this page Feb 13, 2025 · 2 revisions

Overview

The inline SPIR-V intrinsics, attributes, and types allow developers to make new SPIR-V features available without updating HLSL. When a new extension is added to SPIR-V, the feature could be defined in an HLSL header file, and developers could use the feature without changing the compiler. We provide a quick rundown of the features.

Small examples are provided in the Inline SPIR-V proposal, and in the DXC tests.

Contributors

  • Steven Perron, Google LLC

Summary of HLSL attributes, types, and functions

Extensions and capabilities

  • vk::ext_extension(string extension_name)
    • An attribute that can be applied to
      • functions with the vk::ext_instruction attribute,
      • a shader entry pointer,
      • a variable, parameter variable, or member variable variable of type vk::SpirvType, or
      • a template type specialization of vk::SpirvType or vk::SpirvOpaqueType via using.
    • This attribute tells the compiler that if the function, variable, or type is used, then the extension must be added to the SPIR-V module.
  • vk::ext_capability(uint capability)
    • An attribute that can be applied in the same places as vk::ext_extension.
    • This attribute tells the compiler that if the function, variable, or type is used, then the capability must be added to the SPIR-V module.

Entry point execution modes

  • void vk::ext_execution_mode(ExecutionMode mode, …)
    • A call to this function will be turned into an OpExecutionMode instruction where the entry point will be the entry point currently being processed. The parameters will become the operands to the instruction.
    • All operands must be literals.
    • Note that if the function is not called directly in the entry point it is unclear which entry point it will apply to. When there is a single entry point being compiled, it will apply to that entry point. If using a lib_6_x target profile with multiple entry points, it will only be applied to one of them.
    • Note that DXC never implemented the extra arguments.
  • void vk::ext_execution_mode_id(uint execution_mode, ...)
    • This is the same as vk:ext_execution_mode except that it will generate an OpExecutionModeId instruction instead.
  • vk::spvexecutionmode(ExecutionMode)
    • This is an attribute that can be applied only to entry points.
    • It will generate an OpExecutionMode instruction that applies to the entry point with the attribute and the given execution mode.

Instructions

  • vk::ext_instruction(uint opcode, string extended_instruction_set)

    • An attribute that applies to a function prototype. There must not be a definition of the function.
    • The attribute indicates to the compiler that the definition of the function is a single SPIR-V instruction. If the extended_instruction_set is the empty string, then an instruction with the given opcode is generated. Otherwise, an OpExtInst instruction is generated for the given extended instruction set, and opcode becomes the instruction operand.
    • The function parameters become the operands to the instruction. By default, operands will be the id of the value provided. If it is a literal, then the id of the OpConstant will be used. If it is a variable, the id of OpLoad of the variable will be used. The vk::ext_reference and vk::ext_literal attributes can modify this. See below..
    • The return type for the instruction will be the return type of the function following the convention for return values used in the compiler.[1]
  • vk::ext_reference

    • An attribute that applies to a parameter of a function with the vk::ext_instruction attribute.
    • Parameters of this type must be variables. The operand to the instruction will be the pointer to the variable.
    • We do not place any restriction on the storage class of the variable used as the parameter. It is the user's responsibility to ensure the correct storage class is used.
  • vk::ext_literal

    • An attribute that applies to a parameter of a function with the vk::ext_instruction attribute.
    • Parameters of this type must be literal, and the operand to the instruction will be encoded as a literal operand.
  • vk::ext_result_id<T>

    • This is a type that can be used as a parameter or return type in a function with the vk::ext_instruction attribute.
    • It can be used to avoid the implied store of the return value, and the subsequent load of the operand.
    • Note: It is discouraged to use this type. In general, the optimizer will be able to remove the stores and loads. Also, the type can be used only in very specific situations, so it does not fit in well with HLSL. For this reason, it may be considered for deprecation in the future.

Variable annotations and types

  • vk::SpirvOpaqueType<uint OpCode, typename... Operands>
    • A type defined by a SPIR-V instruction with the given opcode.
    • The operands to the type are given in order in Operands.
    • If the typename is the type vk::integral_constant<typename T, T v>, then the operand will be the id of the OpConstant with value v and type T.
    • If the typename is vk::Literal<typename T>, where T is a vk::integral_constant, then the operand will be encoded as a literal with the given value instead of an OpConstant.
    • Otherwise, the operand will be the id of the given type.
    • This will be considered an opaque type, which will have no size or alignment requirements.
    • Because the compiler does not know the size and alignment, there are restrictions on where this type can be used. For example, it cannot be used in a StructureBuffer or any other external resource that is required to be fully laid out.
  • vk::SpirvType<uint OpCode, uint size, uint alignment, typename... Operands>
    • The same as vk::SpirvOpaqueType except that the type will have the given size and alignment requirements.
  • vk::ext_storage_class(uint storage_class)
    • This attribute applies to a variable declaration. The variable will be placed in the given storage class.
  • vk::ext_builtin_input(uint BuiltinID)
    • This attribute applies to file-scope static const variables.
    • It indicates that the variable is a builtin input in SPIR-V. It will be placed in the input storage class, and be decorated with the given builtin id.
  • vk::ext_builtin_output(uint BuiltinID)
    • This attribute applies to file-scope static variables.
    • It indicates that the variable is a builtin output in SPIR-V. It will be placed in the output storage class, and be decorated with the given builtin id.

Decorations

  • vk::ext_decorate(uint decorationId, … int / float / bool literal)
    • An attribute that applies to a function, variable, parameter, member variable, and typedef.
    • The object to which it is applied will be decorated with the given decoration using OpDecorate with the given decoration id. Other parameters will be added as literal operands.
  • vk::ext_decorate_id(decoration, … int / float / bool literals)
    • An attribute that applies to a function, variable, parameter, and typedef.
    • The object to which it is applied will be decorated with the given decoration using OpDecorateId with the given decoration id. The other parameters will be added using the id of the corresponding OpConstant* instructions.
  • vk::ext_decorate_string(decoration, … string literals)
    • An attribute that applies to a function, variable, parameter, and typedef.
    • The object to which it is applied will be decorated with the given decoration using OpDecorateId with the given decoration id. The other parameters will be encoded as string literals.

Notes

[1]: There is no formal ABI for HLSL to SPIR-V. This means the calling convention is compiler defined. Developers will have to make sure their instruction follows the conventions of the compiler being used. In particular, the return value for a function will not have a specified layout in DXC. If the result of the SPIR-V instruction will produce a struct with a defined layout, then invalid code will be generated by DXC.