1; RUN: llc -verify-machineinstrs < %s -mtriple=aarch64-none-linux-gnu -tailcallopt | FileCheck %s --check-prefixes=SDAG,COMMON 2; RUN: llc -global-isel -global-isel-abort=1 -verify-machineinstrs < %s -mtriple=aarch64-none-linux-gnu -tailcallopt | FileCheck %s --check-prefixes=GISEL,COMMON 3 4declare fastcc void @callee_stack0() 5declare fastcc void @callee_stack8([8 x i64], i64) 6declare fastcc void @callee_stack16([8 x i64], i64, i64) 7declare extern_weak fastcc void @callee_weak() 8 9define fastcc void @caller_to0_from0() nounwind { 10; COMMON-LABEL: caller_to0_from0: 11; COMMON-NEXT: // %bb. 12 13 tail call fastcc void @callee_stack0() 14 ret void 15 16; COMMON-NEXT: b callee_stack0 17} 18 19define fastcc void @caller_to0_from8([8 x i64], i64) #0 { 20; COMMON-LABEL: caller_to0_from8: 21 22 tail call fastcc void @callee_stack0() 23 ret void 24 25; COMMON: add sp, sp, #16 26; COMMON: .cfi_def_cfa_offset -16 27; COMMON-NEXT: b callee_stack0 28} 29 30define fastcc void @caller_to8_from0() #0 { 31; COMMON-LABEL: caller_to8_from0: 32 33; Key point is that the "42" should go #16 below incoming stack 34; pointer (we didn't have arg space to reuse). 35 tail call fastcc void @callee_stack8([8 x i64] undef, i64 42) 36 ret void 37 38; COMMON: str {{x[0-9]+}}, [sp, #-16]! 39; COMMON-NEXT: .cfi_def_cfa_offset 16 40; COMMON-NEXT: b callee_stack8 41} 42 43define fastcc void @caller_to8_from8([8 x i64], i64 %a) #0 { 44; COMMON-LABEL: caller_to8_from8: 45; COMMON-NOT: sub sp, 46 47; Key point is that the "%a" should go where at SP on entry. 48 tail call fastcc void @callee_stack8([8 x i64] undef, i64 42) 49 ret void 50 51; COMMON: str {{x[0-9]+}}, [sp] 52; COMMON-NEXT: b callee_stack8 53} 54 55define fastcc void @caller_to16_from8([8 x i64], i64 %a) #0 { 56; COMMON-LABEL: caller_to16_from8: 57; COMMON-NOT: sub sp, 58 59; Important point is that the call reuses the "dead" argument space 60; above %a on the stack. If it tries to go below incoming-SP then the 61; callee will not deallocate the space, even in fastcc. 62 tail call fastcc void @callee_stack16([8 x i64] undef, i64 42, i64 2) 63 64; COMMON: stp {{x[0-9]+}}, {{x[0-9]+}}, [sp] 65; COMMON-NEXT: b callee_stack16 66 ret void 67} 68 69 70define fastcc void @caller_to8_from24([8 x i64], i64 %a, i64 %b, i64 %c) #0 { 71; COMMON-LABEL: caller_to8_from24: 72; COMMON-NOT: sub sp, 73 74; Key point is that the "%a" should go where at #16 above SP on entry. 75 tail call fastcc void @callee_stack8([8 x i64] undef, i64 42) 76 ret void 77 78; COMMON: str {{x[0-9]+}}, [sp, #16]! 79; COMMON: .cfi_def_cfa_offset -16 80; COMMON-NEXT: b callee_stack8 81} 82 83 84define fastcc void @caller_to16_from16([8 x i64], i64 %a, i64 %b) #0 { 85; COMMON-LABEL: caller_to16_from16: 86; COMMON-NOT: sub sp, 87 88; Here we want to make sure that both loads happen before the stores: 89; otherwise either %a or %b will be wrongly clobbered. 90 tail call fastcc void @callee_stack16([8 x i64] undef, i64 %b, i64 %a) 91 ret void 92 93; COMMON: ldp {{x[0-9]+}}, {{x[0-9]+}}, [sp] 94; COMMON: stp {{x[0-9]+}}, {{x[0-9]+}}, [sp] 95; COMMON-NEXT: b callee_stack16 96} 97 98define fastcc void @disable_tail_calls() nounwind "disable-tail-calls"="true" { 99; COMMON-LABEL: disable_tail_calls: 100; COMMON-NEXT: // %bb. 101 102 tail call fastcc void @callee_stack0() 103 ret void 104 105; COMMON: bl callee_stack0 106; COMMON: ret 107} 108 109; Weakly-referenced extern functions cannot be tail-called, as AAELF does 110; not define the behaviour of branch instructions to undefined weak symbols. 111define fastcc void @caller_weak() #0 { 112; COMMON-LABEL: caller_weak: 113; COMMON: bl callee_weak 114 tail call void @callee_weak() 115 ret void 116} 117 118declare { [2 x float] } @get_vec2() 119 120define { [3 x float] } @test_add_elem() #0 { 121; SDAG-LABEL: test_add_elem: 122; SDAG: bl get_vec2 123; SDAG: fmov s2, #1.0 124; SDAG: ret 125; GISEL-LABEL: test_add_elem: 126; GISEL: str x30, [sp, #-16]! 127; GISEL: bl get_vec2 128; GISEL: fmov s2, #1.0 129; GISEL: ldr x30, [sp], #16 130; GISEL: ret 131 132 %call = tail call { [2 x float] } @get_vec2() 133 %arr = extractvalue { [2 x float] } %call, 0 134 %arr.0 = extractvalue [2 x float] %arr, 0 135 %arr.1 = extractvalue [2 x float] %arr, 1 136 137 %res.0 = insertvalue { [3 x float] } undef, float %arr.0, 0, 0 138 %res.01 = insertvalue { [3 x float] } %res.0, float %arr.1, 0, 1 139 %res.012 = insertvalue { [3 x float] } %res.01, float 1.000000e+00, 0, 2 140 ret { [3 x float] } %res.012 141} 142 143declare double @get_double() 144define { double, [2 x double] } @test_mismatched_insert() #0 { 145; COMMON-LABEL: test_mismatched_insert: 146; COMMON: bl get_double 147; COMMON: bl get_double 148; COMMON: bl get_double 149; COMMON: ret 150 151 %val0 = call double @get_double() 152 %val1 = call double @get_double() 153 %val2 = tail call double @get_double() 154 155 %res.0 = insertvalue { double, [2 x double] } undef, double %val0, 0 156 %res.01 = insertvalue { double, [2 x double] } %res.0, double %val1, 1, 0 157 %res.012 = insertvalue { double, [2 x double] } %res.01, double %val2, 1, 1 158 159 ret { double, [2 x double] } %res.012 160} 161 162attributes #0 = { uwtable }