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   -relocation-model=pic -enable-mips-tail-calls < %s | FileCheck %s -check-prefixes=ALL,O32,NOT-R6C
      5 ; RUN: llc -march=mips   -mcpu=mips32r2 -relocation-model=pic -enable-mips-tail-calls < %s | FileCheck %s -check-prefixes=ALL,O32,NOT-R6C
      6 ; RUN: llc -march=mips   -mcpu=mips32r3 -relocation-model=pic -enable-mips-tail-calls < %s | FileCheck %s -check-prefixes=ALL,O32,NOT-R6C
      7 ; RUN: llc -march=mips   -mcpu=mips32r5 -relocation-model=pic -enable-mips-tail-calls < %s | FileCheck %s -check-prefixes=ALL,O32,NOT-R6C
      8 ; RUN: llc -march=mips   -mcpu=mips32r6 -relocation-model=pic -disable-mips-delay-filler -enable-mips-tail-calls < %s | FileCheck %s -check-prefixes=ALL,O32,R6C
      9 ; RUN: llc -march=mips   -mcpu=mips32r6 -relocation-model=pic -mattr=+fp64,+nooddspreg -disable-mips-delay-filler -enable-mips-tail-calls < %s | FileCheck %s -check-prefixes=ALL,O32,R6C
     10 ; RUN: llc -march=mips64 -mcpu=mips4    -enable-mips-tail-calls < %s | FileCheck %s -check-prefixes=ALL,N64,NOT-R6C
     11 ; RUN: llc -march=mips64 -mcpu=mips64   -enable-mips-tail-calls < %s | FileCheck %s -check-prefixes=ALL,N64,NOT-R6C
     12 ; RUN: llc -march=mips64 -mcpu=mips64r2 -enable-mips-tail-calls < %s | FileCheck %s -check-prefixes=ALL,N64,NOT-R6C
     13 ; RUN: llc -march=mips64 -mcpu=mips64r3 -enable-mips-tail-calls < %s | FileCheck %s -check-prefixes=ALL,N64,NOT-R6C
     14 ; RUN: llc -march=mips64 -mcpu=mips64r5 -enable-mips-tail-calls < %s | FileCheck %s -check-prefixes=ALL,N64,NOT-R6C
     15 ; RUN: llc -march=mips64 -mcpu=mips64r6 -disable-mips-delay-filler -enable-mips-tail-calls < %s | FileCheck %s -check-prefixes=ALL,N64,R6C
     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 ; NOT-R6C:       jalr $[[TGT]]
     29 ; R6C:           jalrc $[[TGT]]
     30 
     31   call void @extern_void_void()
     32 ; R6C:           jrc $ra
     33   ret i32 0
     34 }
     35 
     36 define i32 @call_i32_void() {
     37 ; ALL-LABEL: call_i32_void:
     38 
     39 ; O32:           lw $[[TGT:[0-9]+]], %call16(extern_i32_void)($gp)
     40 
     41 ; N64:           ld $[[TGT:[0-9]+]], %call16(extern_i32_void)($gp)
     42 
     43 ; NOT-R6C:       jalr $[[TGT]]
     44 ; R6C:           jalrc $[[TGT]]
     45 
     46   %1 = call i32 @extern_i32_void()
     47   %2 = add i32 %1, 1
     48 ; R6C:           jrc $ra
     49   ret i32 %2
     50 }
     51 
     52 define float @call_float_void() {
     53 ; ALL-LABEL: call_float_void:
     54 
     55 ; FIXME: Not sure why we don't use $gp directly on such a simple test. We should
     56 ;        look into it at some point.
     57 ; O32:           addu $[[GP:[0-9]+]], ${{[0-9]+}}, $25
     58 ; O32:           lw $[[TGT:[0-9]+]], %call16(extern_float_void)($[[GP]])
     59 
     60 ; N64:           ld $[[TGT:[0-9]+]], %call16(extern_float_void)($gp)
     61 
     62 ; NOT-R6C:       jalr $[[TGT]]
     63 ; R6C:           jalrc $[[TGT]]
     64 
     65 
     66   %1 = call float @extern_float_void()
     67   %2 = fadd float %1, 1.0
     68 ; R6C:           jrc $ra
     69   ret float %2
     70 }
     71 
     72 define void @musttail_call_void_void() {
     73 ; ALL-LABEL: musttail_call_void_void:
     74 
     75 ; O32:           lw $[[TGT:[0-9]+]], %call16(extern_void_void)($gp)
     76 
     77 ; N64:           ld $[[TGT:[0-9]+]], %call16(extern_void_void)($gp)
     78 
     79 ; ALL:           jr $[[TGT]]
     80 
     81   musttail call void @extern_void_void()
     82   ret void
     83 }
     84 
     85 define i32 @musttail_call_i32_void() {
     86 ; ALL-LABEL: musttail_call_i32_void:
     87 
     88 ; O32:           lw $[[TGT:[0-9]+]], %call16(extern_i32_void)($gp)
     89 
     90 ; N64:           ld $[[TGT:[0-9]+]], %call16(extern_i32_void)($gp)
     91 
     92 ; ALL:           jr $[[TGT]]
     93 
     94   %1 = musttail call i32 @extern_i32_void()
     95   ret i32 %1
     96 }
     97 
     98 define float @musttail_call_float_void() {
     99 ; ALL-LABEL: musttail_call_float_void:
    100 
    101 ; O32:           lw $[[TGT:[0-9]+]], %call16(extern_float_void)($gp)
    102 
    103 ; N64:           ld $[[TGT:[0-9]+]], %call16(extern_float_void)($gp)
    104 
    105 ; ALL:           jr $[[TGT]]
    106 
    107   %1 = musttail call float @extern_float_void()
    108   ret float %1
    109 }
    110 
    111 define i32 @indirect_call_void_void(void ()* %addr) {
    112 ; ALL-LABEL: indirect_call_void_void:
    113 
    114 ; ALL:           move $25, $4
    115 ; NOT-R6C:       jalr $25
    116 ; R6C:           jalrc $25
    117 
    118   call void %addr()
    119 ; R6C:           jrc $ra
    120   ret i32 0
    121 }
    122 
    123 define i32 @indirect_call_i32_void(i32 ()* %addr) {
    124 ; ALL-LABEL: indirect_call_i32_void:
    125 
    126 ; ALL:           move $25, $4
    127 ; NOT-R6C:       jalr $25
    128 ; R6C:           jalrc $25
    129 
    130 
    131   %1 = call i32 %addr()
    132   %2 = add i32 %1, 1
    133 ; R6C:           jrc $ra
    134   ret i32 %2
    135 }
    136 
    137 define float @indirect_call_float_void(float ()* %addr) {
    138 ; ALL-LABEL: indirect_call_float_void:
    139 
    140 ; ALL:           move $25, $4
    141 ; NOT-R6C:       jalr $25
    142 ; R6C:           jalrc $25
    143 
    144 
    145   %1 = call float %addr()
    146   %2 = fadd float %1, 1.0
    147 ; R6C:           jrc $ra
    148   ret float %2
    149 }
    150 
    151 ; We can't use 'musttail' here because the verifier is too conservative and
    152 ; prohibits any prototype difference.
    153 define void @tail_indirect_call_void_void(void ()* %addr) {
    154 ; ALL-LABEL: tail_indirect_call_void_void:
    155 
    156 ; ALL:           move $25, $4
    157 ; ALL:           jr $25
    158 
    159   tail call void %addr()
    160   ret void
    161 }
    162 
    163 define i32 @tail_indirect_call_i32_void(i32 ()* %addr) {
    164 ; ALL-LABEL: tail_indirect_call_i32_void:
    165 
    166 ; ALL:           move $25, $4
    167 ; ALL:           jr $25
    168 
    169   %1 = tail call i32 %addr()
    170   ret i32 %1
    171 }
    172 
    173 define float @tail_indirect_call_float_void(float ()* %addr) {
    174 ; ALL-LABEL: tail_indirect_call_float_void:
    175 
    176 ; ALL:           move $25, $4
    177 ; ALL:           jr $25
    178 
    179   %1 = tail call float %addr()
    180   ret float %1
    181 }
    182 
    183 ; Check that passing undef as a double value doesn't cause machine code errors
    184 ; for FP64.
    185 declare hidden void @undef_double(i32 %this, double %volume) unnamed_addr align 2
    186 
    187 define hidden void @thunk_undef_double(i32 %this, double %volume) unnamed_addr align 2 {
    188 ; ALL-LABEL: thunk_undef_double:
    189 ; O32: # implicit-def: %A2
    190 ; O32: # implicit-def: %A3
    191 ; ALL:        jr $25
    192 
    193   tail call void @undef_double(i32 undef, double undef) #8
    194   ret void
    195 }
    196 
    197 ; Check that immediate addresses do not use jal.
    198 define i32 @jal_only_allows_symbols() {
    199 ; ALL-LABEL: jal_only_allows_symbols:
    200 
    201 ; ALL-NOT:       {{jal }}
    202 ; ALL:           addiu $[[TGT:[0-9]+]], $zero, 1234
    203 ; ALL-NOT:       {{jal }}
    204 ; NOT-R6C:       jalr $[[TGT]]
    205 ; R6C:           jalrc $[[TGT]]
    206 ; ALL-NOT:       {{jal }}
    207 
    208   call void () inttoptr (i32 1234 to void ()*)()
    209 ; R6C:           jrc $ra
    210   ret i32 0
    211 }
    212 
    213