449 lines · plain
1==============================================================2Specification of DXIL Operations using TableGen Representation3==============================================================4.. contents::5 :local:6 7.. toctree8 :hidden9 10Introduction11============12 13`DirectXShaderCompiler <https://github.com/microsoft/DirectXShaderCompiler>`_14encapsulates, among other information, various DXIL Operations in15`hctdb.py <https://github.com/microsoft/DirectXShaderCompiler/blob/main/utils/hct/hctdb.py>`_.16DXIL Operations are represented in one of the following `two ways17<https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/DXIL.rst#operations>`_:18 19#. Using LLVM instructions.20#. Using LLVM External functions. These are represented in LLVM IR as follows:21 22 * "Standard" LLVM intrinsics (e.g., ``llvm.sin.*``) and23 * HLSL intrinsics (defined as LLVM intrinsics in ``llvm/include/llvm/IR/IntrinsicsDirectX.td``, e.g., ``llvm.dx.*``)24 25 These are collectively referred to as `LLVM Intrinsics` in this note.26 27Following is the complete list of properties of DXIL Ops with the corresponding field name28as used in ``hctdb.py``. A DXIL Op is represented by a set of associated properties. These29are consumed in DXIL backend passes as well as in other usage scenarios such as validation,30DXIL reader, etc.31 32A. Properties consumed in DXIL backend passes33 34 1. Name of operation (``dxil_op``)35 2. A string that documents the operation (``doc``) - This is not strictly necessary but is included36 for readability and documentation of the operation.37 3. The generic or HLSL-specific intrinsic that maps to the operation (``llvm_name``).38 4. Unique Integer ID (``dxil_opid``)39 5. Operation Class signifying the name and function signature of the operation (``dxil_class``).40 This string is an integral part of the DXIL Op function name and is constructed in41 the format ``dx.op.<class-name>.<overload-type>``. Each DXIL Op call target function name42 is required to conform to this format per existing contract with the driver.43 6. List of valid overload types for the operation (``oload_types``).44 7. Required DXIL Version with support for the operation.45 8. Required minimum Shader Model (``shader_model``).46 9. Minimum shader model required with translation by linker (``shader_model_translated``)47 10. List of shader stages applicable to (``shader_stages``), empty, if applicable to all stages.48 11. Memory access attributes of the operation (``fn_attr``).49 12. Boolean attributes of operation to indicate if it50 51 * is some kind of a derivative (``is_derivative``)52 * requires gradient calculation (``is_gradient``)53 * is a sampler feedback (``is_feedback``)54 * requires in-wave, cross-lane functionality (``is_wave``)55 * requires that all of its inputs are uniform across the wave (``requires_uniform_inputs``).56 * is a barrier operation (``is_barrier``).57 58Motivation59==========60 61DXIL backend passes depend on various properties of DXIL Operations. For example, ``DXILOpLowering``62pass will need information such as the DXIL operation an LLVM intrinsic is to be lowered to,63along with valid overload and argument types etc. The TableGen file -64``llvm/lib/Target/DirectX/DXIL.td`` - is used to represent DXIL Operations65by specifying their properties listed above. ``DXIL.td`` is designed to be the single source66of reference of DXIL Operations primarily for the implementation of passes in DXIL backend in67``llvm-project`` repo - analogous to ``hctdb.py`` for ``DirectXShadeCompiler`` repo. However,68the current design does not intend to encapsulate various validation rules, present in ``hctdb.py``,69but do not pertain to DXIL Operations. It needs to have a rich representation capabilities that70TableGen backends (such as ``DXILEmitter``) can rely on. Additionally, the DXIL Op specification71should be easy to read and comprehend.72 73This note provides the design of the specification DXIL Ops as TableGen class ``DXILOp``74by specifying its properties identified above.75 76DXIL Operation Specification77============================78 79The DXIL Operation is represented using the TableGen class ``DXILOp``. The DXIL operation80properties are specified as fields of the ``DXILOp`` class as described below.81 821. Each DXIL Operation is represented as a TableGen record. The name of each of the records83 signifies operation name.842. A documentation string for the operation.853. The LLVM Intrinsic that maps to the operation is represented as ``Intrinsic`` defined in86 `Intrinsics.td <https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/IR/Intrinsics.td>`_.874. The unique operation id is represented by an integer.885. DXIL Operation Class is represented as follows89 90 .. code-block::91 92 // Abstraction of DXIL Operation class.93 class DXILOpClass;94 95 Concrete operation records, such as ``unary`` are defined by inheriting from ``DXILOpClass``.966. A set of type names are defined that represent return and argument types,97 which all inherit from ``DXILOpParamType``. These represent simple types98 like ``int32Ty``, DXIL types like ``dx.types.Handle``, and a special99 ``overloadTy`` which can be any type allowed by ``Overloads``, described100 below.1017. Operation return type is represented as a ``DXILOpParamType``, and arguments102 are represented as a list of the same. An operation with no return value103 shall specify ``VoidTy`` as its return.1048. Valid operation overload types predicated on DXIL version are specified as105 a list of ``Overloads`` records. Representation of ``Overloads``106 class is described in a later section.1079. Valid shader stages predicated on DXIL version are specified as a list of108 ``Stages`` records. Representation of ``Stages`` class is109 described in a later section.11010. Various attributes of the DXIL Operation are represented as a ``list`` of111 ``Attributes`` class records. Representation of ``Attributes``112 class is described in a later section.113 114Types specific to DXIL115----------------------116 117Type notation used in this document viz., ``<size>Ty`` corresponds to TableGen records for118LLVM types ``llvm_<size>_ty``. Apart from ``overloadTy`` described above, ``resRetF32Ty`` is119used to denote resource return type and ``handleTy`` is used to denote handle type.120 121Specification of DXIL Operation122================================123 124A DXIL Operation is represented by the following TableGen class that encapsulates the various125TableGen representations of its properties described above.126 127.. code-block::128 129 // Abstraction DXIL Operation130 class DXILOp<int opcode, DXILOpClass opclass> {131 // A short description of the operation132 string Doc = "";133 134 // Opcode of DXIL Operation135 int OpCode = opcode;136 137 // Class of DXIL Operation.138 DXILOpClass OpClass = opclass;139 140 // LLVM Intrinsic DXIL Operation maps to141 Intrinsic LLVMIntrinsic = ?;142 143 // Result type of the op.144 DXILOpParamType result;145 146 // List of argument types of the op. Default to 0 arguments.147 list<DXILOpParamType> arguments = [];148 149 // List of valid overload types predicated by DXIL version150 list<Overloads> overloads;151 152 // List of valid shader stages predicated by DXIL version153 list<Stages> stages;154 155 // List of valid attributes predicated by DXIL version156 list<Attributes> attributes = [];157 }158 159Version Specification160=====================161 162DXIL version is used to specify various version-dependent operation properties in163place of Shader Model version.164 165A ``Version`` class encapsulating ``Major`` and ``Minor`` version number is defined166as follows:167 168.. code-block::169 170 // Abstract class to represent major and minor version values171 class Version<int major, int minor> {172 int Major = major;173 int Minor = minor;174 }175 176 177Concrete representations of valid DXIL versions are defined as follows:178 179.. code-block::180 181 // Definition of DXIL Version 1.0 - 1.8182 foreach i = 0...8 in {183 def DXIL1_#i : Version<1, i>;184 }185 186Shader Stage Specification187==========================188 189Various shader stages such as ``compute``, ``pixel``, ``vertex``, etc., are represented190as follows191 192.. code-block::193 194 // Shader stages195 class DXILShaderStage;196 197 def compute : DXILShaderStage;198 def pixel : DXILShaderStage;199 def vertex : DXILShaderStage;200 ...201 202Shader Attribute Specification203==============================204 205Various operation memory access and boolean attributes such as ``ReadNone``,206``IsWave`` etc., are represented as follows207 208.. code-block::209 210 class DXILAttribute;211 212 def ReadOnly : DXILOpAttributes;213 def ReadNone : DXILOpAttributes;214 def IsWave : DXILOpAttributes;215 ...216 217Versioned Property Specification218================================219 220DXIL Operation properties such as valid overload types, shader stages and221attributes are predicated on DXIL version. These are represented as list of222versioned properties.223 224Overload Type Specification225---------------------------226 227``overloads`` field of ``class DXILOp`` is used to represent valid operation228overloads predicated on DXIL version as list of records of the following class229 230.. code-block::231 232 class Overloads<Version minver, list<DXILOpParamType> ols> {233 Version dxil_version = minver;234 list<DXILOpParamType> overload_types = ols;235 }236 237Following is an example specification of valid overload types for ``DXIL1_0`` and238``DXIL1_2``.239 240.. code-block::241 242 overloads = [243 Overloads<DXIL1_0, [halfTy, floatTy]>,244 Overloads<DXIL1_2, [halfTy, floatTy, doubleTy]>245 ];246 247An empty list signifies that the operation supports no overload types.248 249 250Stages Specification251--------------------252 253``stages`` field of ``class DXILOp`` is used to represent valid operation254stages predicated on DXIL version as list of records of the following class255 256.. code-block::257 258 class Stages<Version minver, list<DXILShaderStage> sts> {259 Version dxil_version = minver;260 list<DXILShaderStage> shader_stages = sts;261 }262 263Following is an example specification of valid stages for ``DXIL1_0``,264``DXIL1_2``, ``DXIL1_4`` and ``DXIL1_6``.265 266.. code-block::267 268 stages = [269 Stages<DXIL1_0, [compute, pixel]>,270 Stages<DXIL1_2, [compute, pixel, mesh]>,271 Stages<DXIL1_4, [all_stages]>,272 Stages<DXIL1_6, [removed]>273 ];274 275The following two pseudo stage records in addition to standard shader stages276are defined.277 2781. ``all_stages`` signifies that the operation is valid for all stages in the279 specified DXIL version and later.2802. ``removed`` signifies removal of support for the operation in the specified281 DXIL version and later.282 283A non-empty list of supported stages is required to be specified. If an operation284is supported in all DXIL versions and all stages it is required to be specified as285 286.. code-block::287 288 stages = [Stages<DXIL1_0, [all_stages]>];289 290 291Attribute Specification292-----------------------293 294``attributes`` field of ``class DXILOp`` is used to represent valid operation295attributes predicated on DXIL version as list of records of the following class296 297.. code-block::298 299 class Attributes<MinVersion minver, list<DXILAttribute> attrs> {300 MinVersion dxil_version = ver;301 list<DXILAttribute> attributes = attrs;302 }303 304Following is an example specification of valid attributes for ``DXIL1_0``.305 306.. code-block::307 308 attributes = [Attributes<DXIL1_0, [ReadNone]];309 310A null list of ``attributes`` signifies no operation attributes.311 312Interpretation of Multiple Versioned Properties313-----------------------------------------------314 315Each of the versioned properties states that the specified overload type, stage or316attribute records are valid for the predicated DXIL version. Only317the properties corresponding to latest minimal DXIL version are applicable.318Note as in the above example, any overload types, stages or attributes,319that remain valid in a later DXIL version need to be specified in full.320For example, consider the following specification of valid overload types:321 322.. code-block::323 324 overloads = [325 Overloads<DXIL1_0, [halfTy, floatTy]>,326 Overloads<DXIL1_2, [halfTy, floatTy, doubleTy]>327 ];328 329It specifies that the overload types ``halfTy`` and ``floatTy`` are valid for DXIL330version 1.0 and later. It also specifies that ``doubleTy`` is additionally supported331in DXIL version 1.2 and later.332 333This provides the flexibility to specify properties independent of other334versioned specifications in the list.335 336 337DXIL Operation Specification Examples338=====================================339 340Following examples illustrate the specification of some of the DXIL Ops.341 342``Sin`` operation - an operation valid in all DXIL versions and all stages343and has valid overload types predicated on DXIL version.344 345.. code-block::346 347 def Sin : DXILOp<13, unary> {348 let Doc = "Returns sine(theta) for theta in radians.";349 let LLVMIntrinsic = int_sin;350 let result = overloadTy;351 let arguments = [overloadTy];352 let overloads = [Overloads<DXIL1_0, [halfTy, floatTy]>];353 let stages = [Stages<DXIL1_0, [all_stages]>];354 let attributes = [Attributes<DXIL1_0, [ReadNone]>];355 }356 357``FlattenedThreadIdInGroup`` - an operation with no arguments, no358overload types, and valid stages and attributes predicated by DXIL Version.359 360.. code-block::361 362 def FlattenedThreadIdInGroup : DXILOp<96, flattenedThreadIdInGroup> {363 let Doc = "Provides a flattened index for a given thread within a given "364 "group (SV_GroupIndex)";365 let LLVMIntrinsic = int_dx_flattened_thread_id_in_group;366 let result = i32Ty;367 let stages = [Stages<DXIL1_0, [compute, mesh, amplification, node]>];368 let attributes = [Attributes<DXIL1_0, [ReadNone]>];369 }370 371``RawBufferStore`` - an operation with ``void`` return type, valid overload types372predicated by DXIL Version and valid in all DXIL versions and stages.373 374.. code-block::375 376 def RawBufferStore : DXILOp<140, rawBufferStore> {377 let Doc = "Writes to a RWByteAddressBuffer or RWStructuredBuffer.";378 let result = voidTy;379 let arguments = [dxil_resource_ty, i32Ty, i32Ty, overloadTy,380 overloadTy, overloadTy, overloadTy, i8Ty, i32Ty];381 let overloads = [382 Overloads<DXIL1_2, [halfTy, floatTy, i16Ty, i32Ty]>,383 Overloads<DXIL1_3>,[halfTy, floatTy, doubleTy,384 i16Ty, i32Ty, i64Ty]>385 ];386 let stages = [Stages<DXIL1_2, all_stages>];387 let attributes = [Attributes<DXIL1_0, [ReadOnly]>];388 }389 390``DerivCoarseX`` - an operation with no overload types and stages predicated391by DXIL Version.392 393.. code-block::394 395 def DerivCoarseX : DXILOp<83, unary> {396 let doc = "Computes the rate of change per stamp in x direction.";397 let LLVMIntrinsic = int_dx_ddx;398 let result = overloadTy;399 let arguments = [overloadTy];400 let stages = [401 Stages<DXIL1_0, [library, pixel]>,402 Stages<DXIL1_6, [library, pixel, amplification, compute, mesh]>403 ];404 let attributes = [Attributes<DXIL1_0, [ReadNone]>];405 }406 407``CreateHandle`` - an operation with no overload types, no associated ``LLVMIntrinsic``408and stages predicated by DXIL Version.409 410.. code-block::411 412 def CreateHandle : DXILOp<57, createHandle> {413 let doc = "Creates the handle to a resource";414 let result = i32Ty;415 let arguments = [i8Ty, i32Ty, i32Ty, i1Ty];416 let stages = [417 Stages<DXIL1_0, [all_stages]>,418 Stages<DXIL1_6, [removed]419 ];420 let attributes = [Attributes<DXIL1_0, [ReadOnly]>];421 }422 423``Sample`` - an operation with valid overload types, stages and attributes424predicated by DXIL version.425 426.. code-block::427 428 def Sample : DXILOp<60, sample> {429 let Doc = "Samples a texture";430 let LLVMIntrinsic = int_dx_sample;431 let result = resRetF32Ty;432 let arguments = [handleTy, handleTy, floatTy, floatTy, floatTy, floatTy,433 i32Ty, i32Ty, i32Ty, floatTy];434 let overloads = [Overloads<DXIL1_0, [halfTy, floatTy, i16Ty, i32Ty]>];435 let stages = [436 Stages<DXIL1_0, [library, pixel]>,437 Stages<DXIL1_6, [library, pixel, amplification, compute, mesh]>438 ];439 let attributes = [Attributes<DXIL1_0, [ReadOnly]>];440 }441 442Summary443=======444 445This note sketches the design of a readable and maintainable TableGen specification of446DXIL Ops in ``DXIL.td`` intended to serve as a single source of reference for TableGen447backends (such as ``DXILEmitter``) that generate C++ representations used in DXIL448backend passes.449