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=mips32r6 -enable-mips-tail-calls < %s | FileCheck %s -check-prefix=ALL -check-prefix=O32 7 ; RUN: llc -march=mips64 -mcpu=mips4 -enable-mips-tail-calls < %s | FileCheck %s -check-prefix=ALL -check-prefix=N64 8 ; RUN: llc -march=mips64 -mcpu=mips64 -enable-mips-tail-calls < %s | FileCheck %s -check-prefix=ALL -check-prefix=N64 9 ; RUN: llc -march=mips64 -mcpu=mips64r2 -enable-mips-tail-calls < %s | FileCheck %s -check-prefix=ALL -check-prefix=N64 10 ; RUN: llc -march=mips64 -mcpu=mips64r6 -enable-mips-tail-calls < %s | FileCheck %s -check-prefix=ALL -check-prefix=N64 11 12 declare void @extern_void_void() 13 declare i32 @extern_i32_void() 14 declare float @extern_float_void() 15 16 define i32 @call_void_void() { 17 ; ALL-LABEL: call_void_void: 18 19 ; O32: lw $[[TGT:[0-9]+]], %call16(extern_void_void)($gp) 20 21 ; N64: ld $[[TGT:[0-9]+]], %call16(extern_void_void)($gp) 22 23 ; ALL: jalr $[[TGT]] 24 25 call void @extern_void_void() 26 ret i32 0 27 } 28 29 define i32 @call_i32_void() { 30 ; ALL-LABEL: call_i32_void: 31 32 ; O32: lw $[[TGT:[0-9]+]], %call16(extern_i32_void)($gp) 33 34 ; N64: ld $[[TGT:[0-9]+]], %call16(extern_i32_void)($gp) 35 36 ; ALL: jalr $[[TGT]] 37 38 %1 = call i32 @extern_i32_void() 39 %2 = add i32 %1, 1 40 ret i32 %2 41 } 42 43 define float @call_float_void() { 44 ; ALL-LABEL: call_float_void: 45 46 ; FIXME: Not sure why we don't use $gp directly on such a simple test. We should 47 ; look into it at some point. 48 ; O32: addu $[[GP:[0-9]+]], ${{[0-9]+}}, $25 49 ; O32: lw $[[TGT:[0-9]+]], %call16(extern_float_void)($[[GP]]) 50 51 ; N64: ld $[[TGT:[0-9]+]], %call16(extern_float_void)($gp) 52 53 ; ALL: jalr $[[TGT]] 54 55 ; O32: move $gp, $[[GP]] 56 57 %1 = call float @extern_float_void() 58 %2 = fadd float %1, 1.0 59 ret float %2 60 } 61 62 define void @musttail_call_void_void() { 63 ; ALL-LABEL: musttail_call_void_void: 64 65 ; O32: lw $[[TGT:[0-9]+]], %call16(extern_void_void)($gp) 66 67 ; N64: ld $[[TGT:[0-9]+]], %call16(extern_void_void)($gp) 68 69 ; NOT-R6: jr $[[TGT]] 70 ; R6: r6.jr $[[TGT]] 71 72 musttail call void @extern_void_void() 73 ret void 74 } 75 76 define i32 @musttail_call_i32_void() { 77 ; ALL-LABEL: musttail_call_i32_void: 78 79 ; O32: lw $[[TGT:[0-9]+]], %call16(extern_i32_void)($gp) 80 81 ; N64: ld $[[TGT:[0-9]+]], %call16(extern_i32_void)($gp) 82 83 ; NOT-R6: jr $[[TGT]] 84 ; R6: r6.jr $[[TGT]] 85 86 %1 = musttail call i32 @extern_i32_void() 87 ret i32 %1 88 } 89 90 define float @musttail_call_float_void() { 91 ; ALL-LABEL: musttail_call_float_void: 92 93 ; O32: lw $[[TGT:[0-9]+]], %call16(extern_float_void)($gp) 94 95 ; N64: ld $[[TGT:[0-9]+]], %call16(extern_float_void)($gp) 96 97 ; NOT-R6: jr $[[TGT]] 98 ; R6: r6.jr $[[TGT]] 99 100 %1 = musttail call float @extern_float_void() 101 ret float %1 102 } 103 104 define i32 @indirect_call_void_void(void ()* %addr) { 105 ; ALL-LABEL: indirect_call_void_void: 106 107 ; ALL: move $25, $4 108 ; ALL: jalr $25 109 110 call void %addr() 111 ret i32 0 112 } 113 114 define i32 @indirect_call_i32_void(i32 ()* %addr) { 115 ; ALL-LABEL: indirect_call_i32_void: 116 117 ; ALL: move $25, $4 118 ; ALL: jalr $25 119 120 %1 = call i32 %addr() 121 %2 = add i32 %1, 1 122 ret i32 %2 123 } 124 125 define float @indirect_call_float_void(float ()* %addr) { 126 ; ALL-LABEL: indirect_call_float_void: 127 128 ; ALL: move $25, $4 129 ; ALL: jalr $25 130 131 %1 = call float %addr() 132 %2 = fadd float %1, 1.0 133 ret float %2 134 } 135 136 ; We can't use 'musttail' here because the verifier is too conservative and 137 ; prohibits any prototype difference. 138 define void @tail_indirect_call_void_void(void ()* %addr) { 139 ; ALL-LABEL: tail_indirect_call_void_void: 140 141 ; ALL: move $25, $4 142 ; ALL: jr $25 143 144 tail call void %addr() 145 ret void 146 } 147 148 define i32 @tail_indirect_call_i32_void(i32 ()* %addr) { 149 ; ALL-LABEL: tail_indirect_call_i32_void: 150 151 ; ALL: move $25, $4 152 ; ALL: jr $25 153 154 %1 = tail call i32 %addr() 155 ret i32 %1 156 } 157 158 define float @tail_indirect_call_float_void(float ()* %addr) { 159 ; ALL-LABEL: tail_indirect_call_float_void: 160 161 ; ALL: move $25, $4 162 ; ALL: jr $25 163 164 %1 = tail call float %addr() 165 ret float %1 166 } 167