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