[llvm-branch-commits] [clang] [HLSL] Global resource arrays element access (PR #152454)

Helena Kotas via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Mon Aug 11 11:17:16 PDT 2025


================
@@ -0,0 +1,59 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-compute -finclude-default-header \
+// RUN:   -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s -check-prefixes=CHECK,DXIL
+// RUN: %clang_cc1 -finclude-default-header -triple spirv-unknown-vulkan-compute \
+// RUN:   -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s -check-prefixes=CHECK,SPV
+
+// CHECK: @[[BufA:.*]] = private unnamed_addr constant [2 x i8] c"A\00", align 1
+// CHECK: @[[BufB:.*]] = private unnamed_addr constant [2 x i8] c"B\00", align 1
+// CHECK: @[[BufC:.*]] = private unnamed_addr constant [2 x i8] c"C\00", align 1
+// CHECK: @[[BufD:.*]] = private unnamed_addr constant [2 x i8] c"D\00", align 1
+
+// different explicit binding for DXIL and SPIR-V
+[[vk::binding(12, 2)]]
+RWBuffer<float> A[4] : register(u10, space1);
+
+[[vk::binding(13)]] // SPIR-V explicit binding 13, set 0
+RWBuffer<int> B[5]; // DXIL implicit binding in space0
+
+// same explicit binding for both DXIL and SPIR-V
+// (SPIR-V takes the binding from register annotation if there is no vk::binding attribute))
+RWBuffer<int> C[3] : register(u2);
+
+// implicit binding for both DXIL and SPIR-V in space/set 0 
+RWBuffer<double> D[10];
+
+RWStructuredBuffer<float> Out;
+
+[numthreads(4,1,1)]
+void main() {
+  // CHECK: define internal{{.*}} void @_Z4mainv()
+  // CHECK: %[[Tmp0:.*]] = alloca %"class.hlsl::RWBuffer
+  // CHECK: %[[Tmp1:.*]] = alloca %"class.hlsl::RWBuffer
+  // CHECK: %[[Tmp2:.*]] = alloca %"class.hlsl::RWBuffer
+  // CHECK: %[[Tmp3:.*]] = alloca %"class.hlsl::RWBuffer
+
+  // Make sure A[2] is translated to a RWBuffer<float> constructor call with range 4 and index 2
+  // and DXIL explicit binding (u10, space1)
+  // and SPIR-V explicit binding (binding 12, set 2) 
+  // DXIL: call void @_ZN4hlsl8RWBufferIfEC1EjjijPKc(ptr {{.*}} %[[Tmp0]], i32 noundef 10, i32 noundef 1, i32 noundef 4, i32 noundef 2, ptr noundef @[[BufA]])
+  // SPV: call void @_ZN4hlsl8RWBufferIfEC1EjjijPKc(ptr {{.*}} %[[Tmp0]], i32 noundef 12, i32 noundef 2, i32 noundef 4, i32 noundef 2, ptr noundef @[[BufA]])
+
+  // Make sure B[3] is translated to a RWBuffer<int> constructor call with range 5 and index 3
+  // and DXIL for implicit binding in space0, order id 0
+  // and SPIR-V explicit binding (binding 13, set 0)
+  // DXIL: call void @_ZN4hlsl8RWBufferIiEC1EjijjPKc(ptr {{.*}} %[[Tmp1]], i32 noundef 0, i32 noundef 5, i32 noundef 3, i32 noundef 0, ptr noundef @[[BufB]])
----------------
hekota wrote:

This is intentional. The constructor call on line 38 is for explicit binding (`jjij`) and the arguments are `(register, space, range size, index, name)`. The call on line 44 is for implicit binding (`jijj`) and the arguments are `(space, range size, index, order_id, name)`. The range size can be `-1` for unbouded arrays, and that is the only signed int in the signature.

The `order_id` argument is a sequential number that is assigned to resources with implicit binding and corresponds to the order in which the resources were declared in the file. We need it because implicit bindings are assigned later on in an LLVM pass and we need to know the order in which they were declared.

For more details check out [resource constructors proposal](https://github.com/llvm/wg-hlsl/blob/main/proposals/0025-resource-constructors.md) and [implicit binding](https://github.com/llvm/wg-hlsl/blob/main/proposals/0024-implicit-resource-binding.md).

https://github.com/llvm/llvm-project/pull/152454


More information about the llvm-branch-commits mailing list