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; CHECK-LABEL: define {{[^@]+}}@fib
10; CHECK-SAME: (i32 [[N:%.*]]) #[[ATTR0:[0-9]+]] {
11; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i32 [[N]], 0
12; CHECK-NEXT:    br i1 [[CMP1]], label [[EXIT:%.*]], label [[CONT1:%.*]]
13; CHECK:       cont1:
14; CHECK-NEXT:    [[CMP2:%.*]] = icmp eq i32 [[N]], 1
15; CHECK-NEXT:    br i1 [[CMP2]], label [[EXIT]], label [[CONT2:%.*]]
16; CHECK:       cont2:
17; CHECK-NEXT:    [[NM1:%.*]] = sub i32 [[N]], 1
18; CHECK-NEXT:    [[FIBM1:%.*]] = call i32 @fib(i32 [[NM1]])
19; CHECK-NEXT:    [[NM2:%.*]] = sub i32 [[N]], 2
20; CHECK-NEXT:    [[FIBM2:%.*]] = call i32 @fib(i32 [[NM2]])
21; CHECK-NEXT:    [[RETVAL:%.*]] = add i32 [[FIBM1]], [[FIBM2]]
22; CHECK-NEXT:    ret i32 [[RETVAL]]
23; CHECK:       exit:
24; CHECK-NEXT:    ret i32 1
25;
26  %cmp1 = icmp eq i32 %n, 0
27  br i1 %cmp1, label %exit, label %cont1
28
29cont1:
30  %cmp2 = icmp eq i32 %n, 1
31  br i1 %cmp2, label %exit, label %cont2
32
33cont2:
34  %nm1 = sub i32 %n, 1
35  %fibm1 = call i32 @fib(i32 %nm1)
36  %nm2 = sub i32 %n, 2
37  %fibm2 = call i32 @fib(i32 %nm2)
38  %retval = add i32 %fibm1, %fibm2
39
40  ret i32 %retval
41
42exit:
43  ret i32 1
44}
45
46define internal i32 @fib_internal(i32 %n) #0 {
47; AKF_CHECK-LABEL: define {{[^@]+}}@fib_internal
48; AKF_CHECK-SAME: (i32 [[N:%.*]]) #[[ATTR0]] {
49; AKF_CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i32 [[N]], 0
50; AKF_CHECK-NEXT:    br i1 [[CMP1]], label [[EXIT:%.*]], label [[CONT1:%.*]]
51; AKF_CHECK:       cont1:
52; AKF_CHECK-NEXT:    [[CMP2:%.*]] = icmp eq i32 [[N]], 1
53; AKF_CHECK-NEXT:    br i1 [[CMP2]], label [[EXIT]], label [[CONT2:%.*]]
54; AKF_CHECK:       cont2:
55; AKF_CHECK-NEXT:    [[NM1:%.*]] = sub i32 [[N]], 1
56; AKF_CHECK-NEXT:    [[FIBM1:%.*]] = call i32 @fib_internal(i32 [[NM1]])
57; AKF_CHECK-NEXT:    [[NM2:%.*]] = sub i32 [[N]], 2
58; AKF_CHECK-NEXT:    [[FIBM2:%.*]] = call i32 @fib_internal(i32 [[NM2]])
59; AKF_CHECK-NEXT:    [[RETVAL:%.*]] = add i32 [[FIBM1]], [[FIBM2]]
60; AKF_CHECK-NEXT:    ret i32 [[RETVAL]]
61; AKF_CHECK:       exit:
62; AKF_CHECK-NEXT:    ret i32 1
63;
64; ATTRIBUTOR_CHECK-LABEL: define {{[^@]+}}@fib_internal
65; ATTRIBUTOR_CHECK-SAME: (i32 [[N:%.*]]) #[[ATTR1:[0-9]+]] {
66; ATTRIBUTOR_CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i32 [[N]], 0
67; ATTRIBUTOR_CHECK-NEXT:    br i1 [[CMP1]], label [[EXIT:%.*]], label [[CONT1:%.*]]
68; ATTRIBUTOR_CHECK:       cont1:
69; ATTRIBUTOR_CHECK-NEXT:    [[CMP2:%.*]] = icmp eq i32 [[N]], 1
70; ATTRIBUTOR_CHECK-NEXT:    br i1 [[CMP2]], label [[EXIT]], label [[CONT2:%.*]]
71; ATTRIBUTOR_CHECK:       cont2:
72; ATTRIBUTOR_CHECK-NEXT:    [[NM1:%.*]] = sub i32 [[N]], 1
73; ATTRIBUTOR_CHECK-NEXT:    [[FIBM1:%.*]] = call i32 @fib_internal(i32 [[NM1]])
74; ATTRIBUTOR_CHECK-NEXT:    [[NM2:%.*]] = sub i32 [[N]], 2
75; ATTRIBUTOR_CHECK-NEXT:    [[FIBM2:%.*]] = call i32 @fib_internal(i32 [[NM2]])
76; ATTRIBUTOR_CHECK-NEXT:    [[RETVAL:%.*]] = add i32 [[FIBM1]], [[FIBM2]]
77; ATTRIBUTOR_CHECK-NEXT:    ret i32 [[RETVAL]]
78; ATTRIBUTOR_CHECK:       exit:
79; ATTRIBUTOR_CHECK-NEXT:    ret i32 1
80;
81  %cmp1 = icmp eq i32 %n, 0
82  br i1 %cmp1, label %exit, label %cont1
83
84cont1:
85  %cmp2 = icmp eq i32 %n, 1
86  br i1 %cmp2, label %exit, label %cont2
87
88cont2:
89  %nm1 = sub i32 %n, 1
90  %fibm1 = call i32 @fib_internal(i32 %nm1)
91  %nm2 = sub i32 %n, 2
92  %fibm2 = call i32 @fib_internal(i32 %nm2)
93  %retval = add i32 %fibm1, %fibm2
94
95  ret i32 %retval
96
97exit:
98  ret i32 1
99}
100
101define amdgpu_kernel void @kernel(i32 addrspace(1)* %m) #1 {
102; AKF_CHECK-LABEL: define {{[^@]+}}@kernel
103; AKF_CHECK-SAME: (i32 addrspace(1)* [[M:%.*]]) #[[ATTR1:[0-9]+]] {
104; AKF_CHECK-NEXT:    [[R:%.*]] = call i32 @fib(i32 5)
105; AKF_CHECK-NEXT:    [[R2:%.*]] = call i32 @fib_internal(i32 5)
106; AKF_CHECK-NEXT:    store i32 [[R]], i32 addrspace(1)* [[M]], align 4
107; AKF_CHECK-NEXT:    store i32 [[R2]], i32 addrspace(1)* [[M]], align 4
108; AKF_CHECK-NEXT:    ret void
109;
110; ATTRIBUTOR_CHECK-LABEL: define {{[^@]+}}@kernel
111; ATTRIBUTOR_CHECK-SAME: (i32 addrspace(1)* [[M:%.*]]) #[[ATTR2:[0-9]+]] {
112; ATTRIBUTOR_CHECK-NEXT:    [[R:%.*]] = call i32 @fib(i32 5)
113; ATTRIBUTOR_CHECK-NEXT:    [[R2:%.*]] = call i32 @fib_internal(i32 5)
114; ATTRIBUTOR_CHECK-NEXT:    store i32 [[R]], i32 addrspace(1)* [[M]], align 4
115; ATTRIBUTOR_CHECK-NEXT:    store i32 [[R2]], i32 addrspace(1)* [[M]], align 4
116; ATTRIBUTOR_CHECK-NEXT:    ret void
117;
118  %r = call i32 @fib(i32 5)
119  %r2 = call i32 @fib_internal(i32 5)
120
121  store i32 %r, i32 addrspace(1)* %m
122  store i32 %r2, i32 addrspace(1)* %m
123  ret void
124}
125
126; nounwind and readnone are added to match attributor results.
127attributes #0 = { nounwind readnone }
128attributes #1 = { "uniform-work-group-size"="true" }
129
130;.
131; AKF_CHECK: attributes #[[ATTR0]] = { nounwind readnone "uniform-work-group-size"="true" }
132; AKF_CHECK: attributes #[[ATTR1]] = { "amdgpu-calls" "uniform-work-group-size"="true" }
133;.
134; ATTRIBUTOR_CHECK: attributes #[[ATTR0]] = { nounwind readnone "amdgpu-no-dispatch-id" "amdgpu-no-dispatch-ptr" "amdgpu-no-implicitarg-ptr" "amdgpu-no-queue-ptr" "amdgpu-no-workgroup-id-x" "amdgpu-no-workgroup-id-y" "amdgpu-no-workgroup-id-z" "amdgpu-no-workitem-id-x" "amdgpu-no-workitem-id-y" "amdgpu-no-workitem-id-z" "uniform-work-group-size"="false" }
135; ATTRIBUTOR_CHECK: attributes #[[ATTR1]] = { nounwind readnone "amdgpu-no-dispatch-id" "amdgpu-no-dispatch-ptr" "amdgpu-no-implicitarg-ptr" "amdgpu-no-queue-ptr" "amdgpu-no-workgroup-id-x" "amdgpu-no-workgroup-id-y" "amdgpu-no-workgroup-id-z" "amdgpu-no-workitem-id-x" "amdgpu-no-workitem-id-y" "amdgpu-no-workitem-id-z" "uniform-work-group-size"="true" }
136; ATTRIBUTOR_CHECK: attributes #[[ATTR2]] = { "amdgpu-no-dispatch-id" "amdgpu-no-dispatch-ptr" "amdgpu-no-implicitarg-ptr" "amdgpu-no-queue-ptr" "amdgpu-no-workgroup-id-x" "amdgpu-no-workgroup-id-y" "amdgpu-no-workgroup-id-z" "amdgpu-no-workitem-id-x" "amdgpu-no-workitem-id-y" "amdgpu-no-workitem-id-z" "uniform-work-group-size"="true" }
137;.
138