11c235c37SDaniel Cederman; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 2f63a19baSKoakuma; RUN: llc < %s -mtriple=sparc -verify-machineinstrs | FileCheck %s --check-prefix=V8 3f63a19baSKoakuma; RUN: llc < %s -mtriple=sparcv9 -verify-machineinstrs | FileCheck %s --check-prefix=V9 41c235c37SDaniel Cederman 51c235c37SDaniel Cedermandefine i32 @simple_leaf(i32 %i) #0 { 6f63a19baSKoakuma; V8-LABEL: simple_leaf: 7f63a19baSKoakuma; V8: ! %bb.0: ! %entry 8f63a19baSKoakuma; V8-NEXT: mov %o7, %g1 9f63a19baSKoakuma; V8-NEXT: call foo 10f63a19baSKoakuma; V8-NEXT: mov %g1, %o7 11f63a19baSKoakuma; 12f63a19baSKoakuma; V9-LABEL: simple_leaf: 13f63a19baSKoakuma; V9: ! %bb.0: ! %entry 14f63a19baSKoakuma; V9-NEXT: mov %o7, %g1 15f63a19baSKoakuma; V9-NEXT: call foo 16f63a19baSKoakuma; V9-NEXT: mov %g1, %o7 171c235c37SDaniel Cedermanentry: 181c235c37SDaniel Cederman %call = tail call i32 @foo(i32 %i) 191c235c37SDaniel Cederman ret i32 %call 201c235c37SDaniel Cederman} 211c235c37SDaniel Cederman 221c235c37SDaniel Cedermandefine i32 @simple_standard(i32 %i) #1 { 23f63a19baSKoakuma; V8-LABEL: simple_standard: 24f63a19baSKoakuma; V8: ! %bb.0: ! %entry 25f63a19baSKoakuma; V8-NEXT: save %sp, -96, %sp 26f63a19baSKoakuma; V8-NEXT: call foo 27f63a19baSKoakuma; V8-NEXT: restore 28f63a19baSKoakuma; 29f63a19baSKoakuma; V9-LABEL: simple_standard: 30f63a19baSKoakuma; V9: ! %bb.0: ! %entry 31f63a19baSKoakuma; V9-NEXT: save %sp, -128, %sp 32f63a19baSKoakuma; V9-NEXT: call foo 33f63a19baSKoakuma; V9-NEXT: restore 341c235c37SDaniel Cedermanentry: 351c235c37SDaniel Cederman %call = tail call i32 @foo(i32 %i) 361c235c37SDaniel Cederman ret i32 %call 371c235c37SDaniel Cederman} 381c235c37SDaniel Cederman 391c235c37SDaniel Cedermandefine i32 @extra_arg_leaf(i32 %i) #0 { 40f63a19baSKoakuma; V8-LABEL: extra_arg_leaf: 41f63a19baSKoakuma; V8: ! %bb.0: ! %entry 42f63a19baSKoakuma; V8-NEXT: mov 12, %o1 43f63a19baSKoakuma; V8-NEXT: mov %o7, %g1 44f63a19baSKoakuma; V8-NEXT: call foo2 45f63a19baSKoakuma; V8-NEXT: mov %g1, %o7 46f63a19baSKoakuma; 47f63a19baSKoakuma; V9-LABEL: extra_arg_leaf: 48f63a19baSKoakuma; V9: ! %bb.0: ! %entry 49f63a19baSKoakuma; V9-NEXT: mov 12, %o1 50f63a19baSKoakuma; V9-NEXT: mov %o7, %g1 51f63a19baSKoakuma; V9-NEXT: call foo2 52f63a19baSKoakuma; V9-NEXT: mov %g1, %o7 531c235c37SDaniel Cedermanentry: 541c235c37SDaniel Cederman %call = tail call i32 @foo2(i32 %i, i32 12) 551c235c37SDaniel Cederman ret i32 %call 561c235c37SDaniel Cederman} 571c235c37SDaniel Cederman 581c235c37SDaniel Cedermandefine i32 @extra_arg_standard(i32 %i) #1 { 59f63a19baSKoakuma; V8-LABEL: extra_arg_standard: 60f63a19baSKoakuma; V8: ! %bb.0: ! %entry 61f63a19baSKoakuma; V8-NEXT: save %sp, -96, %sp 62f63a19baSKoakuma; V8-NEXT: call foo2 63f63a19baSKoakuma; V8-NEXT: restore %g0, 12, %o1 64f63a19baSKoakuma; 65f63a19baSKoakuma; V9-LABEL: extra_arg_standard: 66f63a19baSKoakuma; V9: ! %bb.0: ! %entry 67f63a19baSKoakuma; V9-NEXT: save %sp, -128, %sp 68f63a19baSKoakuma; V9-NEXT: call foo2 69f63a19baSKoakuma; V9-NEXT: restore %g0, 12, %o1 701c235c37SDaniel Cedermanentry: 711c235c37SDaniel Cederman %call = tail call i32 @foo2(i32 %i, i32 12) 721c235c37SDaniel Cederman ret i32 %call 731c235c37SDaniel Cederman} 741c235c37SDaniel Cederman 751c235c37SDaniel Cederman; Perform tail call optimization for external symbol. 761c235c37SDaniel Cederman 77*ff9af4c4SNikita Popovdefine void @caller_extern(ptr %src) optsize #0 { 78f63a19baSKoakuma; V8-LABEL: caller_extern: 79f63a19baSKoakuma; V8: ! %bb.0: ! %entry 80f63a19baSKoakuma; V8-NEXT: sethi %hi(dest), %o1 81f63a19baSKoakuma; V8-NEXT: add %o1, %lo(dest), %o1 82f63a19baSKoakuma; V8-NEXT: mov 7, %o2 83f63a19baSKoakuma; V8-NEXT: mov %o0, %o3 84f63a19baSKoakuma; V8-NEXT: mov %o1, %o0 85f63a19baSKoakuma; V8-NEXT: mov %o3, %o1 86f63a19baSKoakuma; V8-NEXT: mov %o7, %g1 87f63a19baSKoakuma; V8-NEXT: call memcpy 88f63a19baSKoakuma; V8-NEXT: mov %g1, %o7 89f63a19baSKoakuma; 90f63a19baSKoakuma; V9-LABEL: caller_extern: 91f63a19baSKoakuma; V9: ! %bb.0: ! %entry 92f63a19baSKoakuma; V9-NEXT: sethi %h44(dest), %o1 93f63a19baSKoakuma; V9-NEXT: add %o1, %m44(dest), %o1 94f63a19baSKoakuma; V9-NEXT: sllx %o1, 12, %o1 95f63a19baSKoakuma; V9-NEXT: add %o1, %l44(dest), %o1 96f63a19baSKoakuma; V9-NEXT: mov 7, %o2 97f63a19baSKoakuma; V9-NEXT: mov %o0, %o3 98f63a19baSKoakuma; V9-NEXT: mov %o1, %o0 99f63a19baSKoakuma; V9-NEXT: mov %o3, %o1 100f63a19baSKoakuma; V9-NEXT: mov %o7, %g1 101f63a19baSKoakuma; V9-NEXT: call memcpy 102f63a19baSKoakuma; V9-NEXT: mov %g1, %o7 1031c235c37SDaniel Cedermanentry: 104*ff9af4c4SNikita Popov tail call void @llvm.memcpy.p0.p0.i32( 105*ff9af4c4SNikita Popov ptr @dest, 106*ff9af4c4SNikita Popov ptr %src, i32 7, i1 false) 1071c235c37SDaniel Cederman ret void 1081c235c37SDaniel Cederman} 1091c235c37SDaniel Cederman 1101c235c37SDaniel Cederman; Perform tail call optimization for function pointer. 1111c235c37SDaniel Cederman 112*ff9af4c4SNikita Popovdefine i32 @func_ptr_test(ptr nocapture %func_ptr) #0 { 113f63a19baSKoakuma; V8-LABEL: func_ptr_test: 114f63a19baSKoakuma; V8: ! %bb.0: ! %entry 115f63a19baSKoakuma; V8-NEXT: jmp %o0 116f63a19baSKoakuma; V8-NEXT: nop 117f63a19baSKoakuma; 118f63a19baSKoakuma; V9-LABEL: func_ptr_test: 119f63a19baSKoakuma; V9: ! %bb.0: ! %entry 120f63a19baSKoakuma; V9-NEXT: jmp %o0 121f63a19baSKoakuma; V9-NEXT: nop 1221c235c37SDaniel Cedermanentry: 1231c235c37SDaniel Cederman %call = tail call i32 %func_ptr() #1 1241c235c37SDaniel Cederman ret i32 %call 1251c235c37SDaniel Cederman} 1261c235c37SDaniel Cederman 127*ff9af4c4SNikita Popovdefine i32 @func_ptr_test2(ptr nocapture %func_ptr, 128f63a19baSKoakuma; V8-LABEL: func_ptr_test2: 129f63a19baSKoakuma; V8: ! %bb.0: ! %entry 130f63a19baSKoakuma; V8-NEXT: save %sp, -96, %sp 131f63a19baSKoakuma; V8-NEXT: mov 10, %i3 132f63a19baSKoakuma; V8-NEXT: mov %i0, %i4 133f63a19baSKoakuma; V8-NEXT: mov %i1, %i0 134f63a19baSKoakuma; V8-NEXT: jmp %i4 135f63a19baSKoakuma; V8-NEXT: restore %g0, %i3, %o1 136f63a19baSKoakuma; 137f63a19baSKoakuma; V9-LABEL: func_ptr_test2: 138f63a19baSKoakuma; V9: ! %bb.0: ! %entry 139f63a19baSKoakuma; V9-NEXT: save %sp, -128, %sp 140f63a19baSKoakuma; V9-NEXT: mov 10, %i3 141f63a19baSKoakuma; V9-NEXT: mov %i0, %i4 142f63a19baSKoakuma; V9-NEXT: mov %i1, %i0 143f63a19baSKoakuma; V9-NEXT: jmp %i4 144f63a19baSKoakuma; V9-NEXT: restore %g0, %i3, %o1 1451c235c37SDaniel Cederman i32 %r, i32 %q) #1 { 1461c235c37SDaniel Cedermanentry: 1471c235c37SDaniel Cederman %call = tail call i32 %func_ptr(i32 %r, i32 10, i32 %q) #1 1481c235c37SDaniel Cederman ret i32 %call 1491c235c37SDaniel Cederman} 1501c235c37SDaniel Cederman 1511c235c37SDaniel Cederman 1521c235c37SDaniel Cederman; Do not tail call optimize if stack is used to pass parameters. 1531c235c37SDaniel Cederman 1541c235c37SDaniel Cedermandefine i32 @caller_args() #0 { 155f63a19baSKoakuma; V8-LABEL: caller_args: 156f63a19baSKoakuma; V8: ! %bb.0: ! %entry 157f63a19baSKoakuma; V8-NEXT: save %sp, -104, %sp 158f63a19baSKoakuma; V8-NEXT: mov 6, %i0 159f63a19baSKoakuma; V8-NEXT: mov 1, %o1 160f63a19baSKoakuma; V8-NEXT: mov 2, %o2 161f63a19baSKoakuma; V8-NEXT: mov 3, %o3 162f63a19baSKoakuma; V8-NEXT: mov 4, %o4 163f63a19baSKoakuma; V8-NEXT: mov 5, %o5 1647806f86aSBrad Smith; V8-NEXT: st %i0, [%sp+92] 165eaade37fSKoakuma; V8-NEXT: call foo7 166eaade37fSKoakuma; V8-NEXT: mov %g0, %o0 167f63a19baSKoakuma; V8-NEXT: ret 168f63a19baSKoakuma; V8-NEXT: restore %g0, %o0, %o0 169f63a19baSKoakuma; 170f63a19baSKoakuma; V9-LABEL: caller_args: 171f63a19baSKoakuma; V9: ! %bb.0: ! %entry 172f63a19baSKoakuma; V9-NEXT: save %sp, -192, %sp 173f63a19baSKoakuma; V9-NEXT: mov 6, %i0 174f63a19baSKoakuma; V9-NEXT: mov 1, %o1 175f63a19baSKoakuma; V9-NEXT: mov 2, %o2 176f63a19baSKoakuma; V9-NEXT: mov 3, %o3 177f63a19baSKoakuma; V9-NEXT: mov 4, %o4 178f63a19baSKoakuma; V9-NEXT: mov 5, %o5 1797806f86aSBrad Smith; V9-NEXT: stx %i0, [%sp+2223] 180eaade37fSKoakuma; V9-NEXT: call foo7 181eaade37fSKoakuma; V9-NEXT: mov %g0, %o0 182f63a19baSKoakuma; V9-NEXT: ret 183f63a19baSKoakuma; V9-NEXT: restore %g0, %o0, %o0 1841c235c37SDaniel Cedermanentry: 1851c235c37SDaniel Cederman %r = tail call i32 @foo7(i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6) 1861c235c37SDaniel Cederman ret i32 %r 1871c235c37SDaniel Cederman} 1881c235c37SDaniel Cederman 1891c235c37SDaniel Cederman; Byval parameters hand the function a pointer directly into the stack area 1901c235c37SDaniel Cederman; we want to reuse during a tail call. Do not tail call optimize functions with 1911c235c37SDaniel Cederman; byval parameters. 1921c235c37SDaniel Cederman 1931c235c37SDaniel Cedermandefine i32 @caller_byval() #0 { 194f63a19baSKoakuma; V8-LABEL: caller_byval: 195f63a19baSKoakuma; V8: ! %bb.0: ! %entry 196f63a19baSKoakuma; V8-NEXT: save %sp, -104, %sp 197f63a19baSKoakuma; V8-NEXT: ld [%fp+-4], %i0 198f63a19baSKoakuma; V8-NEXT: st %i0, [%fp+-8] 199f63a19baSKoakuma; V8-NEXT: call callee_byval 200f63a19baSKoakuma; V8-NEXT: add %fp, -8, %o0 201f63a19baSKoakuma; V8-NEXT: ret 202f63a19baSKoakuma; V8-NEXT: restore %g0, %o0, %o0 203f63a19baSKoakuma; 204f63a19baSKoakuma; V9-LABEL: caller_byval: 205f63a19baSKoakuma; V9: ! %bb.0: ! %entry 206f63a19baSKoakuma; V9-NEXT: save %sp, -192, %sp 207f63a19baSKoakuma; V9-NEXT: call callee_byval 208f63a19baSKoakuma; V9-NEXT: add %fp, 2039, %o0 209f63a19baSKoakuma; V9-NEXT: ret 210f63a19baSKoakuma; V9-NEXT: restore %g0, %o0, %o0 2111c235c37SDaniel Cedermanentry: 212*ff9af4c4SNikita Popov %a = alloca ptr 213*ff9af4c4SNikita Popov %r = tail call i32 @callee_byval(ptr byval(ptr) %a) 2141c235c37SDaniel Cederman ret i32 %r 2151c235c37SDaniel Cederman} 2161c235c37SDaniel Cederman 2171c235c37SDaniel Cederman; Perform tail call optimization for sret function. 2181c235c37SDaniel Cederman 219*ff9af4c4SNikita Popovdefine void @sret_test(ptr noalias sret(%struct.a) %agg.result) #0 { 220f63a19baSKoakuma; V8-LABEL: sret_test: 221f63a19baSKoakuma; V8: ! %bb.0: ! %entry 222f63a19baSKoakuma; V8-NEXT: mov %o7, %g1 223f63a19baSKoakuma; V8-NEXT: call sret_func 224f63a19baSKoakuma; V8-NEXT: mov %g1, %o7 225f63a19baSKoakuma; 226f63a19baSKoakuma; V9-LABEL: sret_test: 227f63a19baSKoakuma; V9: ! %bb.0: ! %entry 228f63a19baSKoakuma; V9-NEXT: mov %o7, %g1 229f63a19baSKoakuma; V9-NEXT: call sret_func 230f63a19baSKoakuma; V9-NEXT: mov %g1, %o7 2311c235c37SDaniel Cedermanentry: 232*ff9af4c4SNikita Popov tail call void @sret_func(ptr sret(%struct.a) %agg.result) 2331c235c37SDaniel Cederman ret void 2341c235c37SDaniel Cederman} 2351c235c37SDaniel Cederman 2361c235c37SDaniel Cederman; Do not tail call if either caller or callee returns 2371c235c37SDaniel Cederman; a struct and the other does not. Returning a large 2381c235c37SDaniel Cederman; struct will generate a memcpy as the tail function. 2391c235c37SDaniel Cederman 240*ff9af4c4SNikita Popovdefine void @ret_large_struct(ptr noalias sret(%struct.big) %agg.result) #0 { 241f63a19baSKoakuma; V8-LABEL: ret_large_struct: 242f63a19baSKoakuma; V8: ! %bb.0: ! %entry 243f63a19baSKoakuma; V8-NEXT: save %sp, -96, %sp 244f63a19baSKoakuma; V8-NEXT: ld [%fp+64], %i0 245f63a19baSKoakuma; V8-NEXT: sethi %hi(bigstruct), %i1 246f63a19baSKoakuma; V8-NEXT: add %i1, %lo(bigstruct), %o1 247f63a19baSKoakuma; V8-NEXT: mov 400, %o2 248f63a19baSKoakuma; V8-NEXT: call memcpy 249f63a19baSKoakuma; V8-NEXT: mov %i0, %o0 250f63a19baSKoakuma; V8-NEXT: jmp %i7+12 251f63a19baSKoakuma; V8-NEXT: restore 252f63a19baSKoakuma; 253f63a19baSKoakuma; V9-LABEL: ret_large_struct: 254f63a19baSKoakuma; V9: ! %bb.0: ! %entry 255f63a19baSKoakuma; V9-NEXT: save %sp, -176, %sp 256f63a19baSKoakuma; V9-NEXT: sethi %h44(bigstruct), %i1 257f63a19baSKoakuma; V9-NEXT: add %i1, %m44(bigstruct), %i1 258f63a19baSKoakuma; V9-NEXT: sllx %i1, 12, %i1 259f63a19baSKoakuma; V9-NEXT: add %i1, %l44(bigstruct), %o1 260f63a19baSKoakuma; V9-NEXT: mov 400, %o2 261f63a19baSKoakuma; V9-NEXT: call memcpy 262f63a19baSKoakuma; V9-NEXT: mov %i0, %o0 263f63a19baSKoakuma; V9-NEXT: ret 264f63a19baSKoakuma; V9-NEXT: restore 2651c235c37SDaniel Cedermanentry: 266*ff9af4c4SNikita Popov %0 = bitcast ptr %agg.result to ptr 267*ff9af4c4SNikita Popov tail call void @llvm.memcpy.p0.p0.i32(ptr align 4 %0, ptr align 4 @bigstruct, i32 400, i1 false) 2681c235c37SDaniel Cederman ret void 2691c235c37SDaniel Cederman} 2701c235c37SDaniel Cederman 2711c235c37SDaniel Cederman; Test register + immediate pattern. 2721c235c37SDaniel Cederman 2731c235c37SDaniel Cedermandefine void @addri_test(i32 %ptr) #0 { 274f63a19baSKoakuma; V8-LABEL: addri_test: 275f63a19baSKoakuma; V8: ! %bb.0: ! %entry 276f63a19baSKoakuma; V8-NEXT: jmp %o0+4 277f63a19baSKoakuma; V8-NEXT: nop 278f63a19baSKoakuma; 279f63a19baSKoakuma; V9-LABEL: addri_test: 280f63a19baSKoakuma; V9: ! %bb.0: ! %entry 281f63a19baSKoakuma; V9-NEXT: add %o0, 4, %o0 282f63a19baSKoakuma; V9-NEXT: srl %o0, 0, %o0 283f63a19baSKoakuma; V9-NEXT: jmp %o0 284f63a19baSKoakuma; V9-NEXT: nop 2851c235c37SDaniel Cedermanentry: 2861c235c37SDaniel Cederman %add = add nsw i32 %ptr, 4 287*ff9af4c4SNikita Popov %0 = inttoptr i32 %add to ptr 2881c235c37SDaniel Cederman tail call void %0() #1 2891c235c37SDaniel Cederman ret void 2901c235c37SDaniel Cederman} 2911c235c37SDaniel Cederman 2921c235c37SDaniel Cederman%struct.a = type { i32, i32 } 2931c235c37SDaniel Cederman@dest = global [2 x i8] zeroinitializer 2941c235c37SDaniel Cederman 2951c235c37SDaniel Cederman%struct.big = type { [100 x i32] } 2961c235c37SDaniel Cederman@bigstruct = global %struct.big zeroinitializer 2971c235c37SDaniel Cederman 298*ff9af4c4SNikita Popovdeclare void @llvm.memcpy.p0.p0.i32(ptr, ptr, i32, i1) 299*ff9af4c4SNikita Popovdeclare void @sret_func(ptr sret(%struct.a)) 300*ff9af4c4SNikita Popovdeclare i32 @callee_byval(ptr byval(ptr) %a) 3011c235c37SDaniel Cedermandeclare i32 @foo(i32) 3021c235c37SDaniel Cedermandeclare i32 @foo2(i32, i32) 3031c235c37SDaniel Cedermandeclare i32 @foo7(i32, i32, i32, i32, i32, i32, i32) 3041c235c37SDaniel Cederman 3051c235c37SDaniel Cedermanattributes #0 = { nounwind "disable-tail-calls"="false" 3061c235c37SDaniel Cederman "frame-pointer"="none" } 3071c235c37SDaniel Cedermanattributes #1 = { nounwind "disable-tail-calls"="false" 3081c235c37SDaniel Cederman "frame-pointer"="all" } 309