xref: /llvm-project/llvm/docs/DirectX/DXILOpTableGenDesign.rst (revision f357fe371d3f752878abf1fb1d5fb550e2650c8e)
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