|
| 1 | +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-compute -finclude-default-header \ |
| 2 | +// RUN: -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s -check-prefixes=CHECK,DXIL |
| 3 | +// RUN: %clang_cc1 -finclude-default-header -triple spirv-unknown-vulkan-compute \ |
| 4 | +// RUN: -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s -check-prefixes=CHECK,SPV |
| 5 | + |
| 6 | +// CHECK: @[[BufA:.*]] = private unnamed_addr constant [2 x i8] c"A\00", align 1 |
| 7 | +// CHECK: @[[BufB:.*]] = private unnamed_addr constant [2 x i8] c"B\00", align 1 |
| 8 | + |
| 9 | +RWBuffer<float> A[] : register(u10, space1); |
| 10 | +RWBuffer<int> B[][5][4]; |
| 11 | + |
| 12 | +RWStructuredBuffer<float> Out; |
| 13 | + |
| 14 | +float foo(RWBuffer<int> Arr[4], uint Index) { |
| 15 | + return (float)Arr[Index][0]; |
| 16 | +} |
| 17 | + |
| 18 | +// NOTE: |
| 19 | +// - _ZN4hlsl8RWBufferIfEC1EjjijPKc is the constructor call for explicit binding for RWBuffer<float> |
| 20 | +// (has "jjij" in the mangled name) and the arguments are (register, space, range_size, index, name). |
| 21 | +// - _ZN4hlsl8RWBufferIiEC1EjijjPKc is the constructor call for implicit binding for RWBuffer<int> |
| 22 | +// (has "jijj" in the mangled name) and the arguments are (space, range_size, index, order_id, name). |
| 23 | +// - _ZN4hlsl8RWBufferIfEixEj is the subscript operator on RWBuffer<float> |
| 24 | + |
| 25 | +[numthreads(4,1,1)] |
| 26 | +void main(uint GI : SV_GroupIndex) { |
| 27 | + // CHECK: define internal {{.*}}void @_Z4mainj(i32 noundef %GI) |
| 28 | + // CHECK: %[[GI_alloca:.*]] = alloca i32, align 4 |
| 29 | + // CHECK-NEXT: %a = alloca float, align 4 |
| 30 | + // CHECK-NEXT: %[[Tmp0:.*]] = alloca %"class.hlsl::RWBuffer |
| 31 | + // CHECK-NEXT: %b = alloca float, align 4 |
| 32 | + // CHECK-NEXT: %[[Tmp1:.*]] = alloca [4 x %"class.hlsl::RWBuffer"] |
| 33 | + // CHECK-NEXT: %[[Tmp2:.*]] = alloca [4 x %"class.hlsl::RWBuffer"] |
| 34 | + // CHECK-NEXT: store i32 %GI, ptr %[[GI_alloca]], align 4 |
| 35 | + |
| 36 | + // Make sure A[100] is translated to a RWBuffer<float> constructor call with range -1 and index 100 |
| 37 | + // and explicit binding (u10, space1) |
| 38 | + // CHECK: call void @_ZN4hlsl8RWBufferIfEC1EjjijPKc(ptr {{.*}} %[[Tmp0]], i32 noundef 10, i32 noundef 1, i32 noundef -1, i32 noundef 100, ptr noundef @A.str) |
| 39 | + // CHECK-NEXT: %[[BufPtr:.*]] = call {{.*}} ptr{{.*}} @_ZN4hlsl8RWBufferIfEixEj(ptr {{.*}} %[[Tmp0]], i32 noundef 0) |
| 40 | + // CHECK-NEXT: %[[Value1:.*]] = load float, ptr{{.*}} %[[BufPtr]], align 4 |
| 41 | + // CHECK-NEXT: store float %[[Value1]], ptr %a, align 4 |
| 42 | + float a = A[100][0]; |
| 43 | + |
| 44 | + // Make sure B[2][3] is translated to a local RWBuffer<int>[4] array where each array element |
| 45 | + // is initialized by a constructor call with range -1 and index 52-55 and implicit binding |
| 46 | + // (space 0, order_id 0) |
| 47 | + // The first index is calculated from the array dimensions (unbounded x 5 x 4) and indices (2, 3) |
| 48 | + // as 2 * 5 * 4 + 3 * 4 = 52 and the following indices are sequential. |
| 49 | + // CHECK-NEXT: %[[Ptr_Tmp2_0:.*]] = getelementptr [4 x %"class.hlsl::RWBuffer"], ptr %[[Tmp2]], i32 0, i32 0 |
| 50 | + // CHECK-NEXT: call void @_ZN4hlsl8RWBufferIiEC1EjijjPKc(ptr {{.*}} %[[Ptr_Tmp2_0]], i32 noundef 0, i32 noundef -1, i32 noundef 52, i32 noundef 0, ptr noundef @B.str) |
| 51 | + // CHECK-NEXT: %[[Ptr_Tmp2_1:.*]] = getelementptr [4 x %"class.hlsl::RWBuffer"], ptr %[[Tmp2]], i32 0, i32 1 |
| 52 | + // CHECK-NEXT: call void @_ZN4hlsl8RWBufferIiEC1EjijjPKc(ptr {{.*}} %[[Ptr_Tmp2_1]], i32 noundef 0, i32 noundef -1, i32 noundef 53, i32 noundef 0, ptr noundef @B.str) |
| 53 | + // CHECK-NEXT: %[[Ptr_Tmp2_2:.*]] = getelementptr [4 x %"class.hlsl::RWBuffer"], ptr %[[Tmp2]], i32 0, i32 2 |
| 54 | + // CHECK-NEXT: call void @_ZN4hlsl8RWBufferIiEC1EjijjPKc(ptr {{.*}} %[[Ptr_Tmp2_2]], i32 noundef 0, i32 noundef -1, i32 noundef 54, i32 noundef 0, ptr noundef @B.str) |
| 55 | + // CHECK-NEXT: %[[Ptr_Tmp2_3:.*]] = getelementptr [4 x %"class.hlsl::RWBuffer"], ptr %[[Tmp2]], i32 0, i32 3 |
| 56 | + // CHECK-NEXT: call void @_ZN4hlsl8RWBufferIiEC1EjijjPKc(ptr {{.*}} %[[Ptr_Tmp2_3]], i32 noundef 0, i32 noundef -1, i32 noundef 55, i32 noundef 0, ptr noundef @B.str) |
| 57 | + // DXIL-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 %[[Tmp1]], ptr align 4 %[[Tmp2]], i32 16, i1 false) |
| 58 | + // SPV-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %[[Tmp1]], ptr align 8 %[[Tmp2]], i64 32, i1 false) |
| 59 | + // CHECK-NEXT: %[[GI:.*]] = load i32, ptr %[[GI_alloca]], align 4 |
| 60 | + // DXIL-NEXT: %[[Value2:.*]] = call {{.*}} float @_Z3fooA4_N4hlsl8RWBufferIiEEj(ptr noundef byval([4 x %"class.hlsl::RWBuffer"]) align 4 %[[Tmp1]], i32 noundef %[[GI]]) |
| 61 | + // SPV-NEXT: %[[Value2:.*]] = call {{.*}} float @_Z3fooA4_N4hlsl8RWBufferIiEEj(ptr noundef byval([4 x %"class.hlsl::RWBuffer"]) align 8 %[[Tmp1]], i32 noundef %[[GI]]) |
| 62 | + // CHECK-NEXT: store float %[[Value2]], ptr %b, align 4 |
| 63 | + float b = foo(B[2][3], GI); |
| 64 | + |
| 65 | + Out[0] = a + b; |
| 66 | +} |
0 commit comments