Home | History | Annotate | Download | only in llvm-ir
      1 ; Test the 'call' instruction and the tailcall variant.
      2 
      3 ; FIXME: We should remove the need for -enable-mips-tail-calls
      4 ; RUN: llc -march=mips   -mcpu=mips32   -enable-mips-tail-calls < %s | FileCheck %s -check-prefix=ALL -check-prefix=O32
      5 ; RUN: llc -march=mips   -mcpu=mips32r2 -enable-mips-tail-calls < %s | FileCheck %s -check-prefix=ALL -check-prefix=O32
      6 ; RUN: llc -march=mips   -mcpu=mips32r3 -enable-mips-tail-calls < %s | FileCheck %s -check-prefix=ALL -check-prefix=O32
      7 ; RUN: llc -march=mips   -mcpu=mips32r5 -enable-mips-tail-calls < %s | FileCheck %s -check-prefix=ALL -check-prefix=O32
      8 ; RUN: llc -march=mips   -mcpu=mips32r6 -enable-mips-tail-calls < %s | FileCheck %s -check-prefix=ALL -check-prefix=O32
      9 ; RUN: llc -march=mips   -mcpu=mips32r6 -mattr=+fp64,+nooddspreg -enable-mips-tail-calls < %s | FileCheck %s -check-prefix=ALL -check-prefix=O32
     10 ; RUN: llc -march=mips64 -mcpu=mips4    -enable-mips-tail-calls < %s | FileCheck %s -check-prefix=ALL -check-prefix=N64
     11 ; RUN: llc -march=mips64 -mcpu=mips64   -enable-mips-tail-calls < %s | FileCheck %s -check-prefix=ALL -check-prefix=N64
     12 ; RUN: llc -march=mips64 -mcpu=mips64r2 -enable-mips-tail-calls < %s | FileCheck %s -check-prefix=ALL -check-prefix=N64
     13 ; RUN: llc -march=mips64 -mcpu=mips64r3 -enable-mips-tail-calls < %s | FileCheck %s -check-prefix=ALL -check-prefix=N64
     14 ; RUN: llc -march=mips64 -mcpu=mips64r5 -enable-mips-tail-calls < %s | FileCheck %s -check-prefix=ALL -check-prefix=N64
     15 ; RUN: llc -march=mips64 -mcpu=mips64r6 -enable-mips-tail-calls < %s | FileCheck %s -check-prefix=ALL -check-prefix=N64
     16 
     17 declare void @extern_void_void()
     18 declare i32 @extern_i32_void()
     19 declare float @extern_float_void()
     20 
     21 define i32 @call_void_void() {
     22 ; ALL-LABEL: call_void_void:
     23 
     24 ; O32:           lw $[[TGT:[0-9]+]], %call16(extern_void_void)($gp)
     25 
     26 ; N64:           ld $[[TGT:[0-9]+]], %call16(extern_void_void)($gp)
     27 
     28 ; ALL:           jalr $[[TGT]]
     29 
     30   call void @extern_void_void()
     31   ret i32 0
     32 }
     33 
     34 define i32 @call_i32_void() {
     35 ; ALL-LABEL: call_i32_void:
     36 
     37 ; O32:           lw $[[TGT:[0-9]+]], %call16(extern_i32_void)($gp)
     38 
     39 ; N64:           ld $[[TGT:[0-9]+]], %call16(extern_i32_void)($gp)
     40 
     41 ; ALL:           jalr $[[TGT]]
     42 
     43   %1 = call i32 @extern_i32_void()
     44   %2 = add i32 %1, 1
     45   ret i32 %2
     46 }
     47 
     48 define float @call_float_void() {
     49 ; ALL-LABEL: call_float_void:
     50 
     51 ; FIXME: Not sure why we don't use $gp directly on such a simple test. We should
     52 ;        look into it at some point.
     53 ; O32:           addu $[[GP:[0-9]+]], ${{[0-9]+}}, $25
     54 ; O32:           lw $[[TGT:[0-9]+]], %call16(extern_float_void)($[[GP]])
     55 
     56 ; N64:           ld $[[TGT:[0-9]+]], %call16(extern_float_void)($gp)
     57 
     58 ; ALL:           jalr $[[TGT]]
     59 
     60 ; O32:           move $gp, $[[GP]]
     61 
     62   %1 = call float @extern_float_void()
     63   %2 = fadd float %1, 1.0
     64   ret float %2
     65 }
     66 
     67 define void @musttail_call_void_void() {
     68 ; ALL-LABEL: musttail_call_void_void:
     69 
     70 ; O32:           lw $[[TGT:[0-9]+]], %call16(extern_void_void)($gp)
     71 
     72 ; N64:           ld $[[TGT:[0-9]+]], %call16(extern_void_void)($gp)
     73 
     74 ; NOT-R6:        jr $[[TGT]]
     75 ; R6:            r6.jr $[[TGT]]
     76 
     77   musttail call void @extern_void_void()
     78   ret void
     79 }
     80 
     81 define i32 @musttail_call_i32_void() {
     82 ; ALL-LABEL: musttail_call_i32_void:
     83 
     84 ; O32:           lw $[[TGT:[0-9]+]], %call16(extern_i32_void)($gp)
     85 
     86 ; N64:           ld $[[TGT:[0-9]+]], %call16(extern_i32_void)($gp)
     87 
     88 ; NOT-R6:        jr $[[TGT]]
     89 ; R6:            r6.jr $[[TGT]]
     90 
     91   %1 = musttail call i32 @extern_i32_void()
     92   ret i32 %1
     93 }
     94 
     95 define float @musttail_call_float_void() {
     96 ; ALL-LABEL: musttail_call_float_void:
     97 
     98 ; O32:           lw $[[TGT:[0-9]+]], %call16(extern_float_void)($gp)
     99 
    100 ; N64:           ld $[[TGT:[0-9]+]], %call16(extern_float_void)($gp)
    101 
    102 ; NOT-R6:        jr $[[TGT]]
    103 ; R6:            r6.jr $[[TGT]]
    104 
    105   %1 = musttail call float @extern_float_void()
    106   ret float %1
    107 }
    108 
    109 define i32 @indirect_call_void_void(void ()* %addr) {
    110 ; ALL-LABEL: indirect_call_void_void:
    111 
    112 ; ALL:           move $25, $4
    113 ; ALL:           jalr $25
    114 
    115   call void %addr()
    116   ret i32 0
    117 }
    118 
    119 define i32 @indirect_call_i32_void(i32 ()* %addr) {
    120 ; ALL-LABEL: indirect_call_i32_void:
    121 
    122 ; ALL:           move $25, $4
    123 ; ALL:           jalr $25
    124 
    125   %1 = call i32 %addr()
    126   %2 = add i32 %1, 1
    127   ret i32 %2
    128 }
    129 
    130 define float @indirect_call_float_void(float ()* %addr) {
    131 ; ALL-LABEL: indirect_call_float_void:
    132 
    133 ; ALL:           move $25, $4
    134 ; ALL:           jalr $25
    135 
    136   %1 = call float %addr()
    137   %2 = fadd float %1, 1.0
    138   ret float %2
    139 }
    140 
    141 ; We can't use 'musttail' here because the verifier is too conservative and
    142 ; prohibits any prototype difference.
    143 define void @tail_indirect_call_void_void(void ()* %addr) {
    144 ; ALL-LABEL: tail_indirect_call_void_void:
    145 
    146 ; ALL:           move $25, $4
    147 ; ALL:           jr $25
    148 
    149   tail call void %addr()
    150   ret void
    151 }
    152 
    153 define i32 @tail_indirect_call_i32_void(i32 ()* %addr) {
    154 ; ALL-LABEL: tail_indirect_call_i32_void:
    155 
    156 ; ALL:           move $25, $4
    157 ; ALL:           jr $25
    158 
    159   %1 = tail call i32 %addr()
    160   ret i32 %1
    161 }
    162 
    163 define float @tail_indirect_call_float_void(float ()* %addr) {
    164 ; ALL-LABEL: tail_indirect_call_float_void:
    165 
    166 ; ALL:           move $25, $4
    167 ; ALL:           jr $25
    168 
    169   %1 = tail call float %addr()
    170   ret float %1
    171 }
    172 
    173 ; Check that passing undef as a double value doesn't cause machine code errors
    174 ; for FP64.
    175 declare hidden void @undef_double(i32 %this, double %volume) unnamed_addr align 2
    176 
    177 define hidden void @thunk_undef_double(i32 %this, double %volume) unnamed_addr align 2 {
    178 ; ALL-LABEL: thunk_undef_double:
    179 ; O32: # implicit-def: %A2
    180 ; O32: # implicit-def: %A3
    181 ; ALL: jr $25
    182   tail call void @undef_double(i32 undef, double undef) #8
    183   ret void
    184 }
    185