-
Notifications
You must be signed in to change notification settings - Fork 14.8k
[HLSL] Tests for local resource arrays #153257
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
…ing and make them static If a resource array does not have an explicit binding attribute, SemaHLSL will add an implicit one. The attribute will be used to transfer implicit binding order ID to the codegen, the same way as it is done for HLSLBufferDecls. This is necessary in order to generate correct initialization of resources in an array that does not have an explicit binding. This change also marks resource arrays declared at a global scope as `static`, which is what is already done for standalone resources.
… resource-array-impl-binding-attr
Adds support for accessing individual resources from fixed-size resource arrays declared at global scope. When a global resource array is indexed to retrieve a specific resource, the codegen translates the `ArraySubscriptExpr` into a constructor call for the corresponding resource record type and binding. Closes llvm#145424
…urce-array-subscript-one-elem-codegen
9e9dd4e
to
3a4b7f2
Compare
@llvm/pr-subscribers-hlsl @llvm/pr-subscribers-clang Author: Helena Kotas (hekota) ChangesAdd tests for local arrays of resources. Closes #145425 Depends on #152454 Full diff: https://github.com/llvm/llvm-project/pull/153257.diff 3 Files Affected:
diff --git a/clang/test/CodeGenHLSL/resources/res-array-local1.hlsl b/clang/test/CodeGenHLSL/resources/res-array-local1.hlsl
new file mode 100644
index 0000000000000..3257454484794
--- /dev/null
+++ b/clang/test/CodeGenHLSL/resources/res-array-local1.hlsl
@@ -0,0 +1,62 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-compute -finclude-default-header \
+// RUN: -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
+
+// This test verifies local arrays of resources in HLSL.
+
+// CHECK: @_ZL1A = internal global %"class.hlsl::RWBuffer" poison, align 4
+// CHECK: @_ZL1B = internal global %"class.hlsl::RWBuffer" poison, align 4
+// CHECK: @_ZL1C = internal global %"class.hlsl::RWBuffer" poison, align 4
+
+RWBuffer<float> A : register(u1);
+RWBuffer<float> B : register(u2);
+RWBuffer<float> C : register(u3);
+RWStructuredBuffer<float> Out : register(u0);
+
+// CHECK: define internal void @_Z4mainv()
+// CHECK-NEXT: entry:
+[numthreads(4,1,1)]
+void main() {
+// CHECK-NEXT: %First = alloca [3 x %"class.hlsl::RWBuffer"], align 4
+// CHECK-NEXT: %Second = alloca [4 x %"class.hlsl::RWBuffer"], align 4
+ RWBuffer<float> First[3] = { A, B, C };
+ RWBuffer<float> Second[4];
+
+// Verify initialization of First array from an initialization list
+// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 %First, ptr align 4 @_ZL1A, i32 4, i1 false)
+// CHECK-NEXT: %[[Ptr1:.*]] = getelementptr inbounds %"class.hlsl::RWBuffer", ptr %First, i32 1
+// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 %[[Ptr1]], ptr align 4 @_ZL1B, i32 4, i1 false)
+// CHECK-NEXT: %[[Ptr2:.*]] = getelementptr inbounds %"class.hlsl::RWBuffer", ptr %First, i32 2
+// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 %[[Ptr2]], ptr align 4 @_ZL1C, i32 4, i1 false)
+
+// Verify default initialization of Second array, which means there is a loop iterating
+// over the array elements and calling the default constructor for each
+// CHECK-NEXT: %[[ArrayBeginPtr:.*]] = getelementptr inbounds [4 x %"class.hlsl::RWBuffer"], ptr %Second, i32 0, i32 0
+// CHECK-NEXT: %[[ArrayEndPtr:.*]] = getelementptr inbounds %"class.hlsl::RWBuffer", ptr %[[ArrayBeginPtr]], i32 4
+// CHECK-NEXT: br label %[[ArrayInitLoop:.*]]
+// CHECK: [[ArrayInitLoop]]:
+// CHECK-NEXT: %[[ArrayCurPtr:.*]] = phi ptr [ %[[ArrayBeginPtr]], %entry ], [ %[[ArrayNextPtr:.*]], %[[ArrayInitLoop]] ]
+// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1Ev(ptr {{.*}} %[[ArrayCurPtr]])
+// CHECK-NEXT: %[[ArrayNextPtr]] = getelementptr inbounds %"class.hlsl::RWBuffer", ptr %[[ArrayCurPtr]], i32 1
+// CHECK-NEXT: %[[ArrayInitDone:.*]] = icmp eq ptr %[[ArrayNextPtr]], %[[ArrayEndPtr]]
+// CHECK-NEXT: br i1 %[[ArrayInitDone]], label %[[AfterArrayInit:.*]], label %[[ArrayInitLoop]]
+// CHECK: [[AfterArrayInit]]:
+
+// Initialize First[2] with C
+// CHECK: %[[Ptr3:.*]] = getelementptr inbounds [4 x %"class.hlsl::RWBuffer"], ptr %Second, i32 0, i32 2
+// CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 4 %[[Ptr3]], ptr align 4 @_ZL1C, i32 4, i1 false)
+ Second[2] = C;
+
+// get First[1][0] value
+// CHECK: %[[First_1_Ptr:.*]] = getelementptr inbounds [3 x %"class.hlsl::RWBuffer"], ptr %First, i32 0, i32 1
+// CHECK: %[[BufPtr1:.*]] = call {{.*}} ptr @_ZN4hlsl8RWBufferIfEixEj(ptr {{.*}} %[[First_1_Ptr]], i32 noundef 0)
+// CHECK: %[[Value1:.*]] = load float, ptr %[[BufPtr1]], align 4
+
+// get Second[2][0] value
+// CHECK: %[[Second_2_Ptr:.*]] = getelementptr inbounds [4 x %"class.hlsl::RWBuffer"], ptr %Second, i32 0, i32 2
+// CHECK: %[[BufPtr2:.*]] = call {{.*}} ptr @_ZN4hlsl8RWBufferIfEixEj(ptr {{.*}} %[[Second_2_Ptr]], i32 noundef 0)
+// CHECK: %[[Value2:.*]] = load float, ptr %[[BufPtr2]], align 4
+
+// add them
+// CHECK: %{{.*}} = fadd {{.*}} float %[[Value1]], %[[Value2]]
+ Out[0] = First[1][0] + Second[2][0];
+}
diff --git a/clang/test/CodeGenHLSL/resources/res-array-local2.hlsl b/clang/test/CodeGenHLSL/resources/res-array-local2.hlsl
new file mode 100644
index 0000000000000..e51bf71119914
--- /dev/null
+++ b/clang/test/CodeGenHLSL/resources/res-array-local2.hlsl
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-compute -finclude-default-header \
+// RUN: -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
+
+// This test verifies handling of local arrays of resources when used as a function argument.
+
+// CHECK: @_ZL1A = internal global [3 x %"class.hlsl::RWBuffer"] poison, align 4
+
+RWBuffer<float> A[3] : register(u0);
+RWStructuredBuffer<float> Out : register(u0);
+
+// CHECK: define {{.*}} float @_Z3fooA3_N4hlsl8RWBufferIfEE(ptr noundef byval([3 x %"class.hlsl::RWBuffer"]) align 4 %LocalA)
+// CHECK-NEXT: entry:
+float foo(RWBuffer<float> LocalA[3]) {
+// CHECK-NEXT: %[[LocalA_2_Ptr:.*]] = getelementptr inbounds [3 x %"class.hlsl::RWBuffer"], ptr %LocalA, i32 0, i32 2
+// CHECK-NEXT: %[[BufPtr:.*]] = call {{.*}} ptr @_ZN4hlsl8RWBufferIfEixEj(ptr {{.*}} %[[LocalA_2_Ptr]], i32 noundef 0)
+// CHECK-NEXT: %[[Value:.*]] = load float, ptr %[[BufPtr]], align 4
+// CHECK-NEXT: ret float %[[Value]]
+ return LocalA[2][0];
+}
+
+// CHECK: define internal void @_Z4mainv()
+// CHECK-NEXT: entry:
+[numthreads(4,1,1)]
+void main() {
+// Check that the `main` function calls `foo` with a local copy of the array
+// CHECK-NEXT: %[[Tmp:.*]] = alloca [3 x %"class.hlsl::RWBuffer"], align 4
+// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 %[[Tmp]], ptr align 4 @_ZL1A, i32 12, i1 false)
+
+// CHECK-NEXT: %[[ReturnedValue:.*]] = call {{.*}} float @_Z3fooA3_N4hlsl8RWBufferIfEE(ptr noundef byval([3 x %"class.hlsl::RWBuffer"]) align 4 %[[Tmp]])
+// CHECK-NEXT: %[[OutBufPtr:.*]] = call {{.*}} ptr @_ZN4hlsl18RWStructuredBufferIfEixEj(ptr {{.*}} @_ZL3Out, i32 noundef 0)
+// CHECK-NEXT: store float %[[ReturnedValue]], ptr %[[OutBufPtr]], align 4
+// CHECK-NEXT: ret void
+ Out[0] = foo(A);
+}
diff --git a/clang/test/CodeGenHLSL/resources/res-array-local3.hlsl b/clang/test/CodeGenHLSL/resources/res-array-local3.hlsl
new file mode 100644
index 0000000000000..4b7eee99b6b6f
--- /dev/null
+++ b/clang/test/CodeGenHLSL/resources/res-array-local3.hlsl
@@ -0,0 +1,60 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-compute -finclude-default-header \
+// RUN: -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
+
+// This test verifies handling of local arrays of resources when used
+// as a function argument that is modified inside the function.
+
+// CHECK: @_ZL1X = internal global %"class.hlsl::RWBuffer" poison, align 4
+// CHECK: @_ZL1Y = internal global %"class.hlsl::RWBuffer" poison, align 4
+
+RWBuffer<int> X : register(u0);
+RWBuffer<int> Y : register(u1);
+
+// CHECK: define {{.*}} @_Z6SomeFnA2_N4hlsl8RWBufferIiEEji(
+// CHECK-SAME: ptr noundef byval([2 x %"class.hlsl::RWBuffer"]) align 4 %B, i32 noundef %Idx, i32 noundef %Val0)
+// CHECK-NEXT: entry:
+// CHECK-NEXT: %[[Idx_addr:.*]] = alloca i32, align 4
+// CHECK-NEXT: %[[Val0_addr:.*]] = alloca i32, align 4
+// CHECK-NEXT: store i32 %Idx, ptr %[[Idx_addr]], align 4
+// CHECK-NEXT: store i32 %Val0, ptr %[[Val0_addr]], align 4
+void SomeFn(RWBuffer<int> B[2], uint Idx, int Val0) {
+
+// CHECK-NEXT: %[[B_0_Ptr:.*]] = getelementptr inbounds [2 x %"class.hlsl::RWBuffer"], ptr %B, i32 0, i32 0
+// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 %[[B_0_Ptr]], ptr align 4 @_ZL1Y, i32 4, i1 false)
+ B[0] = Y;
+
+// CHECK-NEXT: %[[Val0:.*]] = load i32, ptr %[[Val0_addr]], align 4
+// CHECK-NEXT: %[[B_0_Ptr:.*]] = getelementptr inbounds [2 x %"class.hlsl::RWBuffer"], ptr %B, i32 0, i32 0
+// CHECK-NEXT: %[[Idx:.*]] = load i32, ptr %[[Idx_addr]], align 4
+// CHECK-NEXT: %[[BufPtr:.*]] = call {{.*}} ptr @_ZN4hlsl8RWBufferIiEixEj(ptr {{.*}} %[[B_0_Ptr]], i32 noundef %[[Idx]])
+// CHECK-NEXT: store i32 %[[Val0]], ptr %[[BufPtr]], align 4
+ B[0][Idx] = Val0;
+}
+
+// CHECK: define {{.*}} void @_Z4mainj(i32 noundef %GI)
+// CHECK-NEXT: entry:
+// CHECK-NEXT: %[[GI_addr:.*]] = alloca i32, align 4
+[numthreads(4,1,1)]
+void main(uint GI : SV_GroupIndex) {
+// CHECK-NEXT: %A = alloca [2 x %"class.hlsl::RWBuffer"], align 4
+// CHECK-NEXT: %[[Tmp:.*]] = alloca [2 x %"class.hlsl::RWBuffer"], align 4
+// CHECK-NEXT: store i32 %GI, ptr %GI.addr, align 4
+
+// Initialization of array A with resources X and Y
+// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 %A, ptr align 4 @_ZL1X, i32 4, i1 false)
+// CHECK-NEXT: %[[A_1_Ptr:.*]] = getelementptr inbounds %"class.hlsl::RWBuffer", ptr %A, i32 1
+// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 %[[A_1_Ptr]], ptr align 4 @_ZL1Y, i32 4, i1 false)
+ RWBuffer<int> A[2] = {X, Y};
+
+// Verify that SomeFn is called with a local copy of the array A
+// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 %[[Tmp]], ptr align 4 %A, i32 8, i1 false)
+// CHECK-NEXT: %[[GI:.*]] = load i32, ptr %[[GI_addr]], align 4
+// CHECK-NEXT: call void @_Z6SomeFnA2_N4hlsl8RWBufferIiEEji(ptr noundef byval([2 x %"class.hlsl::RWBuffer"]) align 4 %[[Tmp]], i32 noundef %[[GI]], i32 noundef 1)
+ SomeFn(A, GI, 1);
+
+// CHECK-NEXT: %[[A_0_Ptr:.*]] = getelementptr inbounds [2 x %"class.hlsl::RWBuffer"], ptr %A, i32 0, i32 0
+// CHECK-NEXT: %[[GI:.*]] = load i32, ptr %[[GI_addr]], align 4
+// CHECK-NEXT: %[[BufPtr:.*]] = call {{.*}} ptr @_ZN4hlsl8RWBufferIiEixEj(ptr {{.*}} %[[A_0_Ptr]], i32 noundef %[[GI]])
+// CHECK-NEXT: store i32 2, ptr %[[BufPtr]], align 4
+ A[0][GI] = 2;
+}
|
…void alloc, use SmallVectorImpl, formatting
s-perron
approved these changes
Aug 18, 2025
…-codegen' of https://github.com/llvm/llvm-project into res-arrays-local-tests
…arrays-local-tests
llvm-beanz
approved these changes
Aug 19, 2025
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Add tests for local arrays of resources.
Closes #145425