| ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py | |
| ; RUN: llc -mtriple=mips-unknown-linux-gnu -mips-tail-calls=1 < %s | FileCheck %s --check-prefix=MIPS32 | |
| ; RUN: llc -mtriple=mips64-unknown-linux-gnu -mips-tail-calls=1 < %s | FileCheck %s --check-prefix=MIPS64 | |
| ; Test musttail support for MIPS | |
| define dso_local i32 @callee_args(i32 %a, i32 %b, i32 %c) { | |
| ; MIPS32-LABEL: callee_args: | |
| ; MIPS32: # %bb.0: | |
| ; MIPS32-NEXT: jr $ra | |
| ; MIPS32-NEXT: move $2, $4 | |
| ; | |
| ; MIPS64-LABEL: callee_args: | |
| ; MIPS64: # %bb.0: | |
| ; MIPS64-NEXT: jr $ra | |
| ; MIPS64-NEXT: sll $2, $4, 0 | |
| ret i32 %a; | |
| } | |
| define i32 @test_musttail_args(i32 %x, i32 %y, i32 %z) { | |
| ; MIPS32-LABEL: test_musttail_args: | |
| ; MIPS32: # %bb.0: | |
| ; MIPS32-NEXT: j callee_args | |
| ; MIPS32-NEXT: nop | |
| ; | |
| ; MIPS64-LABEL: test_musttail_args: | |
| ; MIPS64: # %bb.0: | |
| ; MIPS64-NEXT: j callee_args | |
| ; MIPS64-NEXT: nop | |
| %ret = musttail call i32 @callee_args(i32 %x, i32 %y, i32 %z) | |
| ret i32 %ret | |
| } | |
| ; Test musttail with many arguments that spill to stack (involves memory) | |
| ; MIPS O32 ABI: first 4 args in $a0-$a3, rest on stack | |
| define hidden i32 @many_args_callee(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, i32 %h) { | |
| ; MIPS32-LABEL: many_args_callee: | |
| ; MIPS32: # %bb.0: | |
| ; MIPS32-NEXT: jr $ra | |
| ; MIPS32-NEXT: move $2, $4 | |
| ; | |
| ; MIPS64-LABEL: many_args_callee: | |
| ; MIPS64: # %bb.0: | |
| ; MIPS64-NEXT: jr $ra | |
| ; MIPS64-NEXT: sll $2, $4, 0 | |
| ret i32 %a | |
| } | |
| define i32 @test_musttail_many_args(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, i32 %h) { | |
| ; MIPS32-LABEL: test_musttail_many_args: | |
| ; MIPS32: # %bb.0: | |
| ; MIPS32-NEXT: lw $1, 24($sp) | |
| ; MIPS32-NEXT: lw $2, 20($sp) | |
| ; MIPS32-NEXT: lw $3, 16($sp) | |
| ; MIPS32-NEXT: sw $3, 16($sp) | |
| ; MIPS32-NEXT: sw $2, 20($sp) | |
| ; MIPS32-NEXT: sw $1, 24($sp) | |
| ; MIPS32-NEXT: lw $1, 28($sp) | |
| ; MIPS32-NEXT: j many_args_callee | |
| ; MIPS32-NEXT: sw $1, 28($sp) | |
| ; | |
| ; MIPS64-LABEL: test_musttail_many_args: | |
| ; MIPS64: # %bb.0: | |
| ; MIPS64-NEXT: j many_args_callee | |
| ; MIPS64-NEXT: nop | |
| %ret = musttail call i32 @many_args_callee(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, i32 %h) | |
| ret i32 %ret | |
| } | |
| ; Test musttail with large struct passed by value (involves memory) | |
| %struct.large = type { i32, i32, i32, i32, i32, i32, i32, i32 } | |
| define hidden i32 @callee_with_struct(%struct.large %s, i32 %x) { | |
| ; MIPS32-LABEL: callee_with_struct: | |
| ; MIPS32: # %bb.0: | |
| ; MIPS32-NEXT: lw $2, 32($sp) | |
| ; MIPS32-NEXT: jr $ra | |
| ; MIPS32-NEXT: nop | |
| ; | |
| ; MIPS64-LABEL: callee_with_struct: | |
| ; MIPS64: # %bb.0: | |
| ; MIPS64-NEXT: lw $2, 4($sp) | |
| ; MIPS64-NEXT: jr $ra | |
| ; MIPS64-NEXT: nop | |
| ret i32 %x | |
| } | |
| define i32 @test_musttail_struct(%struct.large %s, i32 %x) { | |
| ; MIPS32-LABEL: test_musttail_struct: | |
| ; MIPS32: # %bb.0: | |
| ; MIPS32-NEXT: lw $1, 28($sp) | |
| ; MIPS32-NEXT: lw $2, 24($sp) | |
| ; MIPS32-NEXT: lw $3, 20($sp) | |
| ; MIPS32-NEXT: lw $8, 16($sp) | |
| ; MIPS32-NEXT: sw $8, 16($sp) | |
| ; MIPS32-NEXT: sw $3, 20($sp) | |
| ; MIPS32-NEXT: sw $2, 24($sp) | |
| ; MIPS32-NEXT: sw $1, 28($sp) | |
| ; MIPS32-NEXT: lw $1, 32($sp) | |
| ; MIPS32-NEXT: j callee_with_struct | |
| ; MIPS32-NEXT: sw $1, 32($sp) | |
| ; | |
| ; MIPS64-LABEL: test_musttail_struct: | |
| ; MIPS64: # %bb.0: | |
| ; MIPS64-NEXT: ld $1, 0($sp) | |
| ; MIPS64-NEXT: j callee_with_struct | |
| ; MIPS64-NEXT: sd $1, 0($sp) | |
| %ret = musttail call i32 @callee_with_struct(%struct.large %s, i32 %x) | |
| ret i32 %ret | |
| } | |
| ; Test musttail with mixed int and float arguments that use stack | |
| define hidden float @mixed_args_callee(i32 %a, float %b, i32 %c, float %d, i32 %e, float %f) { | |
| ; MIPS32-LABEL: mixed_args_callee: | |
| ; MIPS32: # %bb.0: | |
| ; MIPS32-NEXT: jr $ra | |
| ; MIPS32-NEXT: mtc1 $5, $f0 | |
| ; | |
| ; MIPS64-LABEL: mixed_args_callee: | |
| ; MIPS64: # %bb.0: | |
| ; MIPS64-NEXT: jr $ra | |
| ; MIPS64-NEXT: mov.s $f0, $f13 | |
| ret float %b | |
| } | |
| define float @test_musttail_mixed_args(i32 %a, float %b, i32 %c, float %d, i32 %e, float %f) { | |
| ; MIPS32-LABEL: test_musttail_mixed_args: | |
| ; MIPS32: # %bb.0: | |
| ; MIPS32-NEXT: lw $1, 16($sp) | |
| ; MIPS32-NEXT: sw $1, 16($sp) | |
| ; MIPS32-NEXT: lwc1 $f0, 20($sp) | |
| ; MIPS32-NEXT: j mixed_args_callee | |
| ; MIPS32-NEXT: swc1 $f0, 20($sp) | |
| ; | |
| ; MIPS64-LABEL: test_musttail_mixed_args: | |
| ; MIPS64: # %bb.0: | |
| ; MIPS64-NEXT: j mixed_args_callee | |
| ; MIPS64-NEXT: nop | |
| %ret = musttail call float @mixed_args_callee(i32 %a, float %b, i32 %c, float %d, i32 %e, float %f) | |
| ret float %ret | |
| } | |
| ; Test musttail with indirect call | |
| define i32 @test_musttail_fptr(ptr %fptr, i32 %x) { | |
| ; MIPS32-LABEL: test_musttail_fptr: | |
| ; MIPS32: # %bb.0: | |
| ; MIPS32-NEXT: move $25, $4 | |
| ; MIPS32-NEXT: jr $25 | |
| ; MIPS32-NEXT: nop | |
| ; | |
| ; MIPS64-LABEL: test_musttail_fptr: | |
| ; MIPS64: # %bb.0: | |
| ; MIPS64-NEXT: move $25, $4 | |
| ; MIPS64-NEXT: jr $25 | |
| ; MIPS64-NEXT: nop | |
| %ret = musttail call i32 %fptr(ptr %fptr, i32 %x) | |
| ret i32 %ret | |
| } |