Index: test/CodeGen/Mips/llvm-ir/call.ll =================================================================== --- /dev/null +++ test/CodeGen/Mips/llvm-ir/call.ll @@ -0,0 +1,160 @@ +; Test the 'call' instruction and the tailcall variant. + +; FIXME: We should remove the need for -enable-mips-tail-calls +; RUN: llc -march=mips -mcpu=mips32 -enable-mips-tail-calls < %s | FileCheck %s -check-prefix=ALL -check-prefix=O32 +; RUN: llc -march=mips -mcpu=mips32r2 -enable-mips-tail-calls < %s | FileCheck %s -check-prefix=ALL -check-prefix=O32 +; RUN: llc -march=mips64 -mcpu=mips4 -enable-mips-tail-calls < %s | FileCheck %s -check-prefix=ALL -check-prefix=N64 +; RUN: llc -march=mips64 -mcpu=mips64 -enable-mips-tail-calls < %s | FileCheck %s -check-prefix=ALL -check-prefix=N64 + +declare void @extern_void_void() +declare i32 @extern_i32_void() +declare float @extern_float_void() + +define i32 @call_void_void() { +; ALL-LABEL: call_void_void: + +; O32: lw $[[TGT:[0-9]+]], %call16(extern_void_void)($gp) + +; N64: ld $[[TGT:[0-9]+]], %call16(extern_void_void)($gp) + +; ALL: jalr $[[TGT]] + + call void @extern_void_void() + ret i32 0 +} + +define i32 @call_i32_void() { +; ALL-LABEL: call_i32_void: + +; O32: lw $[[TGT:[0-9]+]], %call16(extern_i32_void)($gp) + +; N64: ld $[[TGT:[0-9]+]], %call16(extern_i32_void)($gp) + +; ALL: jalr $[[TGT]] + + %1 = call i32 @extern_i32_void() + %2 = add i32 %1, 1 + ret i32 %2 +} + +define float @call_float_void() { +; ALL-LABEL: call_float_void: + +; FIXME: Not sure why we don't use $gp directly on such a simple test. We should +; look into it at some point. +; O32: addu $[[GP:[0-9]+]], ${{[0-9]+}}, $25 +; O32: lw $[[TGT:[0-9]+]], %call16(extern_float_void)($[[GP]]) + +; N64: ld $[[TGT:[0-9]+]], %call16(extern_float_void)($gp) + +; ALL: jalr $[[TGT]] + +; O32: move $gp, $[[GP]] + + %1 = call float @extern_float_void() + %2 = fadd float %1, 1.0 + ret float %2 +} + +define void @musttail_call_void_void() { +; ALL-LABEL: musttail_call_void_void: + +; O32: lw $[[TGT:[0-9]+]], %call16(extern_void_void)($gp) + +; N64: ld $[[TGT:[0-9]+]], %call16(extern_void_void)($gp) + +; ALL: jr $[[TGT]] + + musttail call void @extern_void_void() + ret void +} + +define i32 @musttail_call_i32_void() { +; ALL-LABEL: musttail_call_i32_void: + +; O32: lw $[[TGT:[0-9]+]], %call16(extern_i32_void)($gp) + +; N64: ld $[[TGT:[0-9]+]], %call16(extern_i32_void)($gp) + +; ALL: jr $[[TGT]] + + %1 = musttail call i32 @extern_i32_void() + ret i32 %1 +} + +define float @musttail_call_float_void() { +; ALL-LABEL: musttail_call_float_void: + +; O32: lw $[[TGT:[0-9]+]], %call16(extern_float_void)($gp) + +; N64: ld $[[TGT:[0-9]+]], %call16(extern_float_void)($gp) + +; ALL: jr $[[TGT]] + + %1 = musttail call float @extern_float_void() + ret float %1 +} + +define i32 @indirect_call_void_void(void ()* %addr) { +; ALL-LABEL: indirect_call_void_void: + +; ALL: move $25, $4 +; ALL: jalr $25 + + call void %addr() + ret i32 0 +} + +define i32 @indirect_call_i32_void(i32 ()* %addr) { +; ALL-LABEL: indirect_call_i32_void: + +; ALL: move $25, $4 +; ALL: jalr $25 + + %1 = call i32 %addr() + %2 = add i32 %1, 1 + ret i32 %2 +} + +define float @indirect_call_float_void(float ()* %addr) { +; ALL-LABEL: indirect_call_float_void: + +; ALL: move $25, $4 +; ALL: jalr $25 + + %1 = call float %addr() + %2 = fadd float %1, 1.0 + ret float %2 +} + +; We can't use 'musttail' here because the verifier is too conservative and +; prohibits any prototype difference. +define void @tail_indirect_call_void_void(void ()* %addr) { +; ALL-LABEL: tail_indirect_call_void_void: + +; ALL: move $25, $4 +; ALL: jr $25 + + tail call void %addr() + ret void +} + +define i32 @tail_indirect_call_i32_void(i32 ()* %addr) { +; ALL-LABEL: tail_indirect_call_i32_void: + +; ALL: move $25, $4 +; ALL: jr $25 + + %1 = tail call i32 %addr() + ret i32 %1 +} + +define float @tail_indirect_call_float_void(float ()* %addr) { +; ALL-LABEL: tail_indirect_call_float_void: + +; ALL: move $25, $4 +; ALL: jr $25 + + %1 = tail call float %addr() + ret float %1 +} Index: test/CodeGen/Mips/llvm-ir/indirectbr.ll =================================================================== --- /dev/null +++ test/CodeGen/Mips/llvm-ir/indirectbr.ll @@ -0,0 +1,27 @@ +; Test all important variants of the unconditional 'br' instruction. + +; RUN: llc -march=mips -mcpu=mips32 < %s | FileCheck %s -check-prefix=ALL +; RUN: llc -march=mips -mcpu=mips32r2 < %s | FileCheck %s -check-prefix=ALL +; RUN: llc -march=mips64 -mcpu=mips4 < %s | FileCheck %s -check-prefix=ALL +; RUN: llc -march=mips64 -mcpu=mips64 < %s | FileCheck %s -check-prefix=ALL +; RUN: llc -march=mips64 -mcpu=mips64r2 < %s | FileCheck %s -check-prefix=ALL + +define i32 @br(i8 *%addr) { +; ALL-LABEL: br: +; ALL: jr $4 +; ALL: $BB0_1: # %L1 +; ALL: jr $ra +; ALL: addiu $2, $zero, 0 +; ALL: $BB0_2: # %L2 +; ALL: jr $ra +; ALL: addiu $2, $zero, 1 + +entry: + indirectbr i8* %addr, [label %L1, label %L2] + +L1: + ret i32 0 + +L2: + ret i32 1 +} Index: test/CodeGen/Mips/llvm-ir/ret.ll =================================================================== --- /dev/null +++ test/CodeGen/Mips/llvm-ir/ret.ll @@ -0,0 +1,166 @@ +; Test all important variants of the 'ret' instruction. +; +; For non-void returns it is necessary to have something to return so we also +; test constant generation here. +; +; We'll test pointer returns in a separate file since the relocation model +; affects it. + +; RUN: llc -march=mips -mcpu=mips32 < %s | FileCheck %s -check-prefix=ALL -check-prefix=GPR32 -check-prefix=NO-MTHC1 +; RUN: llc -march=mips -mcpu=mips32r2 < %s | FileCheck %s -check-prefix=ALL -check-prefix=GPR32 -check-prefix=MTHC1 +; RUN: llc -march=mips64 -mcpu=mips4 < %s | FileCheck %s -check-prefix=ALL -check-prefix=GPR64 -check-prefix=DMTC1 +; RUN: llc -march=mips64 -mcpu=mips64 < %s | FileCheck %s -check-prefix=ALL -check-prefix=GPR64 -check-prefix=DMTC1 +; RUN: llc -march=mips64 -mcpu=mips64r2 < %s | FileCheck %s -check-prefix=ALL -check-prefix=GPR64 -check-prefix=DMTC1 + +define void @ret_void() { +; ALL-LABEL: ret_void: +; ALL: jr $ra + ret void +} + +define i8 @ret_i8() { +; ALL-LABEL: ret_i8: +; ALL-DAG: jr $ra +; ALL-DAG: addiu $2, $zero, 3 + ret i8 3 +} + +define i16 @ret_i16_3() { +; ALL-LABEL: ret_i16_3: +; ALL-DAG: jr $ra +; ALL-DAG: addiu $2, $zero, 3 + ret i16 3 +} + +define i16 @ret_i16_256() { +; ALL-LABEL: ret_i16_256: +; ALL-DAG: jr $ra +; ALL-DAG: addiu $2, $zero, 256 + ret i16 256 +} + +define i16 @ret_i16_257() { +; ALL-LABEL: ret_i16_257: +; ALL-DAG: jr $ra +; ALL-DAG: addiu $2, $zero, 257 + ret i16 257 +} + +define i32 @ret_i32_257() { +; ALL-LABEL: ret_i32_257: +; ALL-DAG: jr $ra +; ALL-DAG: addiu $2, $zero, 257 + ret i32 257 +} + +define i32 @ret_i32_65536() { +; ALL-LABEL: ret_i32_65536: +; ALL-DAG: jr $ra +; ALL-DAG: lui $2, 1 + ret i32 65536 +} + +define i32 @ret_i32_65537() { +; ALL-LABEL: ret_i32_65537: +; ALL: lui $[[T0:[0-9]+]], 1 +; ALL-DAG: jr $ra +; ALL-DAG: ori $2, $[[T0]], 1 + ret i32 65537 +} + +define i64 @ret_i64_65537() { +; ALL-LABEL: ret_i64_65537: +; ALL: lui $[[T0:[0-9]+]], 1 + +; GPR32-DAG: ori $3, $[[T0]], 1 +; GPR32-DAG: addiu $2, $zero, 0 + +; GPR64-DAG: daddiu $2, $[[T0]], 1 + +; ALL-DAG: jr $ra + ret i64 65537 +} + +define i64 @ret_i64_281479271677952() { +; ALL-LABEL: ret_i64_281479271677952: +; ALL-DAG: lui $[[T0:[0-9]+]], 1 + +; GPR32-DAG: ori $2, $[[T0]], 1 +; GPR32-DAG: addiu $3, $zero, 0 + +; GPR64-DAG: daddiu $[[T1:[0-9]+]], $[[T0]], 1 +; GPR64-DAG: dsll $2, $[[T1]], 32 + +; ALL-DAG: jr $ra + ret i64 281479271677952 +} + +define i64 @ret_i64_281479271809026() { +; ALL-LABEL: ret_i64_281479271809026: +; GPR32-DAG: lui $[[T0:[0-9]+]], 1 +; GPR32-DAG: lui $[[T1:[0-9]+]], 2 +; GPR32-DAG: ori $2, $[[T0]], 1 +; GPR32-DAG: ori $3, $[[T1]], 2 + +; GPR64-DAG: ori $[[T0:[0-9]+]], $zero, 32769 +; GPR64-DAG: dsll $[[T1:[0-9]+]], $[[T0]], 16 +; GPR64-DAG: daddiu $[[T0:[0-9]+]], $[[T0]], -32767 +; GPR64-DAG: dsll $[[T1:[0-9]+]], $[[T0]], 17 +; GPR64-DAG: daddiu $2, $[[T1]], 2 + +; ALL-DAG: jr $ra + ret i64 281479271809026 +} + +; TODO: f32 +define float @ret_float_0x0() { +; ALL-LABEL: ret_float_0x0: + +; NO-MTHC1-DAG: mtc1 $zero, $f0 + +; MTHC1-DAG: mtc1 $zero, $f0 + +; DMTC-DAG: dmtc1 $zero, $f0 + +; ALL-DAG: jr $ra + ret float 0x0000000000000000 +} + +define float @ret_float_0x3() { +; ALL-LABEL: ret_float_0x3: + +; Use a constant pool +; O32-DAG: lwc1 $f0, %lo($CPI +; N64-DAG: lwc1 $f0, %got_ofst($CPI + +; ALL-DAG: jr $ra + +; float constants are written as double constants + ret float 0x36b8000000000000 +} + +define double @ret_double_0x0() { +; ALL-LABEL: ret_double_0x0: + +; NO-MTHC1-DAG: mtc1 $zero, $f0 +; NO-MTHC1-DAG: mtc1 $zero, $f1 + +; MTHC1-DAG: mtc1 $zero, $f0 +; MTHC1-DAG: mthc1 $zero, $f0 + +; DMTC-DAG: dmtc1 $zero, $f0 + +; ALL-DAG: jr $ra + ret double 0x0000000000000000 +} + +define double @ret_double_0x3() { +; ALL-LABEL: ret_double_0x3: + +; Use a constant pool +; O32-DAG: ldc1 $f0, %lo($CPI +; N64-DAG: ldc1 $f0, %got_ofst($CPI + +; ALL-DAG: jr $ra + ret double 0x0000000000000003 +}