[llvm] [DirectX][DXIL] Design document for TableGen Spec of DXIL Operations (PR #85170)

Justin Bogner via llvm-commits llvm-commits at lists.llvm.org
Tue Mar 26 12:01:59 PDT 2024


================
@@ -0,0 +1,207 @@
+==============================================================
+Specification of DXIL Operations using TableGen Representation
+==============================================================
+.. contents::
+   :local:
+
+.. toctree
+   :hidden
+
+Introduction
+============
+
+`DirectXShaderCompiler <https://github.com/microsoft/DirectXShaderCompiler>`_
+encapsulates, among other information, various DXIL Operations in
+`hctdb.py <https://github.com/microsoft/DirectXShaderCompiler/blob/main/utils/hct/hctdb.py>`_.
+DXIL Operations are represented in one of the following `two ways
+<https://github.com/microsoft/DirectXShaderCompiler/blob/130877392c263888ef06bab768856d3dab1f1c9a/docs/DXIL.rst#L1978>`_:
+
+#. Using LLVM instructions
+#. Using LLVM External functions. These are represented in LLVM IR as follows:
+
+  * "Standard" LLVM intrinsics (e.g., ``llvm.sin.*``) and
+  * HLSL intrinsics (defined as LLVM intrinsics in ``llvm/include/llvm/IR/IntrinsicsDirectX.td``, e.g., ``llvm.dx.*``)
+
+  These are  collectively referred to as `LLVM Intrinsics` in this note.
+
+DXIL Ops, as currently represented in ``hctdb.py`` have the following attributes
+
+#. ``name`` - A short, unique name
+#. ``llvm_id`` - ID of LLVM instruction. This is just an arbitrary, yet fixed, number that indicates LLVM's ``CallInst`` for all LLVM intrinsics
+#. ``llvm_name`` - String name of LLVM instruction type
+#. ``is_dxil_op`` - A bool indicating whether this is a call into a built-in DXIL function
+#. ``dxil_op`` - String name of DXIL operation
+#. ``dxil_opid`` - ID of DXIL operation
+#. ``dxil_class`` - String name of the opcode class
+#. ``category`` - String classification for this instruction
+#. ``doc`` - String documentation description of this instruction
+#. ``remarks`` - String long-form remarks on this instruction
+#. ``ops`` - List of operands that this instruction takes
+#. ``is_allowed`` - Bool indicating whether this instruction is allowed in a DXIL program
+#. ``oload_types`` - String denoting overload types if applicable (e.g., "hf", "iwl")
+#. ``fn_attr`` - Attribute shorthand strings: rn=does not access memory,ro=only reads from memory,
+#. ``is_deriv`` - Bool indicating whether this is some kind of derivative
+#. ``is_gradient`` - Bool indicating whether this requires a gradient calculation
+#. ``is_feedback`` - Bool indicating whether this is a sampler feedback op
+#. ``is_wave``  - Bool indicating whether this requires in-wave, cross-lane functionality
+#. ``requires_uniform_inputs``  - Bool indicating whether this operation requires that all of its inputs are uniform across the wave
+#. ``is_barrier``  - Bool indicating whether this is a barrier operation
+#. ``shader_stages`` - shader stages to which this applies, empty for all.
+#. ``shader_model`` - minimum shader model required (e.g., 6, 0)
+#. ``inst_helper_prefix`` - None
+#. ``fully_qualified_name_prefix`` - Constant string ``"hlsl::OP::OpCode"``
+#. ``is_dxil_op`` - Bool that evaluates (dxil_op != "") indicating whether this is a DXIL operation
+#. ``is_reserved`` - Bool that evaluates (dxil_class == "Reserved")
+#. ``shader_model_translated`` - minimum shader model required with translation by linker
+#. ``props`` - extra properties
+
+Motivation
+==========
+
+``DXILLowering`` pass needs to lower the LLVM intrinsics. TableGen file -
+``llvm/lib/Target/DirectX/DXIL.td`` - is used to specify the properties of DXIL
+Ops including the mapping of each of them to LLVM intrinsics they correspond to, if any.
+``utils/hct/hctdb.py`` serves this purpose  in ``DirectXShaderCompier`` repo.
+Anologously, ``DXIL.td`` is planned to be the single source of reference
+for the properties and LLVM intrinsic mapping of DXIL Ops for DXIL backend
+implemetation in ``llvm-project`` repo. It needs to have a rich representation
+abilities that TableGen backends (such as ``DXILEmitter``) can rely on. Additionally,
+the DXIL Op specification should be easy to read and comprehend.
+
+Design
+======
+
+Distilling the essential attributes of DXIL Op from the above (as a start), following
+attributes form the core of its specification.
+
+#. ``dxil_opid`` or ``OpCode``
+#. ``dxil_class`` or ``OpClass`` - this string is an integral part of the DXIL Op function name and is constructed in the format ``dx.op.<class-name>.<overload-type>``. The DXIL validator checks for any deviation from this for each of the DXIL Op call.
+#. ``ops`` - list of operands encapsulating the index and valid (fixed or overload) types
+#. ``oload_types`` - Valid overload types of the DXIL op
+
+Each of the LLVM intrinsics maps to an external function represented by a call to an
+external function of the form ``dx.op.<class-name>.<overload-type>`` as noted above.
+
+Following is a basic TableGen class structure to encapsulate the mapping of LLVM Intrinsics to DXIL Ops.
+
+.. code-block::
+
+    // Abstraction of DXIL Operation to LLVM Intrinsic mapping
+    class DXILOpMappingBase {
+      int OpCode = 0;                      // Opcode of DXIL Operation
+      DXILOpClass OpClass = UnknownOpClass;// Class of DXIL Operation.
+      Intrinsic LLVMIntrinsic = ?;         // LLVM Intrinsic DXIL Operation maps to
+      string Doc = "";                     // A short description of the operation
+      list<LLVMType> OpTypes = ?;          // Valid types of DXIL Operation in the
+                                           // format [returnTy, param1ty, ...]
+    }
+
+Various options considered to represent this mapping - keeping the goals of rich
+representation and readability stated above - are discussed in the remainder
+of the note. The basic difference between these options is the way return and
+parameter types are represented for DXIL Ops with valid overload types.
+Valid overload types for several DXIL Ops would be over-specified using LLVM's
+``llvm_any*_ty`` types. For example, ``half`` and ``float`` are only valid for
+DXIL ``Sin`` and would be overspecified using ``llvm_anyfloat_ty``. The options
+listed below address the need to model such overload types specific types
+precisely for correct code generation. They each provide specifications with
+varying levels in (a) ease of readablility and maintainability and
+(b) of compactness / richness.
+
+Option 1 : Specify ``OpType`` as a list of valid fixed types.
+-------------------------------------------------------------
+
+``OpTypes`` for ``Sin`` may be specified as
+``[[llvm_i16, llvm_i32], [llvm_i16, llvm_i32]]``. Repeating such lists for each
+of the DXIL Ops - not all of which are unary - reduces readability and increases
+the proclivity for errors in specification and maintenance. Even if one can
+consider usage of TableGen definitions to create shorthand concrete record
+defs for these, above stated problems are barely mitigated.
+
+Option 2 : Specify a function to validate accepted overload types
+-----------------------------------------------------------------
+
+Specify a validation function to verify/generate the accepted set of overload
+types for DXIL Ops as a field of ``class DXILOpMappingBase``. This function is
+expected to be invoked by the TableGen backends to generate relevant ``*.inc``
+files with accurate content. Such a specification can provide relief from the
+need to specify and maintain long lists of OpTypes. However, having such set
+of functions fits rather awkwardly with the TableGen API usage of being able
+to directly work with the content of a record. Further, these validation
+functions add to the maintenace overlead while not not necessarily making
+the specification more readable.
----------------
bogner wrote:

Typos: `s/overlead/overhead/` and `s/not not/not/`

https://github.com/llvm/llvm-project/pull/85170


More information about the llvm-commits mailing list