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