1 ; RUN: llc < %s -relocation-model=static -O1 -disable-ppc-sco=false -verify-machineinstrs -mtriple=powerpc64-unknown-linux-gnu | FileCheck %s -check-prefix=CHECK-SCO 2 ; RUN: llc < %s -relocation-model=static -O1 -disable-ppc-sco=false -verify-machineinstrs -mtriple=powerpc64-unknown-linux-gnu -mcpu=pwr8 | FileCheck %s -check-prefix=CHECK-SCO-HASQPX 3 ; RUN: llc < %s -relocation-model=static -O1 -disable-ppc-sco=false -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu -mcpu=pwr8 | FileCheck %s -check-prefix=CHECK-SCO-HASQPX 4 ; RUN: llc < %s -relocation-model=static -O1 -disable-ppc-sco=false -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu -mcpu=pwr8 -code-model=small | FileCheck %s -check-prefix=SCM 5 6 ; No combination of "powerpc64le-unknown-linux-gnu" + "CHECK-SCO", because 7 ; only Power8 (and later) fully support LE. 8 9 %S_56 = type { [13 x i32], i32 } 10 %S_64 = type { [15 x i32], i32 } 11 %S_32 = type { [7 x i32], i32 } 12 13 ; Function Attrs: noinline nounwind 14 define void @callee_56_copy([7 x i64] %a, %S_56* %b) #0 { ret void } 15 define void @callee_64_copy([8 x i64] %a, %S_64* %b) #0 { ret void } 16 17 ; Function Attrs: nounwind 18 define void @caller_56_reorder_copy(%S_56* %b, [7 x i64] %a) #1 { 19 tail call void @callee_56_copy([7 x i64] %a, %S_56* %b) 20 ret void 21 22 ; CHECK-SCO-LABEL: caller_56_reorder_copy: 23 ; CHECK-SCO-NOT: stdu 1 24 ; CHECK-SCO: TC_RETURNd8 callee_56_copy 25 } 26 27 define void @caller_64_reorder_copy(%S_64* %b, [8 x i64] %a) #1 { 28 tail call void @callee_64_copy([8 x i64] %a, %S_64* %b) 29 ret void 30 31 ; CHECK-SCO-LABEL: caller_64_reorder_copy: 32 ; CHECK-SCO: bl callee_64_copy 33 } 34 35 define void @callee_64_64_copy([8 x i64] %a, [8 x i64] %b) #0 { ret void } 36 define void @caller_64_64_copy([8 x i64] %a, [8 x i64] %b) #1 { 37 tail call void @callee_64_64_copy([8 x i64] %a, [8 x i64] %b) 38 ret void 39 40 ; CHECK-SCO-LABEL: caller_64_64_copy: 41 ; CHECK-SCO: b callee_64_64_copy 42 } 43 44 define internal fastcc void @callee_64_64_copy_fastcc([8 x i64] %a, [8 x i64] %b) #0 { ret void } 45 define void @caller_64_64_copy_ccc([8 x i64] %a, [8 x i64] %b) #1 { 46 tail call fastcc void @callee_64_64_copy_fastcc([8 x i64] %a, [8 x i64] %b) 47 ret void 48 ; If caller and callee use different calling convensions, we cannot apply TCO. 49 ; CHECK-SCO-LABEL: caller_64_64_copy_ccc: 50 ; CHECK-SCO: bl callee_64_64_copy_fastcc 51 } 52 53 define void @caller_64_64_reorder_copy([8 x i64] %a, [8 x i64] %b) #1 { 54 tail call void @callee_64_64_copy([8 x i64] %b, [8 x i64] %a) 55 ret void 56 57 ; CHECK-SCO-LABEL: caller_64_64_reorder_copy: 58 ; CHECK-SCO: bl callee_64_64_copy 59 } 60 61 define void @caller_64_64_undef_copy([8 x i64] %a, [8 x i64] %b) #1 { 62 tail call void @callee_64_64_copy([8 x i64] %a, [8 x i64] undef) 63 ret void 64 65 ; CHECK-SCO-LABEL: caller_64_64_undef_copy: 66 ; CHECK-SCO: b callee_64_64_copy 67 } 68 69 define void @arg8_callee( 70 float %a, i32 signext %b, float %c, i32* %d, 71 i8 zeroext %e, float %f, i32* %g, i32 signext %h) 72 { 73 ret void 74 } 75 76 define void @arg8_caller(float %a, i32 signext %b, i8 zeroext %c, i32* %d) { 77 entry: 78 tail call void @arg8_callee(float undef, i32 signext undef, float undef, 79 i32* %d, i8 zeroext undef, float undef, 80 i32* undef, i32 signext undef) 81 ret void 82 83 ; CHECK-SCO-LABEL: arg8_caller: 84 ; CHECK-SCO: b arg8_callee 85 } 86 87 ; Struct return test 88 89 ; Function Attrs: noinline nounwind 90 define void @callee_sret_56(%S_56* noalias sret %agg.result) #0 { ret void } 91 define void @callee_sret_32(%S_32* noalias sret %agg.result) #0 { ret void } 92 93 ; Function Attrs: nounwind 94 define void @caller_do_something_sret_32(%S_32* noalias sret %agg.result) #1 { 95 %1 = alloca %S_56, align 4 96 %2 = bitcast %S_56* %1 to i8* 97 call void @callee_sret_56(%S_56* nonnull sret %1) 98 tail call void @callee_sret_32(%S_32* sret %agg.result) 99 ret void 100 101 ; CHECK-SCO-LABEL: caller_do_something_sret_32: 102 ; CHECK-SCO: stdu 1 103 ; CHECK-SCO: bl callee_sret_56 104 ; CHECK-SCO: addi 1 105 ; CHECK-SCO: TC_RETURNd8 callee_sret_32 106 } 107 108 define void @caller_local_sret_32(%S_32* %a) #1 { 109 %tmp = alloca %S_32, align 4 110 tail call void @callee_sret_32(%S_32* nonnull sret %tmp) 111 ret void 112 113 ; CHECK-SCO-LABEL: caller_local_sret_32: 114 ; CHECK-SCO: bl callee_sret_32 115 } 116 117 attributes #0 = { noinline nounwind } 118 attributes #1 = { nounwind } 119 120 ; vector <4 x i1> test 121 122 define void @callee_v4i1(i8 %a, <4 x i1> %b, <4 x i1> %c) { ret void } 123 define void @caller_v4i1_reorder(i8 %a, <4 x i1> %b, <4 x i1> %c) { 124 tail call void @callee_v4i1(i8 %a, <4 x i1> %c, <4 x i1> %b) 125 ret void 126 127 ; <4 x i1> is 32 bytes aligned, if subtarget doesn't support qpx, then we can't 128 ; place b, c to qpx register, so we can't do sco on caller_v4i1_reorder 129 130 ; CHECK-SCO-LABEL: caller_v4i1_reorder: 131 ; CHECK-SCO: bl callee_v4i1 132 133 ; CHECK-SCO-HASQPX-LABEL: caller_v4i1_reorder: 134 ; CHECK-SCO-HASQPX: b callee_v4i1 135 } 136 137 define void @f128_callee(i32* %ptr, ppc_fp128 %a, ppc_fp128 %b) { ret void } 138 define void @f128_caller(i32* %ptr, ppc_fp128 %a, ppc_fp128 %b) { 139 tail call void @f128_callee(i32* %ptr, ppc_fp128 %a, ppc_fp128 %b) 140 ret void 141 142 ; CHECK-SCO-LABEL: f128_caller: 143 ; CHECK-SCO: b f128_callee 144 } 145 146 ; weak linkage test 147 %class.T = type { [2 x i8] } 148 149 define weak_odr hidden void @wo_hcallee(%class.T* %this, i8* %c) { ret void } 150 define void @wo_hcaller(%class.T* %this, i8* %c) { 151 tail call void @wo_hcallee(%class.T* %this, i8* %c) 152 ret void 153 154 ; CHECK-SCO-LABEL: wo_hcaller: 155 ; CHECK-SCO: b wo_hcallee 156 157 ; SCM-LABEL: wo_hcaller: 158 ; SCM: bl wo_hcallee 159 } 160 161 define weak_odr protected void @wo_pcallee(%class.T* %this, i8* %c) { ret void } 162 define void @wo_pcaller(%class.T* %this, i8* %c) { 163 tail call void @wo_pcallee(%class.T* %this, i8* %c) 164 ret void 165 166 ; CHECK-SCO-LABEL: wo_pcaller: 167 ; CHECK-SCO: b wo_pcallee 168 169 ; SCM-LABEL: wo_pcaller: 170 ; SCM: bl wo_pcallee 171 } 172 173 define weak_odr void @wo_callee(%class.T* %this, i8* %c) { ret void } 174 define void @wo_caller(%class.T* %this, i8* %c) { 175 tail call void @wo_callee(%class.T* %this, i8* %c) 176 ret void 177 178 ; CHECK-SCO-LABEL: wo_caller: 179 ; CHECK-SCO: b wo_callee 180 181 ; SCM-LABEL: wo_caller: 182 ; SCM: bl wo_callee 183 } 184 185 define weak protected void @w_pcallee(i8* %ptr) { ret void } 186 define void @w_pcaller(i8* %ptr) { 187 tail call void @w_pcallee(i8* %ptr) 188 ret void 189 190 ; CHECK-SCO-LABEL: w_pcaller: 191 ; CHECK-SCO: b w_pcallee 192 193 ; SCM-LABEL: w_pcaller: 194 ; SCM: bl w_pcallee 195 } 196 197 define weak hidden void @w_hcallee(i8* %ptr) { ret void } 198 define void @w_hcaller(i8* %ptr) { 199 tail call void @w_hcallee(i8* %ptr) 200 ret void 201 202 ; CHECK-SCO-LABEL: w_hcaller: 203 ; CHECK-SCO: b w_hcallee 204 205 ; SCM-LABEL: w_hcaller: 206 ; SCM: bl w_hcallee 207 } 208 209 define weak void @w_callee(i8* %ptr) { ret void } 210 define void @w_caller(i8* %ptr) { 211 tail call void @w_callee(i8* %ptr) 212 ret void 213 214 ; CHECK-SCO-LABEL: w_caller: 215 ; CHECK-SCO: b w_callee 216 217 ; SCM-LABEL: w_caller: 218 ; SCM: bl w_callee 219 } 220 221 %struct.byvalTest = type { [8 x i8] } 222 @byval = common global %struct.byvalTest zeroinitializer 223 224 define void @byval_callee(%struct.byvalTest* byval %ptr) { ret void } 225 define void @byval_caller() { 226 tail call void @byval_callee(%struct.byvalTest* byval @byval) 227 ret void 228 229 ; CHECK-SCO-LABEL: bl byval_callee 230 ; CHECK-SCO: bl byval_callee 231 } 232