1; RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=fiji -mattr=-flat-for-global -enable-ipra=0 -amdgpu-sroa=0 -verify-machineinstrs < %s | FileCheck -enable-var-scope -check-prefixes=GCN,VI,CIVI,MESA %s
2; RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=hawaii -enable-ipra=0 -amdgpu-sroa=0 -verify-machineinstrs < %s | FileCheck -enable-var-scope -check-prefixes=GCN,CI,CIVI,MESA %s
3; RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx900 -mattr=-flat-for-global -enable-ipra=0 -amdgpu-sroa=0 -verify-machineinstrs < %s | FileCheck -enable-var-scope -check-prefixes=GCN,GFX9,MESA %s
4target datalayout = "A5"
5
6; FIXME: Why is this commuted only sometimes?
7; GCN-LABEL: {{^}}i32_fastcc_i32_i32:
8; GCN: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
9; CIVI-NEXT: v_add_{{i|u}}32_e32 v0, vcc, v0, v1
10; GFX9-NEXT: v_add_u32_e32 v0, v0, v1
11; GCN-NEXT: s_setpc_b64
12define fastcc i32 @i32_fastcc_i32_i32(i32 %arg0, i32 %arg1) #1 {
13  %add0 = add i32 %arg0, %arg1
14  ret i32 %add0
15}
16
17; GCN-LABEL: {{^}}i32_fastcc_i32_i32_stack_object:
18; GCN: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
19; GCN-NEXT: v_mov_b32_e32 [[K:v[0-9]+]], 9
20; CIVI-NEXT: v_add_{{i|u}}32_e32 v0, vcc, v0, v1
21; GFX9-NEXT: v_add_u32_e32 v0, v0, v1
22; GCN: buffer_store_dword [[K]], off, s[0:3], s32 offset:20
23; GCN: s_waitcnt vmcnt(0)
24; GCN: s_setpc_b64
25; GCN: ; ScratchSize: 68
26define fastcc i32 @i32_fastcc_i32_i32_stack_object(i32 %arg0, i32 %arg1) #1 {
27  %alloca = alloca [16 x i32], align 4, addrspace(5)
28  %gep = getelementptr inbounds [16 x i32], [16 x i32] addrspace(5)* %alloca, i32 0, i32 5
29  store volatile i32 9, i32 addrspace(5)* %gep
30  %add0 = add i32 %arg0, %arg1
31  ret i32 %add0
32}
33
34; GCN-LABEL: {{^}}sibling_call_i32_fastcc_i32_i32:
35define hidden fastcc i32 @sibling_call_i32_fastcc_i32_i32(i32 %a, i32 %b, i32 %c) #1 {
36entry:
37  %ret = tail call fastcc i32 @i32_fastcc_i32_i32(i32 %a, i32 %b)
38  ret i32 %ret
39}
40
41; GCN-LABEL: {{^}}sibling_call_i32_fastcc_i32_i32_stack_object:
42; GCN: v_mov_b32_e32 [[NINE:v[0-9]+]], 9
43; GCN: buffer_store_dword [[NINE]], off, s[0:3], s32 offset:20
44; GCN: s_setpc_b64
45; GCN: ; ScratchSize: 68
46define fastcc i32 @sibling_call_i32_fastcc_i32_i32_stack_object(i32 %a, i32 %b, i32 %c) #1 {
47entry:
48  %alloca = alloca [16 x i32], align 4, addrspace(5)
49  %gep = getelementptr inbounds [16 x i32], [16 x i32] addrspace(5)* %alloca, i32 0, i32 5
50  store volatile i32 9, i32 addrspace(5)* %gep
51  %ret = tail call fastcc i32 @i32_fastcc_i32_i32(i32 %a, i32 %b)
52  ret i32 %ret
53}
54
55; GCN-LABEL: {{^}}sibling_call_i32_fastcc_i32_i32_callee_stack_object:
56; GCN: v_mov_b32_e32 [[NINE:v[0-9]+]], 9
57; GCN: buffer_store_dword [[NINE]], off, s[0:3], s32 offset:20
58; GCN: s_setpc_b64
59; GCN: ; ScratchSize: 136
60define fastcc i32 @sibling_call_i32_fastcc_i32_i32_callee_stack_object(i32 %a, i32 %b, i32 %c) #1 {
61entry:
62  %alloca = alloca [16 x i32], align 4, addrspace(5)
63  %gep = getelementptr inbounds [16 x i32], [16 x i32] addrspace(5)* %alloca, i32 0, i32 5
64  store volatile i32 9, i32 addrspace(5)* %gep
65  %ret = tail call fastcc i32 @i32_fastcc_i32_i32_stack_object(i32 %a, i32 %b)
66  ret i32 %ret
67}
68
69; GCN-LABEL: {{^}}sibling_call_i32_fastcc_i32_i32_unused_result:
70define fastcc void @sibling_call_i32_fastcc_i32_i32_unused_result(i32 %a, i32 %b, i32 %c) #1 {
71entry:
72  %ret = tail call fastcc i32 @i32_fastcc_i32_i32(i32 %a, i32 %b)
73  ret void
74}
75
76; It doesn't make sense to do a tail from a kernel
77; GCN-LABEL: {{^}}kernel_call_i32_fastcc_i32_i32_unused_result:
78;define amdgpu_kernel void @kernel_call_i32_fastcc_i32_i32_unused_result(i32 %a, i32 %b, i32 %c) #1 {
79define amdgpu_kernel void @kernel_call_i32_fastcc_i32_i32_unused_result(i32 %a, i32 %b, i32 %c) #1 {
80entry:
81  %ret = tail call fastcc i32 @i32_fastcc_i32_i32(i32 %a, i32 %b)
82  ret void
83}
84
85; GCN-LABEL: {{^}}i32_fastcc_i32_byval_i32:
86; GCN: s_waitcnt
87; GCN-NEXT: buffer_load_dword v1, off, s[0:3], s32{{$}}
88; GCN-NEXT: s_waitcnt vmcnt(0)
89
90; CIVI-NEXT: v_add_{{i|u}}32_e32 v0, vcc, v0, v1
91; GFX9-NEXT: v_add_u32_e32 v0, v0, v1
92
93; GCN-NEXT: s_setpc_b64 s[30:31]
94define hidden fastcc i32 @i32_fastcc_i32_byval_i32(i32 %arg0, i32 addrspace(5)* byval align 4 %arg1) #1 {
95  %arg1.load = load i32, i32 addrspace(5)* %arg1, align 4
96  %add0 = add i32 %arg0, %arg1.load
97  ret i32 %add0
98}
99
100; Tail call disallowed with byval in parent.
101; GCN-LABEL: {{^}}sibling_call_i32_fastcc_i32_byval_i32_byval_parent:
102; GCN-NOT: v_writelane_b32 v{{[0-9]+}}, s32
103; GCN: buffer_store_dword v{{[0-9]+}}, off, s[0:3], s32{{$}}
104; GCN: s_swappc_b64
105; GCN-NOT: v_readlane_b32 s32
106; GCN: s_setpc_b64
107define fastcc i32 @sibling_call_i32_fastcc_i32_byval_i32_byval_parent(i32 %a, i32 addrspace(5)* byval %b.byval, i32 %c) #1 {
108entry:
109  %ret = tail call fastcc i32 @i32_fastcc_i32_byval_i32(i32 %a, i32 addrspace(5)* %b.byval)
110  ret i32 %ret
111}
112
113; Tail call disallowed with byval in parent, not callee. The stack
114; usage of incoming arguments must be <= the outgoing stack
115; arguments.
116
117; GCN-LABEL: {{^}}sibling_call_i32_fastcc_i32_byval_i32:
118; GCN-NOT: v0
119; GCN-NOT: s32
120; GCN: buffer_load_dword v1, off, s[0:3], 0 offset:16
121; GCN: buffer_store_dword v1, off, s[0:3], s32{{$}}
122; GCN-NEXT: s_setpc_b64
123define fastcc i32 @sibling_call_i32_fastcc_i32_byval_i32(i32 %a, [32 x i32] %large) #1 {
124entry:
125  %ret = tail call fastcc i32 @i32_fastcc_i32_byval_i32(i32 %a, i32 addrspace(5)* inttoptr (i32 16 to i32 addrspace(5)*))
126  ret i32 %ret
127}
128
129; GCN-LABEL: {{^}}i32_fastcc_i32_i32_a32i32:
130; GCN: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
131; GCN-DAG: buffer_load_dword [[LOAD_0:v[0-9]+]], off, s[0:3], s32{{$}}
132; GCN-DAG: buffer_load_dword [[LOAD_1:v[0-9]+]], off, s[0:3], s32 offset:4
133
134; CIVI-NEXT: v_add_{{i|u}}32_e32 v0, vcc, v0, v1
135; CIVI: v_add_{{i|u}}32_e32 v0, vcc, v0, [[LOAD_0]]
136; CIVI: v_add_{{i|u}}32_e32 v0, vcc, v0, [[LOAD_1]]
137
138
139; GFX9-NEXT: v_add_u32_e32 v0, v0, v1
140; GFX9: v_add3_u32 v0, v0, v3, v2
141
142; GCN-NEXT: s_setpc_b64
143define fastcc i32 @i32_fastcc_i32_i32_a32i32(i32 %arg0, i32 %arg1, [32 x i32] %large) #1 {
144  %val_firststack = extractvalue [32 x i32] %large, 30
145  %val_laststack = extractvalue [32 x i32] %large, 31
146  %add0 = add i32 %arg0, %arg1
147  %add1 = add i32 %add0, %val_firststack
148  %add2 = add i32 %add1, %val_laststack
149  ret i32 %add2
150}
151
152; FIXME: Why load and store same location for stack args?
153; GCN-LABEL: {{^}}sibling_call_i32_fastcc_i32_i32_a32i32:
154
155; GCN-DAG: buffer_store_dword v32, off, s[0:3], s32 offset:12 ; 4-byte Folded Spill
156; GCN-DAG: buffer_store_dword v33, off, s[0:3], s32 offset:8 ; 4-byte Folded Spill
157
158; GCN-DAG: buffer_load_dword [[LOAD_0:v[0-9]+]], off, s[0:3], s32{{$}}
159; GCN-DAG: buffer_load_dword [[LOAD_1:v[0-9]+]], off, s[0:3], s32 offset:4
160
161; GCN-NOT: s32
162
163; GCN-DAG: buffer_store_dword [[LOAD_0]], off, s[0:3], s32{{$}}
164; GCN-DAG: buffer_store_dword [[LOAD_1]], off, s[0:3], s32 offset:4
165
166; GCN-DAG: buffer_load_dword v32, off, s[0:3], s32 offset:12 ; 4-byte Folded Reload
167; GCN-DAG: buffer_load_dword v33, off, s[0:3], s32 offset:8 ; 4-byte Folded Reload
168
169; GCN-NOT: s32
170; GCN: s_setpc_b64
171define fastcc i32 @sibling_call_i32_fastcc_i32_i32_a32i32(i32 %a, i32 %b, [32 x i32] %c) #1 {
172entry:
173  %ret = tail call fastcc i32 @i32_fastcc_i32_i32_a32i32(i32 %a, i32 %b, [32 x i32] %c)
174  ret i32 %ret
175}
176
177; GCN-LABEL: {{^}}sibling_call_i32_fastcc_i32_i32_a32i32_stack_object:
178; GCN-DAG: v_mov_b32_e32 [[NINE:v[0-9]+]], 9
179; GCN: buffer_store_dword [[NINE]], off, s[0:3], s32 offset:40
180; GCN: s_setpc_b64
181define fastcc i32 @sibling_call_i32_fastcc_i32_i32_a32i32_stack_object(i32 %a, i32 %b, [32 x i32] %c) #1 {
182entry:
183  %alloca = alloca [16 x i32], align 4, addrspace(5)
184  %gep = getelementptr inbounds [16 x i32], [16 x i32] addrspace(5)* %alloca, i32 0, i32 5
185  store volatile i32 9, i32 addrspace(5)* %gep
186  %ret = tail call fastcc i32 @i32_fastcc_i32_i32_a32i32(i32 %a, i32 %b, [32 x i32] %c)
187  ret i32 %ret
188}
189
190; If the callee requires more stack argument space than the caller,
191; don't do a tail call.
192; TODO: Do we really need this restriction?
193
194; GCN-LABEL: {{^}}no_sibling_call_callee_more_stack_space:
195; GCN: s_swappc_b64
196; GCN: s_setpc_b64
197define fastcc i32 @no_sibling_call_callee_more_stack_space(i32 %a, i32 %b) #1 {
198entry:
199  %ret = tail call fastcc i32 @i32_fastcc_i32_i32_a32i32(i32 %a, i32 %b, [32 x i32] zeroinitializer)
200  ret i32 %ret
201}
202
203; Have another non-tail in the function
204; GCN-LABEL: {{^}}sibling_call_i32_fastcc_i32_i32_other_call:
205; GCN: s_or_saveexec_b64 s{{\[[0-9]+:[0-9]+\]}}, -1
206; GCN-NEXT: buffer_store_dword v34, off, s[0:3], s32 offset:8 ; 4-byte Folded Spill
207; GCN-NEXT: s_mov_b64 exec
208; GCN: s_mov_b32 s33, s32
209; GCN-DAG: s_add_u32 s32, s32, 0x400
210
211; GCN-DAG: buffer_store_dword v32, off, s[0:3], s33 offset:4 ; 4-byte Folded Spill
212; GCN-DAG: buffer_store_dword v33, off, s[0:3], s33 ; 4-byte Folded Spill
213; GCN-DAG: v_writelane_b32 v34, s34, 0
214; GCN-DAG: v_writelane_b32 v34, s35, 1
215
216; GCN-DAG: s_getpc_b64 s[4:5]
217; GCN-DAG: s_add_u32 s4, s4, i32_fastcc_i32_i32@gotpcrel32@lo+4
218; GCN-DAG: s_addc_u32 s5, s5, i32_fastcc_i32_i32@gotpcrel32@hi+4
219
220
221; GCN: s_swappc_b64
222
223; GCN-DAG: v_readlane_b32 s34, v34, 0
224; GCN-DAG: v_readlane_b32 s35, v34, 1
225
226; GCN: buffer_load_dword v33, off, s[0:3], s33 ; 4-byte Folded Reload
227; GCN: buffer_load_dword v32, off, s[0:3], s33 offset:4 ; 4-byte Folded Reload
228
229; GCN: s_getpc_b64 s[4:5]
230; GCN-NEXT: s_add_u32 s4, s4, sibling_call_i32_fastcc_i32_i32@rel32@lo+4
231; GCN-NEXT: s_addc_u32 s5, s5, sibling_call_i32_fastcc_i32_i32@rel32@hi+4
232
233; GCN: s_sub_u32 s32, s32, 0x400
234; GCN-NEXT: v_readlane_b32 s33,
235; GCN-NEXT: s_or_saveexec_b64 s[6:7], -1
236; GCN-NEXT: buffer_load_dword v34, off, s[0:3], s32 offset:8 ; 4-byte Folded Reload
237; GCN-NEXT: s_mov_b64 exec, s[6:7]
238; GCN-NEXT: s_setpc_b64 s[4:5]
239define fastcc i32 @sibling_call_i32_fastcc_i32_i32_other_call(i32 %a, i32 %b, i32 %c) #1 {
240entry:
241  %other.call = tail call fastcc i32 @i32_fastcc_i32_i32(i32 %a, i32 %b)
242  %ret = tail call fastcc i32 @sibling_call_i32_fastcc_i32_i32(i32 %a, i32 %b, i32 %other.call)
243  ret i32 %ret
244}
245
246; Have stack object in caller and stack passed arguments. SP should be
247; in same place at function exit.
248
249; GCN-LABEL: {{^}}sibling_call_stack_objecti32_fastcc_i32_i32_a32i32:
250; GCN-NOT: s33
251; GCN: buffer_store_dword v{{[0-9]+}}, off, s[0:3], s32 offset:
252
253; GCN-NOT: s33
254
255; GCN: buffer_load_dword v{{[0-9]+}}, off, s[0:3], s32 offset:
256; GCN: s_setpc_b64 s[4:5]
257define fastcc i32 @sibling_call_stack_objecti32_fastcc_i32_i32_a32i32(i32 %a, i32 %b, [32 x i32] %c) #1 {
258entry:
259  %alloca = alloca [16 x i32], align 4, addrspace(5)
260  %gep = getelementptr inbounds [16 x i32], [16 x i32] addrspace(5)* %alloca, i32 0, i32 5
261  store volatile i32 9, i32 addrspace(5)* %gep
262  %ret = tail call fastcc i32 @i32_fastcc_i32_i32_a32i32(i32 %a, i32 %b, [32 x i32] %c)
263  ret i32 %ret
264}
265
266; GCN-LABEL: {{^}}sibling_call_stack_objecti32_fastcc_i32_i32_a32i32_larger_arg_area:
267; GCN-NOT: s33
268; GCN: buffer_store_dword v{{[0-9]+}}, off, s[0:3], s32 offset:44
269
270; GCN-NOT: s33
271; GCN: s_setpc_b64 s[4:5]
272define fastcc i32 @sibling_call_stack_objecti32_fastcc_i32_i32_a32i32_larger_arg_area(i32 %a, i32 %b, [36 x i32] %c) #1 {
273entry:
274  %alloca = alloca [16 x i32], align 4, addrspace(5)
275  %gep = getelementptr inbounds [16 x i32], [16 x i32] addrspace(5)* %alloca, i32 0, i32 5
276  store volatile i32 9, i32 addrspace(5)* %gep
277  %ret = tail call fastcc i32 @i32_fastcc_i32_i32_a32i32(i32 %a, i32 %b, [32 x i32] zeroinitializer)
278  ret i32 %ret
279}
280
281attributes #0 = { nounwind }
282attributes #1 = { nounwind noinline }
283