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