1============================================================== 2Specification of DXIL Operations using TableGen Representation 3============================================================== 4.. contents:: 5 :local: 6 7.. toctree 8 :hidden 9 10Introduction 11============ 12 13`DirectXShaderCompiler <https://github.com/microsoft/DirectXShaderCompiler>`_ 14encapsulates, among other information, various DXIL Operations in 15`hctdb.py <https://github.com/microsoft/DirectXShaderCompiler/blob/main/utils/hct/hctdb.py>`_. 16DXIL Operations are represented in one of the following `two ways 17<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.*``) and 23 * 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 name 28as used in ``hctdb.py``. A DXIL Op is represented by a set of associated properties. These 29are 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 passes 33 34 1. Name of operation (``dxil_op``) 35 2. A string that documents the operation (``doc``) - This is not strictly necessary but is included 36 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 in 41 the format ``dx.op.<class-name>.<overload-type>``. Each DXIL Op call target function name 42 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 it 50 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 58Motivation 59========== 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 Operations 65by specifying their properties listed above. ``DXIL.td`` is designed to be the single source 66of reference of DXIL Operations primarily for the implementation of passes in DXIL backend in 67``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 that 70TableGen backends (such as ``DXILEmitter``) can rely on. Additionally, the DXIL Op specification 71should 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 Specification 77============================ 78 79The DXIL Operation is represented using the TableGen class ``DXILOp``. The DXIL operation 80properties 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 records 83 signifies operation name. 842. A documentation string for the operation. 853. The LLVM Intrinsic that maps to the operation is represented as ``Intrinsic`` defined in 86 `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 follows 89 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 types 98 like ``int32Ty``, DXIL types like ``dx.types.Handle``, and a special 99 ``overloadTy`` which can be any type allowed by ``Overloads``, described 100 below. 1017. Operation return type is represented as a ``DXILOpParamType``, and arguments 102 are represented as a list of the same. An operation with no return value 103 shall specify ``VoidTy`` as its return. 1048. Valid operation overload types predicated on DXIL version are specified as 105 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 of 108 ``Stages`` records. Representation of ``Stages`` class is 109 described in a later section. 11010. Various attributes of the DXIL Operation are represented as a ``list`` of 111 ``Attributes`` class records. Representation of ``Attributes`` 112 class is described in a later section. 113 114Types specific to DXIL 115---------------------- 116 117Type notation used in this document viz., ``<size>Ty`` corresponds to TableGen records for 118LLVM types ``llvm_<size>_ty``. Apart from ``overloadTy`` described above, ``resRetF32Ty`` is 119used to denote resource return type and ``handleTy`` is used to denote handle type. 120 121Specification of DXIL Operation 122================================ 123 124A DXIL Operation is represented by the following TableGen class that encapsulates the various 125TableGen representations of its properties described above. 126 127.. code-block:: 128 129 // Abstraction DXIL Operation 130 class DXILOp<int opcode, DXILOpClass opclass> { 131 // A short description of the operation 132 string Doc = ""; 133 134 // Opcode of DXIL Operation 135 int OpCode = opcode; 136 137 // Class of DXIL Operation. 138 DXILOpClass OpClass = opclass; 139 140 // LLVM Intrinsic DXIL Operation maps to 141 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 version 150 list<Overloads> overloads; 151 152 // List of valid shader stages predicated by DXIL version 153 list<Stages> stages; 154 155 // List of valid attributes predicated by DXIL version 156 list<Attributes> attributes = []; 157 } 158 159Version Specification 160===================== 161 162DXIL version is used to specify various version-dependent operation properties in 163place of Shader Model version. 164 165A ``Version`` class encapsulating ``Major`` and ``Minor`` version number is defined 166as follows: 167 168.. code-block:: 169 170 // Abstract class to represent major and minor version values 171 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.8 182 foreach i = 0...8 in { 183 def DXIL1_#i : Version<1, i>; 184 } 185 186Shader Stage Specification 187========================== 188 189Various shader stages such as ``compute``, ``pixel``, ``vertex``, etc., are represented 190as follows 191 192.. code-block:: 193 194 // Shader stages 195 class DXILShaderStage; 196 197 def compute : DXILShaderStage; 198 def pixel : DXILShaderStage; 199 def vertex : DXILShaderStage; 200 ... 201 202Shader Attribute Specification 203============================== 204 205Various operation memory access and boolean attributes such as ``ReadNone``, 206``IsWave`` etc., are represented as follows 207 208.. code-block:: 209 210 class DXILAttribute; 211 212 def ReadOnly : DXILOpAttributes; 213 def ReadNone : DXILOpAttributes; 214 def IsWave : DXILOpAttributes; 215 ... 216 217Versioned Property Specification 218================================ 219 220DXIL Operation properties such as valid overload types, shader stages and 221attributes are predicated on DXIL version. These are represented as list of 222versioned properties. 223 224Overload Type Specification 225--------------------------- 226 227``overloads`` field of ``class DXILOp`` is used to represent valid operation 228overloads predicated on DXIL version as list of records of the following class 229 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`` and 238``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 Specification 251-------------------- 252 253``stages`` field of ``class DXILOp`` is used to represent valid operation 254stages predicated on DXIL version as list of records of the following class 255 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 stages 276are defined. 277 2781. ``all_stages`` signifies that the operation is valid for all stages in the 279 specified DXIL version and later. 2802. ``removed`` signifies removal of support for the operation in the specified 281 DXIL version and later. 282 283A non-empty list of supported stages is required to be specified. If an operation 284is supported in all DXIL versions and all stages it is required to be specified as 285 286.. code-block:: 287 288 stages = [Stages<DXIL1_0, [all_stages]>]; 289 290 291Attribute Specification 292----------------------- 293 294``attributes`` field of ``class DXILOp`` is used to represent valid operation 295attributes predicated on DXIL version as list of records of the following class 296 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 Properties 313----------------------------------------------- 314 315Each of the versioned properties states that the specified overload type, stage or 316attribute records are valid for the predicated DXIL version. Only 317the 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 DXIL 330version 1.0 and later. It also specifies that ``doubleTy`` is additionally supported 331in DXIL version 1.2 and later. 332 333This provides the flexibility to specify properties independent of other 334versioned specifications in the list. 335 336 337DXIL Operation Specification Examples 338===================================== 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 stages 343and 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, no 358overload 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 types 372predicated 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 predicated 391by 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 attributes 424predicated 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 442Summary 443======= 444 445This note sketches the design of a readable and maintainable TableGen specification of 446DXIL Ops in ``DXIL.td`` intended to serve as a single source of reference for TableGen 447backends (such as ``DXILEmitter``) that generate C++ representations used in DXIL 448backend passes. 449