brintos

brintos / llvm-project-archived public Read only

0
0
Text · 29.9 KiB · db7d4a4 Raw
838 lines · plain
1======================2DXIL Resource Handling3======================4 5.. contents::6   :local:7 8.. toctree::9   :hidden:10 11Introduction12============13 14Resources in DXIL are represented via ``TargetExtType`` in LLVM IR and15eventually lowered by the DirectX backend into metadata in DXIL.16 17In DXC and DXIL, static resources are represented as lists of SRVs (Shader18Resource Views), UAVs (Uniform Access Views), CBVs (Constant Bffer Views), and19Samplers. This metadata consists of a "resource record ID" which uniquely20identifies a resource and type information. As of shader model 6.6, there are21also dynamic resources, which forgo the metadata and are described via22``annotateHandle`` operations in the instruction stream instead.23 24In LLVM we attempt to unify some of the alternative representations that are25present in DXC, with the aim of making handling of resources in the middle end26of the compiler simpler and more consistent.27 28Resource Type Information and Properties29========================================30 31There are a number of properties associated with a resource in DXIL.32 33`Resource ID`34   An arbitrary ID that must be unique per resource type (SRV, UAV, etc).35 36   In LLVM we don't bother representing this, instead opting to generate it at37   DXIL lowering time.38 39`Binding information`40   Information about where the resource comes from. This is either (a) a41   register space, lower bound in that space, and size of the binding, or (b)42   an index into a dynamic resource heap.43 44   In LLVM we represent binding information in the arguments of the45   :ref:`handle creation intrinsics <dxil-resources-handles>`. When generating46   DXIL we transform these calls to metadata, ``dx.op.createHandle``,47   ``dx.op.createHandleFromBinding``, ``dx.op.createHandleFromHeap``, and48   ``dx.op.createHandleForLib`` as needed.49 50`Type information`51   The type of data that's accessible via the resource. For buffers and52   textures this can be a simple type like ``float`` or ``float4``, a struct,53   or raw bytes. For constant buffers this is just a size. For samplers this is54   the kind of sampler.55 56   In LLVM we embed this information as a parameter on the ``target()`` type of57   the resource. See :ref:`dxil-resources-types-of-resource`.58 59`Resource kind information`60   The kind of resource. In HLSL we have things like ``ByteAddressBuffer``,61   ``RWTexture2D``, and ``RasterizerOrderedStructuredBuffer``. These map to a62   set of DXIL kinds like ``RawBuffer`` and ``Texture2D`` with fields for63   certain properties such as ``IsUAV`` and ``IsROV``.64 65   In LLVM we represent this in the ``target()`` type. We omit information66   that's deriveable from the type information, but we do have fields to encode67   ``IsWriteable``, ``IsROV``, and ``SampleCount`` when needed.68 69.. note:: TODO: There are two fields in the DXIL metadata that are not70   represented as part of the target type: ``IsGloballyCoherent`` and71   ``HasCounter``.72 73   Since these are derived from analysis, storing them on the type would mean74   we need to change the type during the compiler pipeline. That just isn't75   practical. It isn't entirely clear to me that we need to serialize this info76   into the IR during the compiler pipeline anyway - we can probably get away77   with an analysis pass that can calculate the information when we need it.78 79   If analysis is insufficient we'll need something akin to ``annotateHandle``80   (but limited to these two properties) or to encode these in the handle81   creation.82 83.. _dxil-resources-types-of-resource:84 85Types of Resource86=================87 88We define a set of ``TargetExtTypes`` that is similar to the HLSL89representations for the various resources, albeit with a few things90parameterized. This is different than DXIL, as simplifying the types to91something like "dx.srv" and "dx.uav" types would mean the operations on these92types would have to be overly generic.93 94Buffers95-------96 97.. code-block:: llvm98 99   target("dx.TypedBuffer", ElementType, IsWriteable, IsROV, IsSigned)100   target("dx.RawBuffer", ElementType, IsWriteable, IsROV)101 102We need two separate buffer types to account for the differences between the10316-byte `bufferLoad`_ / `bufferStore`_ operations that work on DXIL's104TypedBuffers and the `rawBufferLoad`_ / `rawBufferStore`_ operations that are105used for DXIL's RawBuffers and StructuredBuffers. We call the latter106"RawBuffer" to match the naming of the operations, but it can represent both107the Raw and Structured variants.108 109HLSL's Buffer and RWBuffer are represented as a TypedBuffer with an element110type that is a scalar integer or floating point type, or a vector of at most 4111such types. HLSL's ByteAddressBuffer is a RawBuffer with an `i8` element type.112HLSL's StructuredBuffers are RawBuffer with a struct, vector, or scalar type.113 114One unfortunate necessity here is that TypedBuffer needs an extra parameter to115differentiate signed vs unsigned ints. The is because in LLVM IR int types116don't have a sign, so to keep this information we need a side channel.117 118These types are generally used by BufferLoad and BufferStore operations, as119well as atomics.120 121There are a few fields to describe variants of all of these types:122 123.. list-table:: Buffer Fields124   :header-rows: 1125 126   * - Field127     - Description128   * - ElementType129     - Type for a single element, such as ``i8``, ``v4f32``, or a structure130       type.131   * - IsWriteable132     - Whether or not the field is writeable. This distinguishes SRVs (not133       writeable) and UAVs (writeable).134   * - IsROV135     - Whether the UAV is a rasterizer ordered view. Always ``0`` for SRVs.136   * - IsSigned137     - Whether an int element type is signed ("dx.TypedBuffer" only)138 139.. _bufferLoad: https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/DXIL.rst#bufferload140.. _bufferStore: https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/DXIL.rst#bufferstore141.. _rawBufferLoad: https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/DXIL.rst#rawbufferload142.. _rawBufferStore: https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/DXIL.rst#rawbufferstore143 144Resource Operations145===================146 147.. _dxil-resources-handles:148 149Resource Handles150----------------151 152We provide a few different ways to instantiate resources in the IR via the153``llvm.dx.handle.*`` intrinsics. These intrinsics are overloaded on return154type, returning an appropriate handle for the resource, and represent binding155information in the arguments to the intrinsic.156 157The three operations we need are ``llvm.dx.resource.handlefrombinding``,158``llvm.dx.handle.fromHeap``, and ``llvm.dx.handle.fromPointer``. These are159rougly equivalent to the DXIL operations ``dx.op.createHandleFromBinding``,160``dx.op.createHandleFromHeap``, and ``dx.op.createHandleForLib``, but they fold161the subsequent ``dx.op.annotateHandle`` operation in. Note that we don't have162an analogue for `dx.op.createHandle`_, since ``dx.op.createHandleFromBinding``163subsumes it.164 165We diverge from DXIL and index from the beginning of the binding rather than166indexing from the beginning of the binding space. This matches the semantics167more clearly and avoids a non-obvious invariant in what constitutes valid168arguments.169 170.. _dx.op.createHandle: https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/DXIL.rst#resource-handles171 172.. list-table:: ``@llvm.dx.resource.handlefrombinding``173   :header-rows: 1174 175   * - Argument176     -177     - Type178     - Description179   * - Return value180     -181     - A ``target()`` type182     - A handle which can be operated on183   * - ``%reg_space``184     - 1185     - ``i32``186     - Register space ID in the root signature for this resource.187   * - ``%lower_bound``188     - 2189     - ``i32``190     - Lower bound of the binding in its register space.191   * - ``%range_size``192     - 3193     - ``i32``194     - Range size of the binding.195   * - ``%index``196     - 4197     - ``i32``198     - Index from the beginning of the binding.199   * - ``%non-uniform``200     - 5201     - i1202     - Must be ``true`` if the resource index may be non-uniform.203 204.. note:: TODO: Can we drop the uniformity bit? I suspect we can derive it from205          uniformity analysis...206 207Examples:208 209.. code-block:: llvm210 211   ; RWBuffer<float4> Buf : register(u5, space3)212   %buf = call target("dx.TypedBuffer", <4 x float>, 1, 0, 0)213        @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0(214            i32 3, i32 5, i32 1, i32 0, i1 false)215 216   ; RWBuffer<int> Buf : register(u7, space2)217   %buf = call target("dx.TypedBuffer", i32, 1, 0, 1)218        @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_i32_1_0t(219            i32 2, i32 7, i32 1, i32 0, i1 false)220 221   ; Buffer<uint4> Buf[24] : register(t3, space5)222   %buf = call target("dx.TypedBuffer", <4 x i32>, 0, 0, 0)223        @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_i32_0_0t(224            i32 2, i32 7, i32 24, i32 0, i1 false)225 226   ; struct S { float4 a; uint4 b; };227   ; StructuredBuffer<S> Buf : register(t2, space4)228   %buf = call target("dx.RawBuffer", {<4 x float>, <4 x i32>}, 0, 0)229       @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_sl_v4f32v4i32s_0_0t(230           i32 4, i32 2, i32 1, i32 0, i1 false)231 232   ; ByteAddressBuffer Buf : register(t8, space1)233   %buf = call target("dx.RawBuffer", i8, 0, 0)234       @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i8_0_0t(235           i32 1, i32 8, i32 1, i32 0, i1 false)236 237   ; RWBuffer<float4> Global[3] : register(u6, space5)238   ; RWBuffer<float4> Buf = Global[2];239   %buf = call target("dx.TypedBuffer", <4 x float>, 1, 0, 0)240       @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0(241           i32 5, i32 6, i32 3, i32 2, i1 false)242 243.. list-table:: ``@llvm.dx.handle.fromHeap``244   :header-rows: 1245 246   * - Argument247     -248     - Type249     - Description250   * - Return value251     -252     - A ``target()`` type253     - A handle which can be operated on254   * - ``%index``255     - 0256     - ``i32``257     - Index of the resource to access.258   * - ``%non-uniform``259     - 1260     - i1261     - Must be ``true`` if the resource index may be non-uniform.262 263Examples:264 265.. code-block:: llvm266 267   ; RWStructuredBuffer<float4> Buf = ResourceDescriptorHeap[2];268   declare269     target("dx.RawBuffer", <4 x float>, 1, 0)270     @llvm.dx.handle.fromHeap.tdx.RawBuffer_v4f32_1_0(271         i32 %index, i1 %non_uniform)272   ; ...273   %buf = call target("dx.RawBuffer", <4 x f32>, 1, 0)274               @llvm.dx.handle.fromHeap.tdx.RawBuffer_v4f32_1_0(275                   i32 2, i1 false)276 277Accessing Resources as Memory278-----------------------------279 280*relevant types: Buffers, Textures, and CBuffers*281 282Loading and storing from resources is generally represented in LLVM using283operations on memory that is only accessible via a handle object. Given a284handle, `llvm.dx.resource.getpointer` gives a pointer that can be used to read285and (depending on type) write to the resource.286 287Accesses using `llvm.dx.resource.getpointer` are replaced with direct load and288store operations in the `DXILResourceAccess` pass. These direct loads and289stores are described later in this document.290 291.. note:: Currently the pointers returned by `dx.resource.getpointer` are in292          the default address space, but that will likely change in the future.293 294.. list-table:: ``@llvm.dx.resource.getpointer``295   :header-rows: 1296 297   * - Argument298     -299     - Type300     - Description301   * - Return value302     -303     - Pointer304     - A pointer to an object in the buffer305   * - ``%resource``306     - 0307     - Any buffer, texture, or cbuffer type308     - The resource to access309   * - ``%index``310     - 1311     - ``i32``312     - Index into the resource313 314Examples:315 316.. code-block:: llvm317 318   %ptr = call ptr @llvm.dx.resource.getpointer.p0.tdx.TypedBuffer_v4f32_0_0_0t(319       target("dx.TypedBuffer", <4 x float>, 0, 0, 0) %buffer, i32 %index)320 321Loads, Samples, and Gathers322---------------------------323 324*relevant types: Buffers and Textures*325 326All load, sample, and gather operations in DXIL return a `ResRet`_ type. These327types are structs containing 4 elements of some basic type, and a 5th element328that is used by the `CheckAccessFullyMapped`_ operation. Some of these329operations, like `RawBufferLoad`_ include a mask and/or alignment that tell us330some information about how to interpret those four values.331 332In the LLVM IR representations of these operations we instead return scalars or333vectors, but we keep the requirement that we only return up to 4 elements of a334basic type. This avoids some unnecessary casting and structure manipulation in335the intermediate format while also keeping lowering to DXIL straightforward.336 337LLVM intrinsics that map to operations returning `ResRet` return an anonymous338struct with element-0 being the scalar or vector type, and element-1 being the339``i1`` result of a ``CheckAccessFullyMapped`` call. We don't have a separate340call to ``CheckAccessFullyMapped`` at all, since that's the only operation that341can possibly be done on this value. In practice this may mean we insert a DXIL342operation for the check when this was missing in the HLSL source, but this343actually matches DXC's behaviour in practice.344 345For TypedBuffer and Texture, we map directly from the contained type of the346resource to the return value of the intrinsic. Since these resources are347constrained to contain only scalars and vectors of up to 4 elements, the348lowering to DXIL ops is generally straightforward. The one exception we have349here is that `double` types in the elements are special - these are allowed in350the LLVM intrinsics, but are lowered to pairs of `i32` followed by351``MakeDouble`` operations for DXIL.352 353.. _ResRet: https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/DXIL.rst#resource-operation-return-types354.. _CBufRet: https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/DXIL.rst#cbufferloadlegacy355.. _CheckAccessFullyMapped: https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/checkaccessfullymapped356.. _RawBufferLoad: https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/DXIL.rst#rawbufferload357 358.. list-table:: ``@llvm.dx.resource.load.typedbuffer``359   :header-rows: 1360 361   * - Argument362     -363     - Type364     - Description365   * - Return value366     -367     - A structure of the contained type and the check bit368     - The data loaded from the buffer and the check bit369   * - ``%buffer``370     - 0371     - ``target(dx.TypedBuffer, ...)``372     - The buffer to load from373   * - ``%index``374     - 1375     - ``i32``376     - Index into the buffer377 378Examples:379 380.. code-block:: llvm381 382   %ret = call {<4 x float>, i1}383       @llvm.dx.resource.load.typedbuffer.v4f32.tdx.TypedBuffer_v4f32_0_0_0t(384           target("dx.TypedBuffer", <4 x float>, 0, 0, 0) %buffer, i32 %index)385   %ret = call {float, i1}386       @llvm.dx.resource.load.typedbuffer.f32.tdx.TypedBuffer_f32_0_0_0t(387           target("dx.TypedBuffer", float, 0, 0, 0) %buffer, i32 %index)388   %ret = call {<4 x i32>, i1}389       @llvm.dx.resource.load.typedbuffer.v4i32.tdx.TypedBuffer_v4i32_0_0_0t(390           target("dx.TypedBuffer", <4 x i32>, 0, 0, 0) %buffer, i32 %index)391   %ret = call {<4 x half>, i1}392       @llvm.dx.resource.load.typedbuffer.v4f16.tdx.TypedBuffer_v4f16_0_0_0t(393           target("dx.TypedBuffer", <4 x half>, 0, 0, 0) %buffer, i32 %index)394   %ret = call {<2 x double>, i1}395       @llvm.dx.resource.load.typedbuffer.v2f64.tdx.TypedBuffer_v2f64_0_0t(396           target("dx.TypedBuffer", <2 x double>, 0, 0, 0) %buffer, i32 %index)397 398For RawBuffer, an HLSL load operation may return an arbitrarily sized result,399but we still constrain the LLVM intrinsic to return only up to 4 elements of a400basic type. This means that larger loads are represented as a series of loads,401which matches DXIL. Unlike in the `RawBufferLoad`_ operation, we do not need402arguments for the mask/type size and alignment, since we can calculate these403from the return type of the load during lowering.404 405.. _RawBufferLoad: https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/DXIL.rst#rawbufferload406 407.. list-table:: ``@llvm.dx.resource.load.rawbuffer``408   :header-rows: 1409 410   * - Argument411     -412     - Type413     - Description414   * - Return value415     -416     - A structure of a scalar or vector and the check bit417     - The data loaded from the buffer and the check bit418   * - ``%buffer``419     - 0420     - ``target(dx.RawBuffer, ...)``421     - The buffer to load from422   * - ``%index``423     - 1424     - ``i32``425     - Index into the buffer426   * - ``%offset``427     - 2428     - ``i32``429     - Offset into the structure at the given index430 431Examples:432 433.. code-block:: llvm434 435   ; float436   %ret = call {float, i1}437       @llvm.dx.resource.load.rawbuffer.f32.tdx.RawBuffer_f32_0_0_0t(438           target("dx.RawBuffer", float, 0, 0, 0) %buffer,439           i32 %index,440           i32 0)441   %ret = call {float, i1}442       @llvm.dx.resource.load.rawbuffer.f32.tdx.RawBuffer_i8_0_0_0t(443           target("dx.RawBuffer", i8, 0, 0, 0) %buffer,444           i32 %byte_offset,445           i32 0)446 447   ; float4448   %ret = call {<4 x float>, i1}449       @llvm.dx.resource.load.rawbuffer.v4f32.tdx.RawBuffer_v4f32_0_0_0t(450           target("dx.RawBuffer", float, 0, 0, 0) %buffer,451           i32 %index,452           i32 0)453   %ret = call {float, i1}454       @llvm.dx.resource.load.rawbuffer.v4f32.tdx.RawBuffer_i8_0_0_0t(455           target("dx.RawBuffer", i8, 0, 0, 0) %buffer,456           i32 %byte_offset,457           i32 0)458 459   ; struct S0 { float4 f; int4 i; };460   %ret = call {<4 x float>, i1}461       @llvm.dx.resource.load.rawbuffer.v4f32.tdx.RawBuffer_sl_v4f32v4i32s_0_0t(462           target("dx.RawBuffer", {<4 x float>, <4 x i32>}, 0, 0, 0) %buffer,463           i32 %index,464           i32 0)465   %ret = call {<4 x i32>, i1}466       @llvm.dx.resource.load.rawbuffer.v4i32.tdx.RawBuffer_sl_v4f32v4i32s_0_0t(467           target("dx.RawBuffer", {<4 x float>, <4 x i32>}, 0, 0, 0) %buffer,468           i32 %index,469           i32 1)470 471   ; struct Q { float4 f; int3 i; }472   ; struct R { int z; S x; }473   %ret = call {i32, i1}474       @llvm.dx.resource.load.rawbuffer.i32(475           target("dx.RawBuffer", {i32, {<4 x float>, <3 x i32>}}, 0, 0, 0)476               %buffer, i32 %index, i32 0)477   %ret = call {<4 x float>, i1}478       @llvm.dx.resource.load.rawbuffer.i32(479           target("dx.RawBuffer", {i32, {<4 x float>, <3 x i32>}}, 0, 0, 0)480               %buffer, i32 %index, i32 4)481   %ret = call {<3 x i32>, i1}482       @llvm.dx.resource.load.rawbuffer.i32(483           target("dx.RawBuffer", {i32, {<4 x float>, <3 x i32>}}, 0, 0, 0)484               %buffer, i32 %index, i32 20)485 486   ; byteaddressbuf.Load<int64_t4>487   %ret = call {<4 x i64>, i1}488       @llvm.dx.resource.load.rawbuffer.v4i64.tdx.RawBuffer_i8_0_0t(489           target("dx.RawBuffer", i8, 0, 0, 0) %buffer,490           i32 %byte_offset,491           i32 0)492 493Stores494------495 496*relevant types: Textures and Buffer*497 498The `TextureStore`_, `BufferStore`_, and `RawBufferStore`_ DXIL operations499write four components to a texture or a buffer. These include a mask argument500that is used when fewer than 4 components are written, but notably this only501takes on the contiguous x, xy, xyz, and xyzw values.502 503We define the LLVM store intrinsics to accept vectors when storing multiple504components rather than using `undef` and a mask, but otherwise match the DXIL505ops fairly closely.506 507.. _TextureStore: https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/DXIL.rst#texturestore508.. _BufferStore: https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/DXIL.rst#bufferstore509.. _RawBufferStore: https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/DXIL.rst#rawbufferstore510 511For TypedBuffer, we only need one coordinate, and we must always write a vector512since partial writes aren't possible. Similarly to the load operations513described above, we handle 64-bit types specially and only handle 2-element514vectors rather than 4.515 516Examples:517 518.. list-table:: ``@llvm.dx.resource.store.typedbuffer``519   :header-rows: 1520 521   * - Argument522     -523     - Type524     - Description525   * - Return value526     -527     - ``void``528     -529   * - ``%buffer``530     - 0531     - ``target(dx.TypedBuffer, ...)``532     - The buffer to store into533   * - ``%index``534     - 1535     - ``i32``536     - Index into the buffer537   * - ``%data``538     - 2539     - A 4- or 2-element vector of the type of the buffer540     - The data to store541 542Examples:543 544.. code-block:: llvm545 546   call void @llvm.dx.resource.store.typedbuffer.tdx.Buffer_v4f32_1_0_0t(547       target("dx.TypedBuffer", f32, 1, 0) %buf, i32 %index, <4 x f32> %data)548   call void @llvm.dx.resource.store.typedbuffer.tdx.Buffer_v4f16_1_0_0t(549       target("dx.TypedBuffer", f16, 1, 0) %buf, i32 %index, <4 x f16> %data)550   call void @llvm.dx.resource.store.typedbuffer.tdx.Buffer_v2f64_1_0_0t(551       target("dx.TypedBuffer", f64, 1, 0) %buf, i32 %index, <2 x f64> %data)552 553For RawBuffer, we need two indices and we accept scalars and vectors of 4 or554fewer elements. Note that we do allow vectors of 4 64-bit elements here.555 556Examples:557 558.. list-table:: ``@llvm.dx.resource.store.rawbuffer``559   :header-rows: 1560 561   * - Argument562     -563     - Type564     - Description565   * - Return value566     -567     - ``void``568     -569   * - ``%buffer``570     - 0571     - ``target(dx.RawBuffer, ...)``572     - The buffer to store into573   * - ``%index``574     - 1575     - ``i32``576     - Index into the buffer577   * - ``%offset``578     - 2579     - ``i32``580     - Byte offset into structured buffer elements581   * - ``%data``582     - 3583     - Scalar or vector584     - The data to store585 586Examples:587 588.. code-block:: llvm589 590   ; float591   call void @llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_f32_1_0_0t.f32(592       target("dx.RawBuffer", float, 1, 0, 0) %buffer,593       i32 %index, i32 0, float %data)594   call void @llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_i8_1_0_0t.f32(595       target("dx.RawBuffer", i8, 1, 0, 0) %buffer,596       i32 %index, i32 0, float %data)597 598   ; float4599   call void @llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_v4f32_1_0_0t.v4f32(600       target("dx.RawBuffer", <4 x float>, 1, 0, 0) %buffer,601       i32 %index, i32 0, <4 x float> %data)602   call void @llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_i8_1_0_0t.v4f32(603       target("dx.RawBuffer", i8, 1, 0, 0) %buffer,604       i32 %index, i32 0, <4 x float> %data)605 606   ; struct S0 { float4 f; int4 i; }607   call void @llvm.dx.resource.store.rawbuffer.v4f32(608       target("dx.RawBuffer", { <4 x float>, <4 x i32> }, 1, 0, 0) %buffer,609       i32 %index, i32 0, <4 x float> %data0)610   call void @llvm.dx.resource.store.rawbuffer.v4i32(611       target("dx.RawBuffer", { <4 x float>, <4 x i32> }, 1, 0, 0) %buffer,612       i32 %index, i32 16, <4 x i32> %data1)613 614   ; struct Q { float4 f; int3 i; }615   ; struct R { int z; S x; }616   call void @llvm.dx.resource.store.rawbuffer.i32(617       target("dx.RawBuffer", {i32, {<4 x float>, <3 x half>}}, 1, 0, 0)618           %buffer,619       i32 %index, i32 0, i32 %data0)620   call void @llvm.dx.resource.store.rawbuffer.v4f32(621       target("dx.RawBuffer", {i32, {<4 x float>, <3 x half>}}, 1, 0, 0)622           %buffer,623       i32 %index, i32 4, <4 x float> %data1)624   call void @llvm.dx.resource.store.rawbuffer.v3f16(625       target("dx.RawBuffer", {i32, {<4 x float>, <3 x half>}}, 1, 0, 0)626           %buffer,627       i32 %index, i32 20, <3 x half> %data2)628 629   ; byteaddressbuf.Store<int64_t4>630   call void @llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_i8_1_0_0t.v4f64(631       target("dx.RawBuffer", i8, 1, 0, 0) %buffer,632       i32 %index, i32 0, <4 x double> %data)633 634Constant Buffer Loads635---------------------636 637*relevant types: CBuffers*638 639The `CBufferLoadLegacy`_ operation, which despite the name is the only640supported way to load from a cbuffer in any DXIL version, loads a single "row"641of a cbuffer, which is exactly 16 bytes. The return value of the operation is642represented by a `CBufRet`_ type, which has variants for 2 64-bit values, 464332-bit values, and 8 16-bit values.644 645We represent these in LLVM IR with 3 separate operations, which return a6462-element, 4-element, or 8-element struct respectively.647 648.. _CBufferLoadLegacy: https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/DXIL.rst#cbufferLoadLegacy649.. _CBufRet: https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/DXIL.rst#cbufferloadlegacy650 651.. list-table:: ``@llvm.dx.resource.load.cbufferrow.4``652   :header-rows: 1653 654   * - Argument655     -656     - Type657     - Description658   * - Return value659     -660     - A struct of 4 32-bit values661     - A single row of a cbuffer, interpreted as 4 32-bit values662   * - ``%buffer``663     - 0664     - ``target(dx.CBuffer, ...)``665     - The buffer to load from666   * - ``%index``667     - 1668     - ``i32``669     - Index into the buffer670 671Examples:672 673.. code-block:: llvm674 675   %ret = call {float, float, float, float}676       @llvm.dx.resource.load.cbufferrow.4(677           target("dx.CBuffer", target("dx.Layout", {float}, 4, 0)) %buffer,678           i32 %index)679   %ret = call {i32, i32, i32, i32}680       @llvm.dx.resource.load.cbufferrow.4(681           target("dx.CBuffer", target("dx.Layout", {i32}, 4, 0)) %buffer,682           i32 %index)683 684.. list-table:: ``@llvm.dx.resource.load.cbufferrow.2``685   :header-rows: 1686 687   * - Argument688     -689     - Type690     - Description691   * - Return value692     -693     - A struct of 2 64-bit values694     - A single row of a cbuffer, interpreted as 2 64-bit values695   * - ``%buffer``696     - 0697     - ``target(dx.CBuffer, ...)``698     - The buffer to load from699   * - ``%index``700     - 1701     - ``i32``702     - Index into the buffer703 704Examples:705 706.. code-block:: llvm707 708   %ret = call {double, double}709       @llvm.dx.resource.load.cbufferrow.2(710           target("dx.CBuffer", target("dx.Layout", {double}, 8, 0)) %buffer,711           i32 %index)712   %ret = call {i64, i64}713       @llvm.dx.resource.load.cbufferrow.2(714           target("dx.CBuffer", target("dx.Layout", {i64}, 4, 0)) %buffer,715           i32 %index)716 717.. list-table:: ``@llvm.dx.resource.load.cbufferrow.8``718   :header-rows: 1719 720   * - Argument721     -722     - Type723     - Description724   * - Return value725     -726     - A struct of 8 16-bit values727     - A single row of a cbuffer, interpreted as 8 16-bit values728   * - ``%buffer``729     - 0730     - ``target(dx.CBuffer, ...)``731     - The buffer to load from732   * - ``%index``733     - 1734     - ``i32``735     - Index into the buffer736 737Examples:738 739.. code-block:: llvm740 741   %ret = call {half, half, half, half, half, half, half, half}742       @llvm.dx.resource.load.cbufferrow.8(743           target("dx.CBuffer", target("dx.Layout", {half}, 2, 0)) %buffer,744           i32 %index)745   %ret = call {i16, i16, i16, i16, i16, i16, i16, i16}746       @llvm.dx.resource.load.cbufferrow.8(747           target("dx.CBuffer", target("dx.Layout", {i16}, 2, 0)) %buffer,748           i32 %index)749 750Resource dimensions751-------------------752 753*relevant types: Textures and Buffer*754 755The `getDimensions`_ DXIL operation returns the dimensions of a texture or756buffer resource. It returns a `Dimensions`_ type, which is a struct757containing four ``i32`` values. The values in the struct represent the size758of each dimension of the resource, and when aplicable the number of array759elements or number of samples. The mapping is defined in the760`getDimensions`_ documentation.761 762The LLVM IR representation of this operation has several forms763depending on the resource type and the specific ``getDimensions`` query.764The intrinsics return a scalar or anonymous struct with up to 4 `i32`765elements. The intrinsic names include suffixes to indicate the number of766elements in the return value. The suffix `.x` indicates a single `i32`767return value, `.xy` indicates a struct with two `i32` values, and `.xyz`768indicates a struct with three `i32` values.769 770Intrinsics representing queries on multisampled texture resources include771`.ms.` in their name and their return value includes an additional `i32` for772the number of samples.773 774Intrinsics with `mip_level` argument and `.levels.` in their name are used775for texture resources with multiple MIP levels. Their return776struct includes an additional `i32` for the number of levels the resource has.777 778.. code-block:: llvm779 780   i32 @llvm.dx.resource.getdimensions.x( target("dx.*") handle )781   {i32, i32} @llvm.dx.resource.getdimensions.xy( target("dx.*") handle )782   {i32, i32, i32} @llvm.dx.resource.getdimensions.xyz( target("dx.*") handle )783   {i32, i32} @llvm.dx.resource.getdimensions.levels.x( target("dx.*") handle, i32 mip_level )784   {i32, i32, i32} @llvm.dx.resource.getdimensions.levels.xy( target("dx.*") handle, i32 mip_level )785   {i32, i32, i32, i32} @llvm.dx.resource.getdimensions.levels.xyz( target("dx.*") handle, i32 mip_level )786   {i32, i32, i32} @llvm.dx.resource.getdimensions.ms.xy( target("dx.*") handle )787   {i32, i32, i32, i32} @llvm.dx.resource.getdimensions.ms.xyz( target("dx.*") handle )788 789.. list-table:: ``@llvm.dx.resource.getdimensions.*``790   :header-rows: 1791 792   * - Argument793     -794     - Type795     - Description796   * - Return value797     -798     - `i32`, `{i32, i32}`, `{i32, i32, i32}`, or `{i32, i32, i32, i32}`799     - Width, height, and depth of the resource (based on the specific suffix), and a number of levels or samples where aplicable.800   * - ``%handle``801     - 0802     - ``target(dx.*)``803     - Resource handle804   * - ``%mip_level``805     - 1806     - ``i32``807     - MIP level for the requested dimensions.808 809Examples:810 811.. code-block:: llvm812 813  ; RWBuffer<float4>814  %dim = call i32 @llvm.dx.resource.getdimensions.x(target("dx.TypedBuffer", <4 x float>, 1, 0, 0) %handle)815 816  ; Texture2D817  %0 = call {i32, i32} @llvm.dx.resource.getdimensions.xy(target("dx.Texture", ...) %tex2d)818  %tex2d_width = extractvalue {i32, i32} %0, 0819  %tex2d_height = extractvalue {i32, i32} %0, 1820 821  ; Texture2DArray with levels822  %1 = call {i32, i32, i32, i32} @llvm.dx.resource.getdimensions.levels.xyz(823     target("dx.Texture", ...) %tex2darray, i32 1)824  %tex2darray_width = extractvalue {i32, i32, i32, i32} %1, 0825  %tex2darray_height = extractvalue {i32, i32, i32, i32} %1, 1826  %tex2darray_elem_count = extractvalue {i32, i32, i32, i32} %1, 2827  %tex2darray_levels_count = extractvalue {i32, i32, i32, i32} %1, 3828 829  ; Texture2DMS830  %2 = call {i32, i32, i32} @llvm.dx.resource.getdimensions.ms.xy(831     target("dx.Texture", ...) %tex2dms)832  %tex2dms_width = extractvalue {i32, i32, i32} %2, 0833  %tex2dms_height = extractvalue {i32, i32, i32} %2, 1834  %tex2dms_samples_count = extractvalue {i32, i32, i32} %2, 2835 836.. _Dimensions: https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/DXIL.rst#resource-operation-return-types837.. _getDimensions: https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/DXIL.rst#getdimensions838