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