xref: /llvm-project/llvm/docs/DirectX/DXILResources.rst (revision 0e51b54b7ac02b0920e20b8ccae26b32bd6b6982)
1======================
2DXIL Resource Handling
3======================
4
5.. contents::
6   :local:
7
8.. toctree::
9   :hidden:
10
11Introduction
12============
13
14Resources in DXIL are represented via ``TargetExtType`` in LLVM IR and
15eventually lowered by the DirectX backend into metadata in DXIL.
16
17In DXC and DXIL, static resources are represented as lists of SRVs (Shader
18Resource Views), UAVs (Uniform Access Views), CBVs (Constant Bffer Views), and
19Samplers. This metadata consists of a "resource record ID" which uniquely
20identifies a resource and type information. As of shader model 6.6, there are
21also dynamic resources, which forgo the metadata and are described via
22``annotateHandle`` operations in the instruction stream instead.
23
24In LLVM we attempt to unify some of the alternative representations that are
25present in DXC, with the aim of making handling of resources in the middle end
26of the compiler simpler and more consistent.
27
28Resource Type Information and Properties
29========================================
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 at
37   DXIL lowering time.
38
39`Binding information`
40   Information about where the resource comes from. This is either (a) a
41   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 the
45   :ref:`handle creation intrinsics <dxil-resources-handles>`. When generating
46   DXIL we transform these calls to metadata, ``dx.op.createHandle``,
47   ``dx.op.createHandleFromBinding``, ``dx.op.createHandleFromHeap``, and
48   ``dx.op.createHandleForLib`` as needed.
49
50`Type information`
51   The type of data that's accessible via the resource. For buffers and
52   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 is
54   the kind of sampler.
55
56   In LLVM we embed this information as a parameter on the ``target()`` type of
57   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 a
62   set of DXIL kinds like ``RawBuffer`` and ``Texture2D`` with fields for
63   certain properties such as ``IsUAV`` and ``IsROV``.
64
65   In LLVM we represent this in the ``target()`` type. We omit information
66   that's deriveable from the type information, but we do have fields to encode
67   ``IsWriteable``, ``IsROV``, and ``SampleCount`` when needed.
68
69.. note:: TODO: There are two fields in the DXIL metadata that are not
70   represented as part of the target type: ``IsGloballyCoherent`` and
71   ``HasCounter``.
72
73   Since these are derived from analysis, storing them on the type would mean
74   we need to change the type during the compiler pipeline. That just isn't
75   practical. It isn't entirely clear to me that we need to serialize this info
76   into the IR during the compiler pipeline anyway - we can probably get away
77   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 handle
81   creation.
82
83.. _dxil-resources-types-of-resource:
84
85Types of Resource
86=================
87
88We define a set of ``TargetExtTypes`` that is similar to the HLSL
89representations for the various resources, albeit with a few things
90parameterized. This is different than DXIL, as simplifying the types to
91something like "dx.srv" and "dx.uav" types would mean the operations on these
92types would have to be overly generic.
93
94Buffers
95-------
96
97.. code-block:: llvm
98
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 the
10316-byte `bufferLoad`_ / `bufferStore`_ operations that work on DXIL's
104TypedBuffers and the `rawBufferLoad`_ / `rawBufferStore`_ operations that are
105used for DXIL's RawBuffers and StructuredBuffers. We call the latter
106"RawBuffer" to match the naming of the operations, but it can represent both
107the Raw and Structured variants.
108
109HLSL's Buffer and RWBuffer are represented as a TypedBuffer with an element
110type that is a scalar integer or floating point type, or a vector of at most 4
111such 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 to
115differentiate signed vs unsigned ints. The is because in LLVM IR int types
116don'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, as
119well as atomics.
120
121There are a few fields to describe variants of all of these types:
122
123.. list-table:: Buffer Fields
124   :header-rows: 1
125
126   * - Field
127     - Description
128   * - ElementType
129     - Type for a single element, such as ``i8``, ``v4f32``, or a structure
130       type.
131   * - IsWriteable
132     - Whether or not the field is writeable. This distinguishes SRVs (not
133       writeable) and UAVs (writeable).
134   * - IsROV
135     - Whether the UAV is a rasterizer ordered view. Always ``0`` for SRVs.
136   * - IsSigned
137     - Whether an int element type is signed ("dx.TypedBuffer" only)
138
139.. _bufferLoad: https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/DXIL.rst#bufferload
140.. _bufferStore: https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/DXIL.rst#bufferstore
141.. _rawBufferLoad: https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/DXIL.rst#rawbufferload
142.. _rawBufferStore: https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/DXIL.rst#rawbufferstore
143
144Resource Operations
145===================
146
147.. _dxil-resources-handles:
148
149Resource Handles
150----------------
151
152We provide a few different ways to instantiate resources in the IR via the
153``llvm.dx.handle.*`` intrinsics. These intrinsics are overloaded on return
154type, returning an appropriate handle for the resource, and represent binding
155information 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 are
159rougly equivalent to the DXIL operations ``dx.op.createHandleFromBinding``,
160``dx.op.createHandleFromHeap``, and ``dx.op.createHandleForLib``, but they fold
161the subsequent ``dx.op.annotateHandle`` operation in. Note that we don't have
162an 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 than
166indexing from the beginning of the binding space. This matches the semantics
167more clearly and avoids a non-obvious invariant in what constitutes valid
168arguments.
169
170.. _dx.op.createHandle: https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/DXIL.rst#resource-handles
171
172.. list-table:: ``@llvm.dx.resource.handlefrombinding``
173   :header-rows: 1
174
175   * - Argument
176     -
177     - Type
178     - Description
179   * - Return value
180     -
181     - A ``target()`` type
182     - A handle which can be operated on
183   * - ``%reg_space``
184     - 1
185     - ``i32``
186     - Register space ID in the root signature for this resource.
187   * - ``%lower_bound``
188     - 2
189     - ``i32``
190     - Lower bound of the binding in its register space.
191   * - ``%range_size``
192     - 3
193     - ``i32``
194     - Range size of the binding.
195   * - ``%index``
196     - 4
197     - ``i32``
198     - Index from the beginning of the binding.
199   * - ``%non-uniform``
200     - 5
201     - i1
202     - 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 from
205          uniformity analysis...
206
207Examples:
208
209.. code-block:: llvm
210
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: 1
245
246   * - Argument
247     -
248     - Type
249     - Description
250   * - Return value
251     -
252     - A ``target()`` type
253     - A handle which can be operated on
254   * - ``%index``
255     - 0
256     - ``i32``
257     - Index of the resource to access.
258   * - ``%non-uniform``
259     - 1
260     - i1
261     - Must be ``true`` if the resource index may be non-uniform.
262
263Examples:
264
265.. code-block:: llvm
266
267   ; RWStructuredBuffer<float4> Buf = ResourceDescriptorHeap[2];
268   declare
269     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 Memory
278-----------------------------
279
280*relevant types: Buffers, CBuffer, and Textures*
281
282Loading and storing from resources is generally represented in LLVM using
283operations on memory that is only accessible via a handle object. Given a
284handle, `llvm.dx.resource.getpointer` gives a pointer that can be used to read
285and (depending on type) write to the resource.
286
287Accesses using `llvm.dx.resource.getpointer` are replaced with direct load and
288store operations in the `DXILResourceAccess` pass. These direct loads and
289stores are described later in this document.
290
291.. note:: Currently the pointers returned by `dx.resource.getpointer` are in
292          the default address space, but that will likely change in the future.
293
294.. list-table:: ``@llvm.dx.resource.getpointer``
295   :header-rows: 1
296
297   * - Argument
298     -
299     - Type
300     - Description
301   * - Return value
302     -
303     - Pointer
304     - A pointer to an object in the buffer
305   * - ``%buffer``
306     - 0
307     - ``target(dx.TypedBuffer, ...)``
308     - The buffer to access
309   * - ``%index``
310     - 1
311     - ``i32``
312     - Index into the buffer
313
314Examples:
315
316.. code-block:: llvm
317
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 Gathers
322---------------------------
323
324*relevant types: Buffers, CBuffers, and Textures*
325
326All load, sample, and gather operations in DXIL return a `ResRet`_ type, and
327CBuffer loads return a similar `CBufRet`_ type. These types are structs
328containing 4 elements of some basic type, and in the case of `ResRet` a 5th
329element that is used by the `CheckAccessFullyMapped`_ operation. Some of these
330operations, like `RawBufferLoad`_ include a mask and/or alignment that tell us
331some information about how to interpret those four values.
332
333In the LLVM IR representations of these operations we instead return scalars or
334vectors, but we keep the requirement that we only return up to 4 elements of a
335basic type. This avoids some unnecessary casting and structure manipulation in
336the intermediate format while also keeping lowering to DXIL straightforward.
337
338LLVM intrinsics that map to operations returning `ResRet` return an anonymous
339struct with element-0 being the scalar or vector type, and element-1 being the
340``i1`` result of a ``CheckAccessFullyMapped`` call. We don't have a separate
341call to ``CheckAccessFullyMapped`` at all, since that's the only operation that
342can possibly be done on this value. In practice this may mean we insert a DXIL
343operation for the check when this was missing in the HLSL source, but this
344actually matches DXC's behaviour in practice.
345
346For TypedBuffer and Texture, we map directly from the contained type of the
347resource to the return value of the intrinsic. Since these resources are
348constrained to contain only scalars and vectors of up to 4 elements, the
349lowering to DXIL ops is generally straightforward. The one exception we have
350here is that `double` types in the elements are special - these are allowed in
351the LLVM intrinsics, but are lowered to pairs of `i32` followed by
352``MakeDouble`` operations for DXIL.
353
354.. _ResRet: https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/DXIL.rst#resource-operation-return-types
355.. _CBufRet: https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/DXIL.rst#cbufferloadlegacy
356.. _CheckAccessFullyMapped: https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/checkaccessfullymapped
357.. _RawBufferLoad: https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/DXIL.rst#rawbufferload
358
359.. list-table:: ``@llvm.dx.resource.load.typedbuffer``
360   :header-rows: 1
361
362   * - Argument
363     -
364     - Type
365     - Description
366   * - Return value
367     -
368     - A structure of the contained type and the check bit
369     - The data loaded from the buffer and the check bit
370   * - ``%buffer``
371     - 0
372     - ``target(dx.TypedBuffer, ...)``
373     - The buffer to load from
374   * - ``%index``
375     - 1
376     - ``i32``
377     - Index into the buffer
378
379Examples:
380
381.. code-block:: llvm
382
383   %ret = call {<4 x float>, i1}
384       @llvm.dx.resource.load.typedbuffer.v4f32.tdx.TypedBuffer_v4f32_0_0_0t(
385           target("dx.TypedBuffer", <4 x float>, 0, 0, 0) %buffer, i32 %index)
386   %ret = call {float, i1}
387       @llvm.dx.resource.load.typedbuffer.f32.tdx.TypedBuffer_f32_0_0_0t(
388           target("dx.TypedBuffer", float, 0, 0, 0) %buffer, i32 %index)
389   %ret = call {<4 x i32>, i1}
390       @llvm.dx.resource.load.typedbuffer.v4i32.tdx.TypedBuffer_v4i32_0_0_0t(
391           target("dx.TypedBuffer", <4 x i32>, 0, 0, 0) %buffer, i32 %index)
392   %ret = call {<4 x half>, i1}
393       @llvm.dx.resource.load.typedbuffer.v4f16.tdx.TypedBuffer_v4f16_0_0_0t(
394           target("dx.TypedBuffer", <4 x half>, 0, 0, 0) %buffer, i32 %index)
395   %ret = call {<2 x double>, i1}
396       @llvm.dx.resource.load.typedbuffer.v2f64.tdx.TypedBuffer_v2f64_0_0t(
397           target("dx.TypedBuffer", <2 x double>, 0, 0, 0) %buffer, i32 %index)
398
399For RawBuffer, an HLSL load operation may return an arbitrarily sized result,
400but we still constrain the LLVM intrinsic to return only up to 4 elements of a
401basic type. This means that larger loads are represented as a series of loads,
402which matches DXIL. Unlike in the `RawBufferLoad`_ operation, we do not need
403arguments for the mask/type size and alignment, since we can calculate these
404from the return type of the load during lowering.
405
406.. _RawBufferLoad: https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/DXIL.rst#rawbufferload
407
408.. list-table:: ``@llvm.dx.resource.load.rawbuffer``
409   :header-rows: 1
410
411   * - Argument
412     -
413     - Type
414     - Description
415   * - Return value
416     -
417     - A structure of a scalar or vector and the check bit
418     - The data loaded from the buffer and the check bit
419   * - ``%buffer``
420     - 0
421     - ``target(dx.RawBuffer, ...)``
422     - The buffer to load from
423   * - ``%index``
424     - 1
425     - ``i32``
426     - Index into the buffer
427   * - ``%offset``
428     - 2
429     - ``i32``
430     - Offset into the structure at the given index
431
432Examples:
433
434.. code-block:: llvm
435
436   ; float
437   %ret = call {float, i1}
438       @llvm.dx.resource.load.rawbuffer.f32.tdx.RawBuffer_f32_0_0_0t(
439           target("dx.RawBuffer", float, 0, 0, 0) %buffer,
440           i32 %index,
441           i32 0)
442   %ret = call {float, i1}
443       @llvm.dx.resource.load.rawbuffer.f32.tdx.RawBuffer_i8_0_0_0t(
444           target("dx.RawBuffer", i8, 0, 0, 0) %buffer,
445           i32 %byte_offset,
446           i32 0)
447
448   ; float4
449   %ret = call {<4 x float>, i1}
450       @llvm.dx.resource.load.rawbuffer.v4f32.tdx.RawBuffer_v4f32_0_0_0t(
451           target("dx.RawBuffer", float, 0, 0, 0) %buffer,
452           i32 %index,
453           i32 0)
454   %ret = call {float, i1}
455       @llvm.dx.resource.load.rawbuffer.v4f32.tdx.RawBuffer_i8_0_0_0t(
456           target("dx.RawBuffer", i8, 0, 0, 0) %buffer,
457           i32 %byte_offset,
458           i32 0)
459
460   ; struct S0 { float4 f; int4 i; };
461   %ret = call {<4 x float>, i1}
462       @llvm.dx.resource.load.rawbuffer.v4f32.tdx.RawBuffer_sl_v4f32v4i32s_0_0t(
463           target("dx.RawBuffer", {<4 x float>, <4 x i32>}, 0, 0, 0) %buffer,
464           i32 %index,
465           i32 0)
466   %ret = call {<4 x i32>, i1}
467       @llvm.dx.resource.load.rawbuffer.v4i32.tdx.RawBuffer_sl_v4f32v4i32s_0_0t(
468           target("dx.RawBuffer", {<4 x float>, <4 x i32>}, 0, 0, 0) %buffer,
469           i32 %index,
470           i32 1)
471
472   ; struct Q { float4 f; int3 i; }
473   ; struct R { int z; S x; }
474   %ret = call {i32, i1}
475       @llvm.dx.resource.load.rawbuffer.i32(
476           target("dx.RawBuffer", {i32, {<4 x float>, <3 x i32>}}, 0, 0, 0)
477               %buffer, i32 %index, i32 0)
478   %ret = call {<4 x float>, i1}
479       @llvm.dx.resource.load.rawbuffer.i32(
480           target("dx.RawBuffer", {i32, {<4 x float>, <3 x i32>}}, 0, 0, 0)
481               %buffer, i32 %index, i32 4)
482   %ret = call {<3 x i32>, i1}
483       @llvm.dx.resource.load.rawbuffer.i32(
484           target("dx.RawBuffer", {i32, {<4 x float>, <3 x i32>}}, 0, 0, 0)
485               %buffer, i32 %index, i32 20)
486
487   ; byteaddressbuf.Load<int64_t4>
488   %ret = call {<4 x i64>, i1}
489       @llvm.dx.resource.load.rawbuffer.v4i64.tdx.RawBuffer_i8_0_0t(
490           target("dx.RawBuffer", i8, 0, 0, 0) %buffer,
491           i32 %byte_offset,
492           i32 0)
493
494Stores
495------
496
497*relevant types: Textures and Buffer*
498
499The `TextureStore`_, `BufferStore`_, and `RawBufferStore`_ DXIL operations
500write four components to a texture or a buffer. These include a mask argument
501that is used when fewer than 4 components are written, but notably this only
502takes on the contiguous x, xy, xyz, and xyzw values.
503
504We define the LLVM store intrinsics to accept vectors when storing multiple
505components rather than using `undef` and a mask, but otherwise match the DXIL
506ops fairly closely.
507
508.. _TextureStore: https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/DXIL.rst#texturestore
509.. _BufferStore: https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/DXIL.rst#bufferstore
510.. _RawBufferStore: https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/DXIL.rst#rawbufferstore
511
512For TypedBuffer, we only need one coordinate, and we must always write a vector
513since partial writes aren't possible. Similarly to the load operations
514described above, we handle 64-bit types specially and only handle 2-element
515vectors rather than 4.
516
517Examples:
518
519.. list-table:: ``@llvm.dx.resource.store.typedbuffer``
520   :header-rows: 1
521
522   * - Argument
523     -
524     - Type
525     - Description
526   * - Return value
527     -
528     - ``void``
529     -
530   * - ``%buffer``
531     - 0
532     - ``target(dx.TypedBuffer, ...)``
533     - The buffer to store into
534   * - ``%index``
535     - 1
536     - ``i32``
537     - Index into the buffer
538   * - ``%data``
539     - 2
540     - A 4- or 2-element vector of the type of the buffer
541     - The data to store
542
543Examples:
544
545.. code-block:: llvm
546
547   call void @llvm.dx.resource.store.typedbuffer.tdx.Buffer_v4f32_1_0_0t(
548       target("dx.TypedBuffer", f32, 1, 0) %buf, i32 %index, <4 x f32> %data)
549   call void @llvm.dx.resource.store.typedbuffer.tdx.Buffer_v4f16_1_0_0t(
550       target("dx.TypedBuffer", f16, 1, 0) %buf, i32 %index, <4 x f16> %data)
551   call void @llvm.dx.resource.store.typedbuffer.tdx.Buffer_v2f64_1_0_0t(
552       target("dx.TypedBuffer", f64, 1, 0) %buf, i32 %index, <2 x f64> %data)
553
554For RawBuffer, we need two indices and we accept scalars and vectors of 4 or
555fewer elements. Note that we do allow vectors of 4 64-bit elements here.
556
557Examples:
558
559.. list-table:: ``@llvm.dx.resource.store.rawbuffer``
560   :header-rows: 1
561
562   * - Argument
563     -
564     - Type
565     - Description
566   * - Return value
567     -
568     - ``void``
569     -
570   * - ``%buffer``
571     - 0
572     - ``target(dx.RawBuffer, ...)``
573     - The buffer to store into
574   * - ``%index``
575     - 1
576     - ``i32``
577     - Index into the buffer
578   * - ``%offset``
579     - 2
580     - ``i32``
581     - Byte offset into structured buffer elements
582   * - ``%data``
583     - 3
584     - Scalar or vector
585     - The data to store
586
587Examples:
588
589.. code-block:: llvm
590
591   ; float
592   call void @llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_f32_1_0_0t.f32(
593       target("dx.RawBuffer", float, 1, 0, 0) %buffer,
594       i32 %index, i32 0, float %data)
595   call void @llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_i8_1_0_0t.f32(
596       target("dx.RawBuffer", i8, 1, 0, 0) %buffer,
597       i32 %index, i32 0, float %data)
598
599   ; float4
600   call void @llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_v4f32_1_0_0t.v4f32(
601       target("dx.RawBuffer", <4 x float>, 1, 0, 0) %buffer,
602       i32 %index, i32 0, <4 x float> %data)
603   call void @llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_i8_1_0_0t.v4f32(
604       target("dx.RawBuffer", i8, 1, 0, 0) %buffer,
605       i32 %index, i32 0, <4 x float> %data)
606
607   ; struct S0 { float4 f; int4 i; }
608   call void @llvm.dx.resource.store.rawbuffer.v4f32(
609       target("dx.RawBuffer", { <4 x float>, <4 x i32> }, 1, 0, 0) %buffer,
610       i32 %index, i32 0, <4 x float> %data0)
611   call void @llvm.dx.resource.store.rawbuffer.v4i32(
612       target("dx.RawBuffer", { <4 x float>, <4 x i32> }, 1, 0, 0) %buffer,
613       i32 %index, i32 16, <4 x i32> %data1)
614
615   ; struct Q { float4 f; int3 i; }
616   ; struct R { int z; S x; }
617   call void @llvm.dx.resource.store.rawbuffer.i32(
618       target("dx.RawBuffer", {i32, {<4 x float>, <3 x half>}}, 1, 0, 0)
619           %buffer,
620       i32 %index, i32 0, i32 %data0)
621   call void @llvm.dx.resource.store.rawbuffer.v4f32(
622       target("dx.RawBuffer", {i32, {<4 x float>, <3 x half>}}, 1, 0, 0)
623           %buffer,
624       i32 %index, i32 4, <4 x float> %data1)
625   call void @llvm.dx.resource.store.rawbuffer.v3f16(
626       target("dx.RawBuffer", {i32, {<4 x float>, <3 x half>}}, 1, 0, 0)
627           %buffer,
628       i32 %index, i32 20, <3 x half> %data2)
629
630   ; byteaddressbuf.Store<int64_t4>
631   call void @llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_i8_1_0_0t.v4f64(
632       target("dx.RawBuffer", i8, 1, 0, 0) %buffer,
633       i32 %index, i32 0, <4 x double> %data)
634
635