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