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