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
14define void @callee_56_copy([7 x i64] %a, %S_56* %b) #0 { ret void }
15define void @callee_64_copy([8 x i64] %a, %S_64* %b) #0 { ret void }
16
17; Function Attrs: nounwind
18define 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
27define 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
35define void @callee_64_64_copy([8 x i64] %a, [8 x i64] %b) #0 { ret void }
36define 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
44define internal fastcc void @callee_64_64_copy_fastcc([8 x i64] %a, [8 x i64] %b) #0 { ret void }
45define 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
53define 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
61define 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
69define 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
76define void @arg8_caller(float %a, i32 signext %b, i8 zeroext %c, i32* %d) {
77entry:
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
90define void @callee_sret_56(%S_56* noalias sret %agg.result) #0 { ret void }
91define void @callee_sret_32(%S_32* noalias sret %agg.result) #0 { ret void }
92
93; Function Attrs: nounwind
94define 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
108define 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
117attributes #0 = { noinline nounwind  }
118attributes #1 = { nounwind }
119
120; vector <4 x i1> test
121
122define void @callee_v4i1(i8 %a, <4 x i1> %b, <4 x i1> %c) { ret void }
123define 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
137define void @f128_callee(i32* %ptr, ppc_fp128 %a, ppc_fp128 %b) { ret void }
138define 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
149define weak_odr hidden void @wo_hcallee(%class.T* %this, i8* %c) { ret void }
150define 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
161define weak_odr protected void @wo_pcallee(%class.T* %this, i8* %c) { ret void }
162define 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
173define weak_odr void @wo_callee(%class.T* %this, i8* %c) { ret void }
174define 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
185define weak protected void @w_pcallee(i8* %ptr) { ret void }
186define 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
197define weak hidden void @w_hcallee(i8* %ptr) { ret void }
198define 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
209define weak void @w_callee(i8* %ptr) { ret void }
210define 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
224define void @byval_callee(%struct.byvalTest* byval %ptr) { ret void }
225define 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