xref: /llvm-project/clang/test/CodeGenHLSL/BasicFeatures/ArrayOutputArguments.hlsl (revision 46de3a7064250bd2dfc7f8dc6e300474afa9fa97)
1// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -disable-llvm-passes -emit-llvm -finclude-default-header -o - %s | FileCheck %s
2
3// CHECK-LABEL: increment
4void increment(inout int Arr[2]) {
5  for (int I = 0; I < 2; I++)
6    Arr[0] += 2;
7}
8
9// CHECK-LABEL: arrayCall
10// CHECK: [[A:%.*]] = alloca [2 x i32], align 4
11// CHECK-NEXT: [[Tmp:%.*]] = alloca [2 x i32], align 4
12// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[A]], ptr align 4 @{{.*}}, i32 8, i1 false)
13// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Tmp]], ptr align 4 [[A]], i32 8, i1 false)
14// CHECK-NEXT: call void @{{.*}}increment{{.*}}(ptr noalias noundef byval([2 x i32]) align 4 [[Tmp]]) #3
15// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[A]], ptr align 4 [[Tmp]], i32 8, i1 false)
16// CHECK-NEXT: [[Idx:%.*]] = getelementptr inbounds [2 x i32], ptr [[A]], i32 0, i32 0
17// CHECK-NEXT: [[B:%.*]] = load i32, ptr [[Idx]], align 4
18// CHECK-NEXT: ret i32 [[B]]
19export int arrayCall() {
20  int A[2] = { 0, 1 };
21  increment(A);
22  return A[0];
23}
24
25// CHECK-LABEL: fn2
26void fn2(out int Arr[2]) {
27  Arr[0] += 5;
28  Arr[1] += 6;
29}
30
31// CHECK-LABEL: arrayCall2
32// CHECK: [[A:%.*]] = alloca [2 x i32], align 4
33// CHECK-NEXT: [[Tmp:%.*]] = alloca [2 x i32], align 4
34// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[A]], ptr align 4 @{{.*}}, i32 8, i1 false)
35// CHECK-NEXT: call void @{{.*}}fn2{{.*}}(ptr noalias noundef byval([2 x i32]) align 4 [[Tmp]]) #3
36// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[A]], ptr align 4 [[Tmp]], i32 8, i1 false)
37// CHECK-NEXT: [[Idx:%.*]] = getelementptr inbounds [2 x i32], ptr [[A]], i32 0, i32 0
38// CHECK-NEXT: [[B:%.*]] = load i32, ptr [[Idx]], align 4
39// CHECK-NEXT: ret i32 [[B]]
40export int arrayCall2() {
41  int A[2] = { 0, 1 };
42  fn2(A);
43  return A[0];
44}
45
46// CHECK-LABEL: nestedCall
47void nestedCall(inout int Arr[2], uint index) {
48  if (index < 2) {
49    Arr[index] += 2;
50    nestedCall(Arr, index+1);
51  }
52}
53
54// CHECK-LABEL: arrayCall3
55// CHECK: [[A:%.*]] = alloca [2 x i32], align 4
56// CHECK-NEXT: [[Tmp:%.*]] = alloca [2 x i32], align 4
57// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[A]], ptr align 4 @{{.*}}, i32 8, i1 false)
58// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Tmp]], ptr align 4 [[A]], i32 8, i1 false)
59// CHECK-NEXT: call void @{{.*}}nestedCall{{.*}}(ptr noalias noundef byval([2 x i32]) align 4 [[Tmp]], i32 noundef 0) #3
60// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[A]], ptr align 4 [[Tmp]], i32 8, i1 false)
61// CHECK-NEXT: [[Idx:%.*]] = getelementptr inbounds [2 x i32], ptr [[A]], i32 0, i32 1
62// CHECK-NEXT: [[B:%.*]] = load i32, ptr [[Idx]], align 4
63// CHECK-NEXt: ret i32 [[B]]
64export int arrayCall3() {
65  int A[2] = { 0, 1 };
66  nestedCall(A, 0);
67  return A[1];
68}
69
70// CHECK-LABEL: outerCall
71// CHECK: [[Tmp:%.*]] = alloca [2 x i32], align 4
72// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Tmp]], ptr align 4 %{{.*}}, i32 8, i1 false)
73// CHECK-NEXT: call void {{.*}}increment{{.*}}(ptr noalias noundef byval([2 x i32]) align 4 [[Tmp]]) #3
74// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 {{.*}}, ptr align 4 [[Tmp]], i32 8, i1 false)
75// CHECK-NEXT: ret void
76void outerCall(inout int Arr[2]) {
77  increment(Arr);
78}
79
80// CHECK-LABEL: arrayCall4
81// CHECK: [[A:%.*]] = alloca [2 x i32], align 4
82// CHECK-NEXT: [[Tmp:%.*]] = alloca [2 x i32], align 4
83// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[A]], ptr align 4 @{{.*}}, i32 8, i1 false)
84// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Tmp]], ptr align 4 [[A]], i32 8, i1 false)
85// CHECK-NEXT: call void @{{.*}}outerCall{{.*}}(ptr noalias noundef byval([2 x i32]) align 4 [[Tmp]]) #3
86// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[A]], ptr align 4 [[Tmp]], i32 8, i1 false)
87// CHECK-NEXT: [[Idx:%.*]] = getelementptr inbounds [2 x i32], ptr [[A]], i32 0, i32 0
88// CHECK-NEXT: [[B:%.*]] = load i32, ptr [[Idx]], align 4
89// CHECK-NEXT: ret i32 [[B]]
90export int arrayCall4() {
91  int A[2] = { 0, 1 };
92  outerCall(A);
93  return A[0];
94}
95
96// CHECK-LABEL: fn3
97void fn3(int Arr[2]) {}
98
99// CHECK-LABEL: outerCall2
100// CHECK: [[Tmp:%.*]] = alloca [2 x i32], align 4
101// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Tmp]], ptr align 4 {{.*}}, i32 8, i1 false)
102// CHECK-NEXT: call void {{.*}}fn3{{.*}}(ptr noundef byval([2 x i32]) align 4 [[Tmp]]) #3
103// CHECK-NEXT: ret void
104void outerCall2(inout int Arr[2]) {
105  fn3(Arr);
106}
107
108// CHECK-LABEL: arrayCall5
109// CHECK: [[A:%.*]] = alloca [2 x i32], align 4
110// CHECK-NEXT: [[Tmp:%.*]] = alloca [2 x i32], align 4
111// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[A]], ptr align 4 @{{.*}}, i32 8, i1 false)
112// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Tmp]], ptr align 4 [[A]], i32 8, i1 false)
113// CHECK-NEXT: call void @{{.*}}outerCall2{{.*}}(ptr noalias noundef byval([2 x i32]) align 4 [[Tmp]]) #3
114// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[A]], ptr align 4 [[Tmp]], i32 8, i1 false)
115// CHECK-NEXT: [[Idx:%.*]] = getelementptr inbounds [2 x i32], ptr [[A]], i32 0, i32 0
116// CHECK-NEXT: [[B:%.*]] = load i32, ptr [[Idx]], align 4
117// CHECK-NEXT: ret i32 [[B]]
118export int arrayCall5() {
119  int A[2] = { 0, 1 };
120  outerCall2(A);
121  return A[0];
122}
123