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