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