1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-globals
2; RUN: opt -S -mtriple=amdgcn-amd- -amdgpu-annotate-kernel-features %s | FileCheck --allow-unused-prefixes -check-prefixes=CHECK,AKF_CHECK %s
3; RUN: opt -S -mtriple=amdgcn-amd- -amdgpu-attributor %s | FileCheck --allow-unused-prefixes -check-prefixes=CHECK,ATTRIBUTOR_CHECK %s
4
5; Test to ensure recursive functions exhibit proper behaviour
6; Test to generate fibonacci numbers
7
8define i32 @fib(i32 %n) #0 {
9; AKF_CHECK-LABEL: define {{[^@]+}}@fib
10; AKF_CHECK-SAME: (i32 [[N:%.*]]) #[[ATTR0:[0-9]+]] {
11; AKF_CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i32 [[N]], 0
12; AKF_CHECK-NEXT:    br i1 [[CMP1]], label [[EXIT:%.*]], label [[CONT1:%.*]]
13; AKF_CHECK:       cont1:
14; AKF_CHECK-NEXT:    [[CMP2:%.*]] = icmp eq i32 [[N]], 1
15; AKF_CHECK-NEXT:    br i1 [[CMP2]], label [[EXIT]], label [[CONT2:%.*]]
16; AKF_CHECK:       cont2:
17; AKF_CHECK-NEXT:    [[NM1:%.*]] = sub i32 [[N]], 1
18; AKF_CHECK-NEXT:    [[FIBM1:%.*]] = call i32 @fib(i32 [[NM1]])
19; AKF_CHECK-NEXT:    [[NM2:%.*]] = sub i32 [[N]], 2
20; AKF_CHECK-NEXT:    [[FIBM2:%.*]] = call i32 @fib(i32 [[NM2]])
21; AKF_CHECK-NEXT:    [[RETVAL:%.*]] = add i32 [[FIBM1]], [[FIBM2]]
22; AKF_CHECK-NEXT:    ret i32 [[RETVAL]]
23; AKF_CHECK:       exit:
24; AKF_CHECK-NEXT:    ret i32 1
25;
26; ATTRIBUTOR_CHECK-LABEL: define {{[^@]+}}@fib
27; ATTRIBUTOR_CHECK-SAME: (i32 [[N:%.*]]) #[[ATTR0:[0-9]+]] {
28; ATTRIBUTOR_CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i32 [[N]], 0
29; ATTRIBUTOR_CHECK-NEXT:    br i1 [[CMP1]], label [[EXIT:%.*]], label [[CONT1:%.*]]
30; ATTRIBUTOR_CHECK:       cont1:
31; ATTRIBUTOR_CHECK-NEXT:    [[CMP2:%.*]] = icmp eq i32 [[N]], 1
32; ATTRIBUTOR_CHECK-NEXT:    br i1 [[CMP2]], label [[EXIT]], label [[CONT2:%.*]]
33; ATTRIBUTOR_CHECK:       cont2:
34; ATTRIBUTOR_CHECK-NEXT:    [[NM1:%.*]] = sub i32 [[N]], 1
35; ATTRIBUTOR_CHECK-NEXT:    [[FIBM1:%.*]] = call i32 @fib(i32 [[NM1]]) #[[ATTR3:[0-9]+]]
36; ATTRIBUTOR_CHECK-NEXT:    [[NM2:%.*]] = sub i32 [[N]], 2
37; ATTRIBUTOR_CHECK-NEXT:    [[FIBM2:%.*]] = call i32 @fib(i32 [[NM2]]) #[[ATTR3]]
38; ATTRIBUTOR_CHECK-NEXT:    [[RETVAL:%.*]] = add i32 [[FIBM1]], [[FIBM2]]
39; ATTRIBUTOR_CHECK-NEXT:    ret i32 [[RETVAL]]
40; ATTRIBUTOR_CHECK:       exit:
41; ATTRIBUTOR_CHECK-NEXT:    ret i32 1
42;
43  %cmp1 = icmp eq i32 %n, 0
44  br i1 %cmp1, label %exit, label %cont1
45
46cont1:
47  %cmp2 = icmp eq i32 %n, 1
48  br i1 %cmp2, label %exit, label %cont2
49
50cont2:
51  %nm1 = sub i32 %n, 1
52  %fibm1 = call i32 @fib(i32 %nm1)
53  %nm2 = sub i32 %n, 2
54  %fibm2 = call i32 @fib(i32 %nm2)
55  %retval = add i32 %fibm1, %fibm2
56
57  ret i32 %retval
58
59exit:
60  ret i32 1
61}
62
63define internal i32 @fib_internal(i32 %n) #0 {
64; AKF_CHECK-LABEL: define {{[^@]+}}@fib_internal
65; AKF_CHECK-SAME: (i32 [[N:%.*]]) #[[ATTR0]] {
66; AKF_CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i32 [[N]], 0
67; AKF_CHECK-NEXT:    br i1 [[CMP1]], label [[EXIT:%.*]], label [[CONT1:%.*]]
68; AKF_CHECK:       cont1:
69; AKF_CHECK-NEXT:    [[CMP2:%.*]] = icmp eq i32 [[N]], 1
70; AKF_CHECK-NEXT:    br i1 [[CMP2]], label [[EXIT]], label [[CONT2:%.*]]
71; AKF_CHECK:       cont2:
72; AKF_CHECK-NEXT:    [[NM1:%.*]] = sub i32 [[N]], 1
73; AKF_CHECK-NEXT:    [[FIBM1:%.*]] = call i32 @fib_internal(i32 [[NM1]])
74; AKF_CHECK-NEXT:    [[NM2:%.*]] = sub i32 [[N]], 2
75; AKF_CHECK-NEXT:    [[FIBM2:%.*]] = call i32 @fib_internal(i32 [[NM2]])
76; AKF_CHECK-NEXT:    [[RETVAL:%.*]] = add i32 [[FIBM1]], [[FIBM2]]
77; AKF_CHECK-NEXT:    ret i32 [[RETVAL]]
78; AKF_CHECK:       exit:
79; AKF_CHECK-NEXT:    ret i32 1
80;
81; ATTRIBUTOR_CHECK-LABEL: define {{[^@]+}}@fib_internal
82; ATTRIBUTOR_CHECK-SAME: (i32 [[N:%.*]]) #[[ATTR1:[0-9]+]] {
83; ATTRIBUTOR_CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i32 [[N]], 0
84; ATTRIBUTOR_CHECK-NEXT:    br i1 [[CMP1]], label [[EXIT:%.*]], label [[CONT1:%.*]]
85; ATTRIBUTOR_CHECK:       cont1:
86; ATTRIBUTOR_CHECK-NEXT:    [[CMP2:%.*]] = icmp eq i32 [[N]], 1
87; ATTRIBUTOR_CHECK-NEXT:    br i1 [[CMP2]], label [[EXIT]], label [[CONT2:%.*]]
88; ATTRIBUTOR_CHECK:       cont2:
89; ATTRIBUTOR_CHECK-NEXT:    [[NM1:%.*]] = sub i32 [[N]], 1
90; ATTRIBUTOR_CHECK-NEXT:    [[FIBM1:%.*]] = call i32 @fib_internal(i32 [[NM1]]) #[[ATTR4:[0-9]+]]
91; ATTRIBUTOR_CHECK-NEXT:    [[NM2:%.*]] = sub i32 [[N]], 2
92; ATTRIBUTOR_CHECK-NEXT:    [[FIBM2:%.*]] = call i32 @fib_internal(i32 [[NM2]]) #[[ATTR4]]
93; ATTRIBUTOR_CHECK-NEXT:    [[RETVAL:%.*]] = add i32 [[FIBM1]], [[FIBM2]]
94; ATTRIBUTOR_CHECK-NEXT:    ret i32 [[RETVAL]]
95; ATTRIBUTOR_CHECK:       exit:
96; ATTRIBUTOR_CHECK-NEXT:    ret i32 1
97;
98  %cmp1 = icmp eq i32 %n, 0
99  br i1 %cmp1, label %exit, label %cont1
100
101cont1:
102  %cmp2 = icmp eq i32 %n, 1
103  br i1 %cmp2, label %exit, label %cont2
104
105cont2:
106  %nm1 = sub i32 %n, 1
107  %fibm1 = call i32 @fib_internal(i32 %nm1)
108  %nm2 = sub i32 %n, 2
109  %fibm2 = call i32 @fib_internal(i32 %nm2)
110  %retval = add i32 %fibm1, %fibm2
111
112  ret i32 %retval
113
114exit:
115  ret i32 1
116}
117
118define amdgpu_kernel void @kernel(i32 addrspace(1)* %m) #1 {
119; AKF_CHECK-LABEL: define {{[^@]+}}@kernel
120; AKF_CHECK-SAME: (i32 addrspace(1)* [[M:%.*]]) #[[ATTR1:[0-9]+]] {
121; AKF_CHECK-NEXT:    [[R:%.*]] = call i32 @fib(i32 5)
122; AKF_CHECK-NEXT:    [[R2:%.*]] = call i32 @fib_internal(i32 5)
123; AKF_CHECK-NEXT:    store i32 [[R]], i32 addrspace(1)* [[M]], align 4
124; AKF_CHECK-NEXT:    store i32 [[R2]], i32 addrspace(1)* [[M]], align 4
125; AKF_CHECK-NEXT:    ret void
126;
127; ATTRIBUTOR_CHECK-LABEL: define {{[^@]+}}@kernel
128; ATTRIBUTOR_CHECK-SAME: (i32 addrspace(1)* [[M:%.*]]) #[[ATTR2:[0-9]+]] {
129; ATTRIBUTOR_CHECK-NEXT:    [[R:%.*]] = call i32 @fib(i32 5) #[[ATTR3]]
130; ATTRIBUTOR_CHECK-NEXT:    [[R2:%.*]] = call i32 @fib_internal(i32 noundef 5) #[[ATTR3]]
131; ATTRIBUTOR_CHECK-NEXT:    store i32 [[R]], i32 addrspace(1)* [[M]], align 4
132; ATTRIBUTOR_CHECK-NEXT:    store i32 [[R2]], i32 addrspace(1)* [[M]], align 4
133; ATTRIBUTOR_CHECK-NEXT:    ret void
134;
135  %r = call i32 @fib(i32 5)
136  %r2 = call i32 @fib_internal(i32 5)
137
138  store i32 %r, i32 addrspace(1)* %m
139  store i32 %r2, i32 addrspace(1)* %m
140  ret void
141}
142
143; nounwind and readnone are added to match attributor results.
144attributes #0 = { nounwind readnone }
145attributes #1 = { "uniform-work-group-size"="true" }
146
147;.
148; AKF_CHECK: attributes #[[ATTR0]] = { nounwind readnone "uniform-work-group-size"="true" }
149; AKF_CHECK: attributes #[[ATTR1]] = { "amdgpu-calls" "uniform-work-group-size"="true" }
150;.
151; ATTRIBUTOR_CHECK: attributes #[[ATTR0]] = { nounwind readnone "uniform-work-group-size"="false" }
152; ATTRIBUTOR_CHECK: attributes #[[ATTR1]] = { nofree nosync nounwind readnone "uniform-work-group-size"="true" }
153; ATTRIBUTOR_CHECK: attributes #[[ATTR2]] = { "amdgpu-calls" "uniform-work-group-size"="true" }
154; ATTRIBUTOR_CHECK: attributes #[[ATTR3]] = { nounwind readnone }
155; ATTRIBUTOR_CHECK: attributes #[[ATTR4]] = { nofree nounwind readnone }
156;.
157