• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   -relocation-model=pic -enable-mips-tail-calls < %s | FileCheck %s -check-prefixes=ALL,O32,NOT-R6C
5; RUN: llc -march=mips   -mcpu=mips32r2 -relocation-model=pic -enable-mips-tail-calls < %s | FileCheck %s -check-prefixes=ALL,O32,NOT-R6C
6; RUN: llc -march=mips   -mcpu=mips32r3 -relocation-model=pic -enable-mips-tail-calls < %s | FileCheck %s -check-prefixes=ALL,O32,NOT-R6C
7; RUN: llc -march=mips   -mcpu=mips32r5 -relocation-model=pic -enable-mips-tail-calls < %s | FileCheck %s -check-prefixes=ALL,O32,NOT-R6C
8; RUN: llc -march=mips   -mcpu=mips32r6 -relocation-model=pic -disable-mips-delay-filler -enable-mips-tail-calls < %s | FileCheck %s -check-prefixes=ALL,O32,R6C
9; RUN: llc -march=mips   -mcpu=mips32r6 -relocation-model=pic -mattr=+fp64,+nooddspreg -disable-mips-delay-filler -enable-mips-tail-calls < %s | FileCheck %s -check-prefixes=ALL,O32,R6C
10; RUN: llc -march=mips64 -mcpu=mips4    -enable-mips-tail-calls < %s | FileCheck %s -check-prefixes=ALL,N64,NOT-R6C
11; RUN: llc -march=mips64 -mcpu=mips64   -enable-mips-tail-calls < %s | FileCheck %s -check-prefixes=ALL,N64,NOT-R6C
12; RUN: llc -march=mips64 -mcpu=mips64r2 -enable-mips-tail-calls < %s | FileCheck %s -check-prefixes=ALL,N64,NOT-R6C
13; RUN: llc -march=mips64 -mcpu=mips64r3 -enable-mips-tail-calls < %s | FileCheck %s -check-prefixes=ALL,N64,NOT-R6C
14; RUN: llc -march=mips64 -mcpu=mips64r5 -enable-mips-tail-calls < %s | FileCheck %s -check-prefixes=ALL,N64,NOT-R6C
15; RUN: llc -march=mips64 -mcpu=mips64r6 -disable-mips-delay-filler -enable-mips-tail-calls < %s | FileCheck %s -check-prefixes=ALL,N64,R6C
16
17declare void @extern_void_void()
18declare i32 @extern_i32_void()
19declare float @extern_float_void()
20
21define i32 @call_void_void() {
22; ALL-LABEL: call_void_void:
23
24; O32:           lw $[[TGT:[0-9]+]], %call16(extern_void_void)($gp)
25
26; N64:           ld $[[TGT:[0-9]+]], %call16(extern_void_void)($gp)
27
28; NOT-R6C:       jalr $[[TGT]]
29; R6C:           jalrc $[[TGT]]
30
31  call void @extern_void_void()
32; R6C:           jrc $ra
33  ret i32 0
34}
35
36define i32 @call_i32_void() {
37; ALL-LABEL: call_i32_void:
38
39; O32:           lw $[[TGT:[0-9]+]], %call16(extern_i32_void)($gp)
40
41; N64:           ld $[[TGT:[0-9]+]], %call16(extern_i32_void)($gp)
42
43; NOT-R6C:       jalr $[[TGT]]
44; R6C:           jalrc $[[TGT]]
45
46  %1 = call i32 @extern_i32_void()
47  %2 = add i32 %1, 1
48; R6C:           jrc $ra
49  ret i32 %2
50}
51
52define float @call_float_void() {
53; ALL-LABEL: call_float_void:
54
55; FIXME: Not sure why we don't use $gp directly on such a simple test. We should
56;        look into it at some point.
57; O32:           addu $[[GP:[0-9]+]], ${{[0-9]+}}, $25
58; O32:           lw $[[TGT:[0-9]+]], %call16(extern_float_void)($[[GP]])
59
60; N64:           ld $[[TGT:[0-9]+]], %call16(extern_float_void)($gp)
61
62; NOT-R6C:       jalr $[[TGT]]
63; R6C:           jalrc $[[TGT]]
64
65
66  %1 = call float @extern_float_void()
67  %2 = fadd float %1, 1.0
68; R6C:           jrc $ra
69  ret float %2
70}
71
72define void @musttail_call_void_void() {
73; ALL-LABEL: musttail_call_void_void:
74
75; O32:           lw $[[TGT:[0-9]+]], %call16(extern_void_void)($gp)
76
77; N64:           ld $[[TGT:[0-9]+]], %call16(extern_void_void)($gp)
78
79; ALL:           jr $[[TGT]]
80
81  musttail call void @extern_void_void()
82  ret void
83}
84
85define i32 @musttail_call_i32_void() {
86; ALL-LABEL: musttail_call_i32_void:
87
88; O32:           lw $[[TGT:[0-9]+]], %call16(extern_i32_void)($gp)
89
90; N64:           ld $[[TGT:[0-9]+]], %call16(extern_i32_void)($gp)
91
92; ALL:           jr $[[TGT]]
93
94  %1 = musttail call i32 @extern_i32_void()
95  ret i32 %1
96}
97
98define float @musttail_call_float_void() {
99; ALL-LABEL: musttail_call_float_void:
100
101; O32:           lw $[[TGT:[0-9]+]], %call16(extern_float_void)($gp)
102
103; N64:           ld $[[TGT:[0-9]+]], %call16(extern_float_void)($gp)
104
105; ALL:           jr $[[TGT]]
106
107  %1 = musttail call float @extern_float_void()
108  ret float %1
109}
110
111define i32 @indirect_call_void_void(void ()* %addr) {
112; ALL-LABEL: indirect_call_void_void:
113
114; ALL:           move $25, $4
115; NOT-R6C:       jalr $25
116; R6C:           jalrc $25
117
118  call void %addr()
119; R6C:           jrc $ra
120  ret i32 0
121}
122
123define i32 @indirect_call_i32_void(i32 ()* %addr) {
124; ALL-LABEL: indirect_call_i32_void:
125
126; ALL:           move $25, $4
127; NOT-R6C:       jalr $25
128; R6C:           jalrc $25
129
130
131  %1 = call i32 %addr()
132  %2 = add i32 %1, 1
133; R6C:           jrc $ra
134  ret i32 %2
135}
136
137define float @indirect_call_float_void(float ()* %addr) {
138; ALL-LABEL: indirect_call_float_void:
139
140; ALL:           move $25, $4
141; NOT-R6C:       jalr $25
142; R6C:           jalrc $25
143
144
145  %1 = call float %addr()
146  %2 = fadd float %1, 1.0
147; R6C:           jrc $ra
148  ret float %2
149}
150
151; We can't use 'musttail' here because the verifier is too conservative and
152; prohibits any prototype difference.
153define void @tail_indirect_call_void_void(void ()* %addr) {
154; ALL-LABEL: tail_indirect_call_void_void:
155
156; ALL:           move $25, $4
157; ALL:           jr $25
158
159  tail call void %addr()
160  ret void
161}
162
163define i32 @tail_indirect_call_i32_void(i32 ()* %addr) {
164; ALL-LABEL: tail_indirect_call_i32_void:
165
166; ALL:           move $25, $4
167; ALL:           jr $25
168
169  %1 = tail call i32 %addr()
170  ret i32 %1
171}
172
173define float @tail_indirect_call_float_void(float ()* %addr) {
174; ALL-LABEL: tail_indirect_call_float_void:
175
176; ALL:           move $25, $4
177; ALL:           jr $25
178
179  %1 = tail call float %addr()
180  ret float %1
181}
182
183; Check that passing undef as a double value doesn't cause machine code errors
184; for FP64.
185declare hidden void @undef_double(i32 %this, double %volume) unnamed_addr align 2
186
187define hidden void @thunk_undef_double(i32 %this, double %volume) unnamed_addr align 2 {
188; ALL-LABEL: thunk_undef_double:
189; O32: # implicit-def: %A2
190; O32: # implicit-def: %A3
191; ALL:        jr $25
192
193  tail call void @undef_double(i32 undef, double undef) #8
194  ret void
195}
196
197; Check that immediate addresses do not use jal.
198define i32 @jal_only_allows_symbols() {
199; ALL-LABEL: jal_only_allows_symbols:
200
201; ALL-NOT:       {{jal }}
202; ALL:           addiu $[[TGT:[0-9]+]], $zero, 1234
203; ALL-NOT:       {{jal }}
204; NOT-R6C:       jalr $[[TGT]]
205; R6C:           jalrc $[[TGT]]
206; ALL-NOT:       {{jal }}
207
208  call void () inttoptr (i32 1234 to void ()*)()
209; R6C:           jrc $ra
210  ret i32 0
211}
212
213