; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -mtriple=sparc -verify-machineinstrs | FileCheck %s define i32 @simple_leaf(i32 %i) #0 { ; CHECK-LABEL: simple_leaf: ; CHECK: ! %bb.0: ! %entry ; CHECK-NEXT: mov %o7, %g1 ; CHECK-NEXT: call foo ; CHECK-NEXT: mov %g1, %o7 entry: %call = tail call i32 @foo(i32 %i) ret i32 %call } define i32 @simple_standard(i32 %i) #1 { ; CHECK-LABEL: simple_standard: ; CHECK: ! %bb.0: ! %entry ; CHECK-NEXT: save %sp, -96, %sp ; CHECK-NEXT: call foo ; CHECK-NEXT: restore entry: %call = tail call i32 @foo(i32 %i) ret i32 %call } define i32 @extra_arg_leaf(i32 %i) #0 { ; CHECK-LABEL: extra_arg_leaf: ; CHECK: ! %bb.0: ! %entry ; CHECK-NEXT: mov 12, %o1 ; CHECK-NEXT: mov %o7, %g1 ; CHECK-NEXT: call foo2 ; CHECK-NEXT: mov %g1, %o7 entry: %call = tail call i32 @foo2(i32 %i, i32 12) ret i32 %call } define i32 @extra_arg_standard(i32 %i) #1 { ; CHECK-LABEL: extra_arg_standard: ; CHECK: ! %bb.0: ! %entry ; CHECK-NEXT: save %sp, -96, %sp ; CHECK-NEXT: call foo2 ; CHECK-NEXT: restore %g0, 12, %o1 entry: %call = tail call i32 @foo2(i32 %i, i32 12) ret i32 %call } ; Perform tail call optimization for external symbol. define void @caller_extern(i8* %src) optsize #0 { ; CHECK-LABEL: caller_extern: ; CHECK: ! %bb.0: ! %entry ; CHECK-NEXT: sethi %hi(dest), %o1 ; CHECK-NEXT: add %o1, %lo(dest), %o1 ; CHECK-NEXT: mov 7, %o2 ; CHECK-NEXT: mov %o0, %o3 ; CHECK-NEXT: mov %o1, %o0 ; CHECK-NEXT: mov %o3, %o1 ; CHECK-NEXT: mov %o7, %g1 ; CHECK-NEXT: call memcpy ; CHECK-NEXT: mov %g1, %o7 entry: tail call void @llvm.memcpy.p0i8.p0i8.i32( i8* getelementptr inbounds ([2 x i8], [2 x i8]* @dest, i32 0, i32 0), i8* %src, i32 7, i1 false) ret void } ; Perform tail call optimization for function pointer. define i32 @func_ptr_test(i32 ()* nocapture %func_ptr) #0 { ; CHECK-LABEL: func_ptr_test: ; CHECK: ! %bb.0: ! %entry ; CHECK-NEXT: jmp %o0 ; CHECK-NEXT: nop entry: %call = tail call i32 %func_ptr() #1 ret i32 %call } define i32 @func_ptr_test2(i32 (i32, i32, i32)* nocapture %func_ptr, ; CHECK-LABEL: func_ptr_test2: ; CHECK: ! %bb.0: ! %entry ; CHECK-NEXT: save %sp, -96, %sp ; CHECK-NEXT: mov 10, %i3 ; CHECK-NEXT: mov %i0, %i4 ; CHECK-NEXT: mov %i1, %i0 ; CHECK-NEXT: jmp %i4 ; CHECK-NEXT: restore %g0, %i3, %o1 i32 %r, i32 %q) #1 { entry: %call = tail call i32 %func_ptr(i32 %r, i32 10, i32 %q) #1 ret i32 %call } ; Do not tail call optimize if stack is used to pass parameters. define i32 @caller_args() #0 { ; CHECK-LABEL: caller_args: ; CHECK: ! %bb.0: ! %entry ; CHECK-NEXT: save %sp, -104, %sp ; CHECK-NEXT: mov 6, %i0 ; CHECK-NEXT: mov %g0, %o0 ; CHECK-NEXT: mov 1, %o1 ; CHECK-NEXT: mov 2, %o2 ; CHECK-NEXT: mov 3, %o3 ; CHECK-NEXT: mov 4, %o4 ; CHECK-NEXT: mov 5, %o5 ; CHECK-NEXT: call foo7 ; CHECK-NEXT: st %i0, [%sp+92] ; CHECK-NEXT: ret ; CHECK-NEXT: restore %g0, %o0, %o0 entry: %r = tail call i32 @foo7(i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6) ret i32 %r } ; Byval parameters hand the function a pointer directly into the stack area ; we want to reuse during a tail call. Do not tail call optimize functions with ; byval parameters. define i32 @caller_byval() #0 { ; CHECK-LABEL: caller_byval: ; CHECK: ! %bb.0: ! %entry ; CHECK-NEXT: save %sp, -104, %sp ; CHECK-NEXT: ld [%fp+-4], %i0 ; CHECK-NEXT: st %i0, [%fp+-8] ; CHECK-NEXT: call callee_byval ; CHECK-NEXT: add %fp, -8, %o0 ; CHECK-NEXT: ret ; CHECK-NEXT: restore %g0, %o0, %o0 entry: %a = alloca i32* %r = tail call i32 @callee_byval(i32** byval(i32*) %a) ret i32 %r } ; Perform tail call optimization for sret function. define void @sret_test(%struct.a* noalias sret(%struct.a) %agg.result) #0 { ; CHECK-LABEL: sret_test: ; CHECK: ! %bb.0: ! %entry ; CHECK-NEXT: mov %o7, %g1 ; CHECK-NEXT: call sret_func ; CHECK-NEXT: mov %g1, %o7 entry: tail call void bitcast (void (%struct.a*)* @sret_func to void (%struct.a*)*)(%struct.a* sret(%struct.a) %agg.result) ret void } ; Do not tail call if either caller or callee returns ; a struct and the other does not. Returning a large ; struct will generate a memcpy as the tail function. define void @ret_large_struct(%struct.big* noalias sret(%struct.big) %agg.result) #0 { ; CHECK-LABEL: ret_large_struct: ; CHECK: ! %bb.0: ! %entry ; CHECK-NEXT: save %sp, -96, %sp ; CHECK-NEXT: ld [%fp+64], %i0 ; CHECK-NEXT: sethi %hi(bigstruct), %i1 ; CHECK-NEXT: add %i1, %lo(bigstruct), %o1 ; CHECK-NEXT: mov 400, %o2 ; CHECK-NEXT: call memcpy ; CHECK-NEXT: mov %i0, %o0 ; CHECK-NEXT: jmp %i7+12 ; CHECK-NEXT: restore entry: %0 = bitcast %struct.big* %agg.result to i8* tail call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %0, i8* align 4 bitcast (%struct.big* @bigstruct to i8*), i32 400, i1 false) ret void } ; Test register + immediate pattern. define void @addri_test(i32 %ptr) #0 { ; CHECK-LABEL: addri_test: ; CHECK: ! %bb.0: ! %entry ; CHECK-NEXT: jmp %o0+4 ; CHECK-NEXT: nop entry: %add = add nsw i32 %ptr, 4 %0 = inttoptr i32 %add to void ()* tail call void %0() #1 ret void } %struct.a = type { i32, i32 } @dest = global [2 x i8] zeroinitializer %struct.big = type { [100 x i32] } @bigstruct = global %struct.big zeroinitializer declare void @llvm.memcpy.p0i8.p0i8.i32(i8*, i8*, i32, i1) declare void @sret_func(%struct.a* sret(%struct.a)) declare i32 @callee_byval(i32** byval(i32*) %a) declare i32 @foo(i32) declare i32 @foo2(i32, i32) declare i32 @foo7(i32, i32, i32, i32, i32, i32, i32) attributes #0 = { nounwind "disable-tail-calls"="false" "frame-pointer"="none" } attributes #1 = { nounwind "disable-tail-calls"="false" "frame-pointer"="all" }