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 12declare void @extern_void_void() 13declare i32 @extern_i32_void() 14declare float @extern_float_void() 15 16define 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 29define 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 43define 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 62define 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 76define 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 90define 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 104define 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 114define 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 125define 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. 138define 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 148define 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 158define 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