[LoongArch] Eliminate the redundant sign extension of division (#107971)
[llvm-project.git] / llvm / docs / DirectX / DXILArchitecture.rst
blob32b1e72deae7cdf7367a1429b831ac4b2207fc89
1 ===============================================
2 Architecture and Design of DXIL Support in LLVM
3 ===============================================
5 .. contents::
6    :local:
8 .. toctree::
9    :hidden:
11 Introduction
12 ============
14 LLVM supports reading and writing the `DirectX Intermediate Language.
15 <https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/DXIL.rst>`_,
16 or DXIL. DXIL is essentially LLVM 3.7 era bitcode with some
17 restrictions and various semantically important operations and
18 metadata.
20 LLVM's implementation philosophy for DXIL support is to treat DXIL as
21 merely a representation format as much as possible. When reading DXIL,
22 we should translate everything to generic LLVM constructs when
23 possible. Similarly, we should introduce DXIL-specific constructs as
24 late as possible in the process of lowering to the format.
26 There are three places to look for DXIL related code in LLVM: The
27 `DirectX` backend, for writing DXIL; The `DXILUpgrade` pass, for
28 reading; and in library code that is shared between writing and
29 reading. We'll describe these in reverse order.
31 Common Code for Reading and Writing
32 ===================================
34 There's quite a bit of logic that needs to be shared between reading
35 and writing DXIL in order to avoid code duplication. While we don't
36 have a hard and fast rule about where such code should live, there are
37 generally three sensible places. Simple definitions of enums and
38 values that must stay fixed to match DXIL's ABI can be found in
39 `Support/DXILABI.h`, utilities to translate bidirectionally between
40 DXIL and modern LLVM constructs live in `lib/Transforms/Utils`, and
41 more analyses that are needed to derive or preserve information are
42 implemented as typical `lib/Analysis` passes.
44 The DXILUpgrade Pass
45 ====================
47 Translating DXIL to LLVM IR takes advantage of the fact that DXIL is
48 compatible with LLVM 3.7 bitcode, and that modern LLVM is capable of
49 "upgrading" older bitcode into modern IR. Simply relying on the
50 bitcode upgrade process isn't sufficient though, since that leaves a
51 number of DXIL specific constructs around. Thus, we have the
52 `DXILUpgrade` pass to transform DXIL operations to LLVM operations and
53 smooth over differences in metadata representation. We call this pass
54 "upgrade" to reflect that it follows LLVM's standard bitcode upgrade
55 process and simply finishes the job for DXIL constructs - while
56 "reader" or "lifting" might also be reasonable names, they could be a
57 bit misleading.
59 The `DXILUpgrade` pass itself is fairly lightweight. It mostly relies
60 on the utilities described in "Common Code" above in order to share
61 logic with both the DirectX backend and with Clang's codegen of HLSL
62 support as much as possible.
64 The DirectX Intrinsic Expansion Pass
65 ====================================
66 There are intrinsics that don't map directly to DXIL Ops. In some cases
67 an intrinsic needs to be expanded to a set of LLVM IR instructions. In
68 other cases an intrinsic needs modifications to the arguments or return
69 values of a DXIL Op. The `DXILIntrinsicExpansion` pass handles all 
70 the cases where our intrinsics don't have a one to one mapping. This 
71 pass may also be used when the expansion is specific to DXIL to keep 
72 implementation details out of CodeGen. Finally, there is an expectation 
73 that we maintain vector types through this pass. Therefore, best 
74 practice would be to avoid scalarization in this pass.
77 The DirectX Backend
78 ===================
80 The DirectX backend lowers LLVM IR into DXIL. As we're transforming to
81 an intermediate format rather than a specific ISA, this backend does
82 not follow the instruction selection patterns you might be familiar
83 with from other backends. There are two parts to lowering DXIL - a set
84 of passes that mutate various constructs into a form that matches how
85 DXIL represents those constructs, followed by a limited bitcode
86 "downgrader pass".
88 Before emitting DXIL, the DirectX backend needs to modify the LLVM IR
89 such that external operations, types, and metadata is represented in
90 the way that DXIL expects. For example, `DXILOpLowering` translates
91 intrinsics into `dx.op` calls. These passes are essentially the
92 inverse of the `DXILUpgrade` pass. It's best to do this downgrading
93 process as IR to IR passes when possible, as that means that they can
94 be easily tested with `opt` and `FileCheck` without the need for
95 external tooling.
97 The second part of DXIL emission is more or less an LLVM bitcode
98 downgrader. We need to emit bitcode that matches the LLVM 3.7
99 representation. For this, we have `DXILWriter`, which is an alternate
100 version of LLVM's `BitcodeWriter`. At present, this is able to
101 leverage LLVM's current bitcode libraries to do a lot of the work, but
102 it's possible that at some point in the future it will need to be
103 completely separate as modern LLVM bitcode evolves.
105 DirectX Backend Flow
106 --------------------
108 The code generation flow for DXIL is broken into a series of passes. The passes
109 are grouped into two flows:
111 #. Generating DXIL IR.
112 #. Generating DXIL Binary.
114 The passes to generate DXIL IR follow the flow:
116   DXILOpLowering -> DXILPrepare -> DXILTranslateMetadata
118 Each of these passes has a defined responsibility:
120 #. DXILOpLowering translates LLVM intrinsic calls to dx.op calls.
121 #. DXILPrepare transforms the DXIL IR to be compatible with LLVM 3.7, and
122    inserts bitcasts to allow typed pointers to be inserted.
123 #. DXILTranslateMetadata emits the DXIL Metadata structures.
125 The passes to encode DXIL to binary in the DX Container follow the flow:
127   DXILEmbedder -> DXContainerGlobals -> AsmPrinter
129 Each of these passes have the following defined responsibilities:
131 #. DXILEmbedder runs the DXIL bitcode writer to generate a bitcode stream and
132    embeds the binary data inside a global in the original module.
133 #. DXContainerGlobals generates binary data globals for the other DX Container
134    parts based on computed analysis passes.
135 #. AsmPrinter is the standard LLVM infrastructure for emitting object files.
137 When emitting DXIL into a DX Container file the MC layer is used in a similar
138 way to how the Clang ``-fembed-bitcode`` option operates. The DX Container
139 object writer knows how to construct the headers and structural fields of the
140 container, and reads global variables from the module to fill in the remaining
141 part data.
143 DirectX Container
144 -----------------
146 The DirectX container format is treated in LLVM as an object file format.
147 Reading is implemented between the BinaryFormat and Object libraries, and
148 writing is implemented in the MC layer. Additional testing and inspection
149 support are implemented in the ObjectYAML library and tools.
151 Testing
152 =======
154 A lot of DXIL testing can be done with typical IR to IR tests using
155 `opt` and `FileCheck`, since a lot of the support is implemented in
156 terms of IR level passes as described in the previous sections. You
157 can see examples of this in `llvm/test/CodeGen/DirectX` as well as
158 `llvm/test/Transforms/DXILUpgrade`, and this type of testing should be
159 leveraged as much as possible.
161 However, when it comes to testing the DXIL format itself, IR passes
162 are insufficient for testing. For now, the best option we have
163 available is using the DXC project's tools in order to round trip.
164 These tests are currently found in `test/tools/dxil-dis` and are only
165 available if the `LLVM_INCLUDE_DXIL_TESTS` cmake option is set. Note
166 that we do not currently have the equivalent testing set up for the
167 DXIL reading path.
169 As soon as we are able, we will also want to round trip using the DXIL
170 writing and reading paths in order to ensure self consistency and to
171 get test coverage when `dxil-dis` isn't available.