]>
Commit | Line | Data |
---|---|---|
afba61d1 | 1 | /* mips16 floating point support code |
5d5bf775 | 2 | Copyright (C) 1996-2013 Free Software Foundation, Inc. |
afba61d1 ILT |
3 | Contributed by Cygnus Support |
4 | ||
5 | This file is free software; you can redistribute it and/or modify it | |
6 | under the terms of the GNU General Public License as published by the | |
748086b7 | 7 | Free Software Foundation; either version 3, or (at your option) any |
afba61d1 ILT |
8 | later version. |
9 | ||
afba61d1 ILT |
10 | This file is distributed in the hope that it will be useful, but |
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | General Public License for more details. | |
14 | ||
748086b7 JJ |
15 | Under Section 7 of GPL version 3, you are granted additional |
16 | permissions described in the GCC Runtime Library Exception, version | |
17 | 3.1, as published by the Free Software Foundation. | |
afba61d1 | 18 | |
748086b7 JJ |
19 | You should have received a copy of the GNU General Public License and |
20 | a copy of the GCC Runtime Library Exception along with this program; | |
21 | see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
22 | <http://www.gnu.org/licenses/>. */ | |
afba61d1 | 23 | |
22c4c869 CM |
24 | #ifdef __mips_micromips |
25 | /* DO NOTHING */ | |
26 | #else | |
27 | ||
afba61d1 ILT |
28 | /* This file contains mips16 floating point support functions. These |
29 | functions are called by mips16 code to handle floating point when | |
30 | -msoft-float is not used. They accept the arguments and return | |
31 | values using the soft-float calling convention, but do the actual | |
32 | operation using the hard floating point instructions. */ | |
33 | ||
08d0963a RS |
34 | #if defined _MIPS_SIM && (_MIPS_SIM == _ABIO32 || _MIPS_SIM == _ABIO64) |
35 | ||
85f65093 | 36 | /* This file contains 32-bit assembly code. */ |
afba61d1 ILT |
37 | .set nomips16 |
38 | ||
987ba558 | 39 | /* Start a function. */ |
afba61d1 ILT |
40 | |
41 | #define STARTFN(NAME) .globl NAME; .ent NAME; NAME: | |
42 | ||
43 | /* Finish a function. */ | |
44 | ||
45 | #define ENDFN(NAME) .end NAME | |
46 | ||
a38e0142 SL |
47 | /* ARG1 |
48 | The FPR that holds the first floating-point argument. | |
afba61d1 | 49 | |
a38e0142 SL |
50 | ARG2 |
51 | The FPR that holds the second floating-point argument. | |
afba61d1 | 52 | |
a38e0142 SL |
53 | RET |
54 | The FPR that holds a floating-point return value. */ | |
55 | ||
56 | #define RET $f0 | |
57 | #define ARG1 $f12 | |
58 | #ifdef __mips64 | |
59 | #define ARG2 $f13 | |
60 | #else | |
61 | #define ARG2 $f14 | |
62 | #endif | |
63 | ||
64 | /* Set 64-bit register GPR so that its high 32 bits contain HIGH_FPR | |
65 | and so that its low 32 bits contain LOW_FPR. */ | |
66 | #define MERGE_GPRf(GPR, HIGH_FPR, LOW_FPR) \ | |
67 | .set noat; \ | |
a38e0142 | 68 | mfc1 $1, LOW_FPR; \ |
93f63c68 RS |
69 | mfc1 GPR, HIGH_FPR; \ |
70 | dsll $1, $1, 32; \ | |
a38e0142 | 71 | dsll GPR, GPR, 32; \ |
93f63c68 | 72 | dsrl $1, $1, 32; \ |
a38e0142 SL |
73 | or GPR, GPR, $1; \ |
74 | .set at | |
75 | ||
76 | /* Move the high 32 bits of GPR to HIGH_FPR and the low 32 bits of | |
77 | GPR to LOW_FPR. */ | |
78 | #define MERGE_GPRt(GPR, HIGH_FPR, LOW_FPR) \ | |
79 | .set noat; \ | |
80 | dsrl $1, GPR, 32; \ | |
81 | mtc1 GPR, LOW_FPR; \ | |
82 | mtc1 $1, HIGH_FPR; \ | |
83 | .set at | |
84 | ||
85 | /* Jump to T, and use "OPCODE, OP2" to implement a delayed move. */ | |
86 | #define DELAYt(T, OPCODE, OP2) \ | |
87 | .set noreorder; \ | |
88 | jr T; \ | |
89 | OPCODE, OP2; \ | |
90 | .set reorder | |
91 | ||
92 | /* Use "OPCODE. OP2" and jump to T. */ | |
93 | #define DELAYf(T, OPCODE, OP2) OPCODE, OP2; jr T | |
94 | ||
95 | /* MOVE_SF_BYTE0(D) | |
96 | Move the first single-precision floating-point argument between | |
97 | GPRs and FPRs. | |
98 | ||
99 | MOVE_SI_BYTE0(D) | |
100 | Likewise the first single-precision integer argument. | |
101 | ||
102 | MOVE_SF_BYTE4(D) | |
103 | Move the second single-precision floating-point argument between | |
104 | GPRs and FPRs, given that the first argument occupies 4 bytes. | |
105 | ||
106 | MOVE_SF_BYTE8(D) | |
107 | Move the second single-precision floating-point argument between | |
108 | GPRs and FPRs, given that the first argument occupies 8 bytes. | |
109 | ||
110 | MOVE_DF_BYTE0(D) | |
111 | Move the first double-precision floating-point argument between | |
112 | GPRs and FPRs. | |
113 | ||
114 | MOVE_DF_BYTE8(D) | |
115 | Likewise the second double-precision floating-point argument. | |
116 | ||
117 | MOVE_SF_RET(D, T) | |
118 | Likewise a single-precision floating-point return value, | |
119 | then jump to T. | |
120 | ||
121 | MOVE_SC_RET(D, T) | |
122 | Likewise a complex single-precision floating-point return value. | |
123 | ||
124 | MOVE_DF_RET(D, T) | |
125 | Likewise a double-precision floating-point return value. | |
126 | ||
127 | MOVE_DC_RET(D, T) | |
128 | Likewise a complex double-precision floating-point return value. | |
129 | ||
130 | MOVE_SI_RET(D, T) | |
131 | Likewise a single-precision integer return value. | |
132 | ||
133 | The D argument is "t" to move to FPRs and "f" to move from FPRs. | |
134 | The return macros may assume that the target of the jump does not | |
135 | use a floating-point register. */ | |
136 | ||
137 | #define MOVE_SF_RET(D, T) DELAY##D (T, m##D##c1 $2,$f0) | |
138 | #define MOVE_SI_RET(D, T) DELAY##D (T, m##D##c1 $2,$f0) | |
139 | ||
140 | #if defined(__mips64) && defined(__MIPSEB__) | |
141 | #define MOVE_SC_RET(D, T) MERGE_GPR##D ($2, $f0, $f1); jr T | |
142 | #elif defined(__mips64) | |
143 | /* The high 32 bits of $2 correspond to the second word in memory; | |
144 | i.e. the imaginary part. */ | |
145 | #define MOVE_SC_RET(D, T) MERGE_GPR##D ($2, $f1, $f0); jr T | |
146 | #elif __mips_fpr == 64 | |
147 | #define MOVE_SC_RET(D, T) m##D##c1 $2,$f0; DELAY##D (T, m##D##c1 $3,$f1) | |
148 | #else | |
149 | #define MOVE_SC_RET(D, T) m##D##c1 $2,$f0; DELAY##D (T, m##D##c1 $3,$f2) | |
150 | #endif | |
151 | ||
152 | #if defined(__mips64) | |
153 | #define MOVE_SF_BYTE0(D) m##D##c1 $4,$f12 | |
154 | #define MOVE_SF_BYTE4(D) m##D##c1 $5,$f13 | |
155 | #define MOVE_SF_BYTE8(D) m##D##c1 $5,$f13 | |
156 | #else | |
157 | #define MOVE_SF_BYTE0(D) m##D##c1 $4,$f12 | |
158 | #define MOVE_SF_BYTE4(D) m##D##c1 $5,$f14 | |
159 | #define MOVE_SF_BYTE8(D) m##D##c1 $6,$f14 | |
160 | #endif | |
161 | #define MOVE_SI_BYTE0(D) MOVE_SF_BYTE0(D) | |
162 | ||
163 | #if defined(__mips64) | |
164 | #define MOVE_DF_BYTE0(D) dm##D##c1 $4,$f12 | |
165 | #define MOVE_DF_BYTE8(D) dm##D##c1 $5,$f13 | |
166 | #define MOVE_DF_RET(D, T) DELAY##D (T, dm##D##c1 $2,$f0) | |
167 | #define MOVE_DC_RET(D, T) dm##D##c1 $3,$f1; MOVE_DF_RET (D, T) | |
168 | #elif __mips_fpr == 64 && defined(__MIPSEB__) | |
169 | #define MOVE_DF_BYTE0(D) m##D##c1 $5,$f12; m##D##hc1 $4,$f12 | |
170 | #define MOVE_DF_BYTE8(D) m##D##c1 $7,$f14; m##D##hc1 $6,$f14 | |
171 | #define MOVE_DF_RET(D, T) m##D##c1 $3,$f0; DELAY##D (T, m##D##hc1 $2,$f0) | |
172 | #define MOVE_DC_RET(D, T) m##D##c1 $5,$f1; m##D##hc1 $4,$f1; MOVE_DF_RET (D, T) | |
173 | #elif __mips_fpr == 64 | |
174 | #define MOVE_DF_BYTE0(D) m##D##c1 $4,$f12; m##D##hc1 $5,$f12 | |
175 | #define MOVE_DF_BYTE8(D) m##D##c1 $6,$f14; m##D##hc1 $7,$f14 | |
176 | #define MOVE_DF_RET(D, T) m##D##c1 $2,$f0; DELAY##D (T, m##D##hc1 $3,$f0) | |
177 | #define MOVE_DC_RET(D, T) m##D##c1 $4,$f1; m##D##hc1 $5,$f1; MOVE_DF_RET (D, T) | |
178 | #elif defined(__MIPSEB__) | |
179 | /* FPRs are little-endian. */ | |
180 | #define MOVE_DF_BYTE0(D) m##D##c1 $4,$f13; m##D##c1 $5,$f12 | |
181 | #define MOVE_DF_BYTE8(D) m##D##c1 $6,$f15; m##D##c1 $7,$f14 | |
182 | #define MOVE_DF_RET(D, T) m##D##c1 $2,$f1; DELAY##D (T, m##D##c1 $3,$f0) | |
183 | #define MOVE_DC_RET(D, T) m##D##c1 $4,$f3; m##D##c1 $5,$f2; MOVE_DF_RET (D, T) | |
184 | #else | |
185 | #define MOVE_DF_BYTE0(D) m##D##c1 $4,$f12; m##D##c1 $5,$f13 | |
186 | #define MOVE_DF_BYTE8(D) m##D##c1 $6,$f14; m##D##c1 $7,$f15 | |
187 | #define MOVE_DF_RET(D, T) m##D##c1 $2,$f0; DELAY##D (T, m##D##c1 $3,$f1) | |
188 | #define MOVE_DC_RET(D, T) m##D##c1 $4,$f2; m##D##c1 $5,$f3; MOVE_DF_RET (D, T) | |
189 | #endif | |
190 | ||
191 | /* Single-precision math. */ | |
192 | ||
193 | /* Define a function NAME that loads two single-precision values, | |
194 | performs FPU operation OPCODE on them, and returns the single- | |
195 | precision result. */ | |
196 | ||
197 | #define OPSF3(NAME, OPCODE) \ | |
afba61d1 | 198 | STARTFN (NAME); \ |
a38e0142 SL |
199 | MOVE_SF_BYTE0 (t); \ |
200 | MOVE_SF_BYTE4 (t); \ | |
201 | OPCODE RET,ARG1,ARG2; \ | |
202 | MOVE_SF_RET (f, $31); \ | |
afba61d1 ILT |
203 | ENDFN (NAME) |
204 | ||
205 | #ifdef L_m16addsf3 | |
a38e0142 | 206 | OPSF3 (__mips16_addsf3, add.s) |
afba61d1 ILT |
207 | #endif |
208 | #ifdef L_m16subsf3 | |
a38e0142 | 209 | OPSF3 (__mips16_subsf3, sub.s) |
afba61d1 ILT |
210 | #endif |
211 | #ifdef L_m16mulsf3 | |
a38e0142 | 212 | OPSF3 (__mips16_mulsf3, mul.s) |
afba61d1 ILT |
213 | #endif |
214 | #ifdef L_m16divsf3 | |
a38e0142 | 215 | OPSF3 (__mips16_divsf3, div.s) |
afba61d1 ILT |
216 | #endif |
217 | ||
a38e0142 SL |
218 | /* Define a function NAME that loads a single-precision value, |
219 | performs FPU operation OPCODE on it, and returns the single- | |
220 | precision result. */ | |
221 | ||
222 | #define OPSF2(NAME, OPCODE) \ | |
eb774d8d | 223 | STARTFN (NAME); \ |
a38e0142 SL |
224 | MOVE_SF_BYTE0 (t); \ |
225 | OPCODE RET,ARG1; \ | |
226 | MOVE_SF_RET (f, $31); \ | |
eb774d8d | 227 | ENDFN (NAME) |
91e01231 | 228 | |
eb774d8d | 229 | #ifdef L_m16negsf2 |
a38e0142 | 230 | OPSF2 (__mips16_negsf2, neg.s) |
eb774d8d NS |
231 | #endif |
232 | #ifdef L_m16abssf2 | |
a38e0142 | 233 | OPSF2 (__mips16_abssf2, abs.s) |
eb774d8d | 234 | #endif |
91e01231 | 235 | |
a38e0142 | 236 | /* Single-precision comparisons. */ |
afba61d1 | 237 | |
a38e0142 SL |
238 | /* Define a function NAME that loads two single-precision values, |
239 | performs floating point comparison OPCODE, and returns TRUE or | |
240 | FALSE depending on the result. */ | |
afba61d1 | 241 | |
a38e0142 | 242 | #define CMPSF(NAME, OPCODE, TRUE, FALSE) \ |
afba61d1 | 243 | STARTFN (NAME); \ |
a38e0142 SL |
244 | MOVE_SF_BYTE0 (t); \ |
245 | MOVE_SF_BYTE4 (t); \ | |
246 | OPCODE ARG1,ARG2; \ | |
afba61d1 ILT |
247 | li $2,TRUE; \ |
248 | bc1t 1f; \ | |
249 | li $2,FALSE; \ | |
250 | 1:; \ | |
251 | j $31; \ | |
252 | ENDFN (NAME) | |
253 | ||
a38e0142 | 254 | /* Like CMPSF, but reverse the comparison operands. */ |
afba61d1 | 255 | |
a38e0142 | 256 | #define REVCMPSF(NAME, OPCODE, TRUE, FALSE) \ |
afba61d1 | 257 | STARTFN (NAME); \ |
a38e0142 SL |
258 | MOVE_SF_BYTE0 (t); \ |
259 | MOVE_SF_BYTE4 (t); \ | |
260 | OPCODE ARG2,ARG1; \ | |
afba61d1 ILT |
261 | li $2,TRUE; \ |
262 | bc1t 1f; \ | |
263 | li $2,FALSE; \ | |
264 | 1:; \ | |
265 | j $31; \ | |
266 | ENDFN (NAME) | |
267 | ||
268 | #ifdef L_m16eqsf2 | |
a38e0142 | 269 | CMPSF (__mips16_eqsf2, c.eq.s, 0, 1) |
afba61d1 ILT |
270 | #endif |
271 | #ifdef L_m16nesf2 | |
a38e0142 | 272 | CMPSF (__mips16_nesf2, c.eq.s, 0, 1) |
afba61d1 ILT |
273 | #endif |
274 | #ifdef L_m16gtsf2 | |
a38e0142 | 275 | REVCMPSF (__mips16_gtsf2, c.lt.s, 1, 0) |
afba61d1 ILT |
276 | #endif |
277 | #ifdef L_m16gesf2 | |
a38e0142 | 278 | REVCMPSF (__mips16_gesf2, c.le.s, 0, -1) |
afba61d1 ILT |
279 | #endif |
280 | #ifdef L_m16lesf2 | |
a38e0142 | 281 | CMPSF (__mips16_lesf2, c.le.s, 0, 1) |
afba61d1 ILT |
282 | #endif |
283 | #ifdef L_m16ltsf2 | |
a38e0142 | 284 | CMPSF (__mips16_ltsf2, c.lt.s, -1, 0) |
afba61d1 | 285 | #endif |
45059ab1 SL |
286 | #ifdef L_m16unordsf2 |
287 | CMPSF(__mips16_unordsf2, c.un.s, 1, 0) | |
288 | #endif | |
289 | ||
afba61d1 | 290 | |
a38e0142 | 291 | /* Single-precision conversions. */ |
afba61d1 ILT |
292 | |
293 | #ifdef L_m16fltsisf | |
294 | STARTFN (__mips16_floatsisf) | |
a38e0142 SL |
295 | MOVE_SF_BYTE0 (t) |
296 | cvt.s.w RET,ARG1 | |
297 | MOVE_SF_RET (f, $31) | |
afba61d1 ILT |
298 | ENDFN (__mips16_floatsisf) |
299 | #endif | |
300 | ||
45059ab1 SL |
301 | #ifdef L_m16fltunsisf |
302 | STARTFN (__mips16_floatunsisf) | |
08d0963a | 303 | .set noreorder |
45059ab1 | 304 | bltz $4,1f |
08d0963a RS |
305 | MOVE_SF_BYTE0 (t) |
306 | .set reorder | |
307 | cvt.s.w RET,ARG1 | |
308 | MOVE_SF_RET (f, $31) | |
45059ab1 SL |
309 | 1: |
310 | and $2,$4,1 | |
311 | srl $3,$4,1 | |
312 | or $2,$2,$3 | |
313 | mtc1 $2,RET | |
314 | cvt.s.w RET,RET | |
315 | add.s RET,RET,RET | |
316 | MOVE_SF_RET (f, $31) | |
317 | ENDFN (__mips16_floatunsisf) | |
318 | #endif | |
319 | ||
91e01231 EC |
320 | #ifdef L_m16fix_truncsfsi |
321 | STARTFN (__mips16_fix_truncsfsi) | |
a38e0142 SL |
322 | MOVE_SF_BYTE0 (t) |
323 | trunc.w.s RET,ARG1,$4 | |
324 | MOVE_SI_RET (f, $31) | |
91e01231 | 325 | ENDFN (__mips16_fix_truncsfsi) |
afba61d1 ILT |
326 | #endif |
327 | ||
eb774d8d | 328 | #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT) |
91e01231 | 329 | |
a38e0142 | 330 | /* Double-precision math. */ |
afba61d1 | 331 | |
a38e0142 SL |
332 | /* Define a function NAME that loads two double-precision values, |
333 | performs FPU operation OPCODE on them, and returns the double- | |
334 | precision result. */ | |
afba61d1 | 335 | |
a38e0142 | 336 | #define OPDF3(NAME, OPCODE) \ |
afba61d1 | 337 | STARTFN (NAME); \ |
a38e0142 SL |
338 | MOVE_DF_BYTE0 (t); \ |
339 | MOVE_DF_BYTE8 (t); \ | |
340 | OPCODE RET,ARG1,ARG2; \ | |
341 | MOVE_DF_RET (f, $31); \ | |
afba61d1 ILT |
342 | ENDFN (NAME) |
343 | ||
344 | #ifdef L_m16adddf3 | |
a38e0142 | 345 | OPDF3 (__mips16_adddf3, add.d) |
afba61d1 ILT |
346 | #endif |
347 | #ifdef L_m16subdf3 | |
a38e0142 | 348 | OPDF3 (__mips16_subdf3, sub.d) |
afba61d1 ILT |
349 | #endif |
350 | #ifdef L_m16muldf3 | |
a38e0142 | 351 | OPDF3 (__mips16_muldf3, mul.d) |
afba61d1 ILT |
352 | #endif |
353 | #ifdef L_m16divdf3 | |
a38e0142 | 354 | OPDF3 (__mips16_divdf3, div.d) |
afba61d1 ILT |
355 | #endif |
356 | ||
a38e0142 SL |
357 | /* Define a function NAME that loads a double-precision value, |
358 | performs FPU operation OPCODE on it, and returns the double- | |
359 | precision result. */ | |
360 | ||
361 | #define OPDF2(NAME, OPCODE) \ | |
eb774d8d | 362 | STARTFN (NAME); \ |
a38e0142 SL |
363 | MOVE_DF_BYTE0 (t); \ |
364 | OPCODE RET,ARG1; \ | |
365 | MOVE_DF_RET (f, $31); \ | |
eb774d8d | 366 | ENDFN (NAME) |
91e01231 | 367 | |
eb774d8d | 368 | #ifdef L_m16negdf2 |
a38e0142 | 369 | OPDF2 (__mips16_negdf2, neg.d) |
eb774d8d NS |
370 | #endif |
371 | #ifdef L_m16absdf2 | |
a38e0142 | 372 | OPDF2 (__mips16_absdf2, abs.d) |
eb774d8d NS |
373 | #endif |
374 | ||
afba61d1 ILT |
375 | /* Conversions between single and double precision. */ |
376 | ||
377 | #ifdef L_m16extsfdf2 | |
378 | STARTFN (__mips16_extendsfdf2) | |
a38e0142 SL |
379 | MOVE_SF_BYTE0 (t) |
380 | cvt.d.s RET,ARG1 | |
381 | MOVE_DF_RET (f, $31) | |
afba61d1 ILT |
382 | ENDFN (__mips16_extendsfdf2) |
383 | #endif | |
384 | ||
385 | #ifdef L_m16trdfsf2 | |
386 | STARTFN (__mips16_truncdfsf2) | |
a38e0142 SL |
387 | MOVE_DF_BYTE0 (t) |
388 | cvt.s.d RET,ARG1 | |
389 | MOVE_SF_RET (f, $31) | |
afba61d1 ILT |
390 | ENDFN (__mips16_truncdfsf2) |
391 | #endif | |
392 | ||
a38e0142 | 393 | /* Double-precision comparisons. */ |
afba61d1 | 394 | |
a38e0142 SL |
395 | /* Define a function NAME that loads two double-precision values, |
396 | performs floating point comparison OPCODE, and returns TRUE or | |
397 | FALSE depending on the result. */ | |
afba61d1 | 398 | |
a38e0142 | 399 | #define CMPDF(NAME, OPCODE, TRUE, FALSE) \ |
afba61d1 | 400 | STARTFN (NAME); \ |
a38e0142 SL |
401 | MOVE_DF_BYTE0 (t); \ |
402 | MOVE_DF_BYTE8 (t); \ | |
403 | OPCODE ARG1,ARG2; \ | |
afba61d1 ILT |
404 | li $2,TRUE; \ |
405 | bc1t 1f; \ | |
406 | li $2,FALSE; \ | |
407 | 1:; \ | |
408 | j $31; \ | |
409 | ENDFN (NAME) | |
410 | ||
a38e0142 | 411 | /* Like CMPDF, but reverse the comparison operands. */ |
afba61d1 | 412 | |
a38e0142 | 413 | #define REVCMPDF(NAME, OPCODE, TRUE, FALSE) \ |
afba61d1 | 414 | STARTFN (NAME); \ |
a38e0142 SL |
415 | MOVE_DF_BYTE0 (t); \ |
416 | MOVE_DF_BYTE8 (t); \ | |
417 | OPCODE ARG2,ARG1; \ | |
afba61d1 ILT |
418 | li $2,TRUE; \ |
419 | bc1t 1f; \ | |
420 | li $2,FALSE; \ | |
421 | 1:; \ | |
422 | j $31; \ | |
423 | ENDFN (NAME) | |
424 | ||
425 | #ifdef L_m16eqdf2 | |
a38e0142 | 426 | CMPDF (__mips16_eqdf2, c.eq.d, 0, 1) |
afba61d1 ILT |
427 | #endif |
428 | #ifdef L_m16nedf2 | |
a38e0142 | 429 | CMPDF (__mips16_nedf2, c.eq.d, 0, 1) |
afba61d1 ILT |
430 | #endif |
431 | #ifdef L_m16gtdf2 | |
a38e0142 | 432 | REVCMPDF (__mips16_gtdf2, c.lt.d, 1, 0) |
afba61d1 ILT |
433 | #endif |
434 | #ifdef L_m16gedf2 | |
a38e0142 | 435 | REVCMPDF (__mips16_gedf2, c.le.d, 0, -1) |
afba61d1 ILT |
436 | #endif |
437 | #ifdef L_m16ledf2 | |
a38e0142 | 438 | CMPDF (__mips16_ledf2, c.le.d, 0, 1) |
afba61d1 ILT |
439 | #endif |
440 | #ifdef L_m16ltdf2 | |
a38e0142 | 441 | CMPDF (__mips16_ltdf2, c.lt.d, -1, 0) |
afba61d1 | 442 | #endif |
45059ab1 SL |
443 | #ifdef L_m16unorddf2 |
444 | CMPDF(__mips16_unorddf2, c.un.d, 1, 0) | |
445 | #endif | |
afba61d1 | 446 | |
a38e0142 | 447 | /* Double-precision conversions. */ |
afba61d1 ILT |
448 | |
449 | #ifdef L_m16fltsidf | |
450 | STARTFN (__mips16_floatsidf) | |
a38e0142 SL |
451 | MOVE_SI_BYTE0 (t) |
452 | cvt.d.w RET,ARG1 | |
453 | MOVE_DF_RET (f, $31) | |
afba61d1 ILT |
454 | ENDFN (__mips16_floatsidf) |
455 | #endif | |
45059ab1 SL |
456 | |
457 | #ifdef L_m16fltunsidf | |
458 | STARTFN (__mips16_floatunsidf) | |
459 | MOVE_SI_BYTE0 (t) | |
460 | cvt.d.w RET,ARG1 | |
461 | bgez $4,1f | |
462 | li.d ARG1, 4.294967296e+9 | |
463 | add.d RET, RET, ARG1 | |
464 | 1: MOVE_DF_RET (f, $31) | |
465 | ENDFN (__mips16_floatunsidf) | |
466 | #endif | |
467 | ||
91e01231 EC |
468 | #ifdef L_m16fix_truncdfsi |
469 | STARTFN (__mips16_fix_truncdfsi) | |
a38e0142 SL |
470 | MOVE_DF_BYTE0 (t) |
471 | trunc.w.d RET,ARG1,$4 | |
472 | MOVE_SI_RET (f, $31) | |
91e01231 | 473 | ENDFN (__mips16_fix_truncdfsi) |
afba61d1 | 474 | #endif |
eb774d8d | 475 | #endif /* !__mips_single_float */ |
afba61d1 | 476 | |
a38e0142 SL |
477 | /* Define a function NAME that moves a return value of mode MODE from |
478 | FPRs to GPRs. */ | |
479 | ||
480 | #define RET_FUNCTION(NAME, MODE) \ | |
481 | STARTFN (NAME); \ | |
482 | MOVE_##MODE##_RET (t, $31); \ | |
483 | ENDFN (NAME) | |
afba61d1 ILT |
484 | |
485 | #ifdef L_m16retsf | |
a38e0142 SL |
486 | RET_FUNCTION (__mips16_ret_sf, SF) |
487 | #endif | |
488 | ||
489 | #ifdef L_m16retsc | |
490 | RET_FUNCTION (__mips16_ret_sc, SC) | |
afba61d1 ILT |
491 | #endif |
492 | ||
eb774d8d | 493 | #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT) |
afba61d1 | 494 | #ifdef L_m16retdf |
a38e0142 | 495 | RET_FUNCTION (__mips16_ret_df, DF) |
eb774d8d | 496 | #endif |
a38e0142 SL |
497 | |
498 | #ifdef L_m16retdc | |
499 | RET_FUNCTION (__mips16_ret_dc, DC) | |
afba61d1 | 500 | #endif |
eb774d8d | 501 | #endif /* !__mips_single_float */ |
afba61d1 | 502 | |
a38e0142 SL |
503 | /* STUB_ARGS_X copies the arguments from GPRs to FPRs for argument |
504 | code X. X is calculated as ARG1 + ARG2 * 4, where ARG1 and ARG2 | |
505 | classify the first and second arguments as follows: | |
506 | ||
507 | 1: a single-precision argument | |
508 | 2: a double-precision argument | |
509 | 0: no argument, or not one of the above. */ | |
510 | ||
511 | #define STUB_ARGS_0 /* () */ | |
512 | #define STUB_ARGS_1 MOVE_SF_BYTE0 (t) /* (sf) */ | |
513 | #define STUB_ARGS_5 MOVE_SF_BYTE0 (t); MOVE_SF_BYTE4 (t) /* (sf, sf) */ | |
514 | #define STUB_ARGS_9 MOVE_SF_BYTE0 (t); MOVE_DF_BYTE8 (t) /* (sf, df) */ | |
515 | #define STUB_ARGS_2 MOVE_DF_BYTE0 (t) /* (df) */ | |
516 | #define STUB_ARGS_6 MOVE_DF_BYTE0 (t); MOVE_SF_BYTE8 (t) /* (df, sf) */ | |
517 | #define STUB_ARGS_10 MOVE_DF_BYTE0 (t); MOVE_DF_BYTE8 (t) /* (df, df) */ | |
518 | ||
85f65093 | 519 | /* These functions are used by 16-bit code when calling via a function |
a38e0142 SL |
520 | pointer. They must copy the floating point arguments from the GPRs |
521 | to FPRs and then call function $2. */ | |
522 | ||
523 | #define CALL_STUB_NO_RET(NAME, CODE) \ | |
524 | STARTFN (NAME); \ | |
525 | STUB_ARGS_##CODE; \ | |
08d0963a | 526 | .set noreorder; \ |
a38e0142 | 527 | jr $2; \ |
08d0963a RS |
528 | move $25,$2; \ |
529 | .set reorder; \ | |
a38e0142 | 530 | ENDFN (NAME) |
afba61d1 ILT |
531 | |
532 | #ifdef L_m16stub1 | |
a38e0142 | 533 | CALL_STUB_NO_RET (__mips16_call_stub_1, 1) |
afba61d1 ILT |
534 | #endif |
535 | ||
afba61d1 | 536 | #ifdef L_m16stub5 |
a38e0142 | 537 | CALL_STUB_NO_RET (__mips16_call_stub_5, 5) |
afba61d1 ILT |
538 | #endif |
539 | ||
eb774d8d NS |
540 | #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT) |
541 | ||
542 | #ifdef L_m16stub2 | |
a38e0142 | 543 | CALL_STUB_NO_RET (__mips16_call_stub_2, 2) |
eb774d8d NS |
544 | #endif |
545 | ||
afba61d1 | 546 | #ifdef L_m16stub6 |
a38e0142 | 547 | CALL_STUB_NO_RET (__mips16_call_stub_6, 6) |
afba61d1 ILT |
548 | #endif |
549 | ||
550 | #ifdef L_m16stub9 | |
a38e0142 | 551 | CALL_STUB_NO_RET (__mips16_call_stub_9, 9) |
afba61d1 ILT |
552 | #endif |
553 | ||
554 | #ifdef L_m16stub10 | |
a38e0142 | 555 | CALL_STUB_NO_RET (__mips16_call_stub_10, 10) |
afba61d1 | 556 | #endif |
eb774d8d | 557 | #endif /* !__mips_single_float */ |
afba61d1 ILT |
558 | |
559 | /* Now we have the same set of functions, except that this time the | |
a38e0142 SL |
560 | function being called returns an SFmode, SCmode, DFmode or DCmode |
561 | value; we need to instantiate a set for each case. The calling | |
afba61d1 ILT |
562 | function will arrange to preserve $18, so these functions are free |
563 | to use it to hold the return address. | |
564 | ||
565 | Note that we do not know whether the function we are calling is 16 | |
85f65093 | 566 | bit or 32 bit. However, it does not matter, because 16-bit |
afba61d1 ILT |
567 | functions always return floating point values in both the gp and |
568 | the fp regs. It would be possible to check whether the function | |
569 | being called is 16 bits, in which case the copy is unnecessary; | |
570 | however, it's faster to always do the copy. */ | |
571 | ||
5adeb246 RS |
572 | #define CALL_STUB_RET(NAME, CODE, MODE) \ |
573 | STARTFN (NAME); \ | |
574 | .cfi_startproc; \ | |
575 | /* Create a fake CFA 4 bytes below the stack pointer. */ \ | |
576 | .cfi_def_cfa 29,-4; \ | |
577 | /* "Save" $sp in itself so we don't use the fake CFA. \ | |
578 | This is: DW_CFA_val_expression r29, { DW_OP_reg29 }. */ \ | |
579 | .cfi_escape 0x16,29,1,0x6d; \ | |
580 | move $18,$31; \ | |
581 | .cfi_register 31,18; \ | |
582 | STUB_ARGS_##CODE; \ | |
583 | .set noreorder; \ | |
584 | jalr $2; \ | |
585 | move $25,$2; \ | |
586 | .set reorder; \ | |
587 | MOVE_##MODE##_RET (f, $18); \ | |
588 | .cfi_endproc; \ | |
a38e0142 SL |
589 | ENDFN (NAME) |
590 | ||
591 | /* First, instantiate the single-float set. */ | |
592 | ||
afba61d1 | 593 | #ifdef L_m16stubsf0 |
a38e0142 | 594 | CALL_STUB_RET (__mips16_call_stub_sf_0, 0, SF) |
afba61d1 ILT |
595 | #endif |
596 | ||
597 | #ifdef L_m16stubsf1 | |
a38e0142 | 598 | CALL_STUB_RET (__mips16_call_stub_sf_1, 1, SF) |
afba61d1 ILT |
599 | #endif |
600 | ||
eb774d8d | 601 | #ifdef L_m16stubsf5 |
a38e0142 | 602 | CALL_STUB_RET (__mips16_call_stub_sf_5, 5, SF) |
afba61d1 ILT |
603 | #endif |
604 | ||
eb774d8d NS |
605 | #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT) |
606 | #ifdef L_m16stubsf2 | |
a38e0142 | 607 | CALL_STUB_RET (__mips16_call_stub_sf_2, 2, SF) |
afba61d1 ILT |
608 | #endif |
609 | ||
610 | #ifdef L_m16stubsf6 | |
a38e0142 | 611 | CALL_STUB_RET (__mips16_call_stub_sf_6, 6, SF) |
afba61d1 ILT |
612 | #endif |
613 | ||
614 | #ifdef L_m16stubsf9 | |
a38e0142 | 615 | CALL_STUB_RET (__mips16_call_stub_sf_9, 9, SF) |
afba61d1 ILT |
616 | #endif |
617 | ||
618 | #ifdef L_m16stubsf10 | |
a38e0142 | 619 | CALL_STUB_RET (__mips16_call_stub_sf_10, 10, SF) |
afba61d1 | 620 | #endif |
a38e0142 SL |
621 | #endif /* !__mips_single_float */ |
622 | ||
afba61d1 ILT |
623 | |
624 | /* Now we have the same set of functions again, except that this time | |
625 | the function being called returns an DFmode value. */ | |
626 | ||
a38e0142 | 627 | #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT) |
afba61d1 | 628 | #ifdef L_m16stubdf0 |
a38e0142 | 629 | CALL_STUB_RET (__mips16_call_stub_df_0, 0, DF) |
afba61d1 ILT |
630 | #endif |
631 | ||
632 | #ifdef L_m16stubdf1 | |
a38e0142 | 633 | CALL_STUB_RET (__mips16_call_stub_df_1, 1, DF) |
afba61d1 ILT |
634 | #endif |
635 | ||
a38e0142 SL |
636 | #ifdef L_m16stubdf5 |
637 | CALL_STUB_RET (__mips16_call_stub_df_5, 5, DF) | |
afba61d1 ILT |
638 | #endif |
639 | ||
a38e0142 SL |
640 | #ifdef L_m16stubdf2 |
641 | CALL_STUB_RET (__mips16_call_stub_df_2, 2, DF) | |
afba61d1 ILT |
642 | #endif |
643 | ||
644 | #ifdef L_m16stubdf6 | |
a38e0142 | 645 | CALL_STUB_RET (__mips16_call_stub_df_6, 6, DF) |
afba61d1 ILT |
646 | #endif |
647 | ||
648 | #ifdef L_m16stubdf9 | |
a38e0142 | 649 | CALL_STUB_RET (__mips16_call_stub_df_9, 9, DF) |
afba61d1 ILT |
650 | #endif |
651 | ||
652 | #ifdef L_m16stubdf10 | |
a38e0142 SL |
653 | CALL_STUB_RET (__mips16_call_stub_df_10, 10, DF) |
654 | #endif | |
655 | #endif /* !__mips_single_float */ | |
656 | ||
657 | ||
658 | /* Ho hum. Here we have the same set of functions again, this time | |
659 | for when the function being called returns an SCmode value. */ | |
660 | ||
661 | #ifdef L_m16stubsc0 | |
662 | CALL_STUB_RET (__mips16_call_stub_sc_0, 0, SC) | |
663 | #endif | |
664 | ||
665 | #ifdef L_m16stubsc1 | |
666 | CALL_STUB_RET (__mips16_call_stub_sc_1, 1, SC) | |
667 | #endif | |
668 | ||
669 | #ifdef L_m16stubsc5 | |
670 | CALL_STUB_RET (__mips16_call_stub_sc_5, 5, SC) | |
671 | #endif | |
672 | ||
673 | #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT) | |
674 | #ifdef L_m16stubsc2 | |
675 | CALL_STUB_RET (__mips16_call_stub_sc_2, 2, SC) | |
676 | #endif | |
677 | ||
678 | #ifdef L_m16stubsc6 | |
679 | CALL_STUB_RET (__mips16_call_stub_sc_6, 6, SC) | |
680 | #endif | |
681 | ||
682 | #ifdef L_m16stubsc9 | |
683 | CALL_STUB_RET (__mips16_call_stub_sc_9, 9, SC) | |
684 | #endif | |
685 | ||
686 | #ifdef L_m16stubsc10 | |
687 | CALL_STUB_RET (__mips16_call_stub_sc_10, 10, SC) | |
688 | #endif | |
689 | #endif /* !__mips_single_float */ | |
690 | ||
691 | ||
692 | /* Finally, another set of functions for DCmode. */ | |
693 | ||
694 | #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT) | |
695 | #ifdef L_m16stubdc0 | |
696 | CALL_STUB_RET (__mips16_call_stub_dc_0, 0, DC) | |
697 | #endif | |
698 | ||
699 | #ifdef L_m16stubdc1 | |
700 | CALL_STUB_RET (__mips16_call_stub_dc_1, 1, DC) | |
701 | #endif | |
702 | ||
703 | #ifdef L_m16stubdc5 | |
704 | CALL_STUB_RET (__mips16_call_stub_dc_5, 5, DC) | |
705 | #endif | |
706 | ||
707 | #ifdef L_m16stubdc2 | |
708 | CALL_STUB_RET (__mips16_call_stub_dc_2, 2, DC) | |
709 | #endif | |
710 | ||
711 | #ifdef L_m16stubdc6 | |
712 | CALL_STUB_RET (__mips16_call_stub_dc_6, 6, DC) | |
713 | #endif | |
714 | ||
715 | #ifdef L_m16stubdc9 | |
716 | CALL_STUB_RET (__mips16_call_stub_dc_9, 9, DC) | |
717 | #endif | |
718 | ||
719 | #ifdef L_m16stubdc10 | |
720 | CALL_STUB_RET (__mips16_call_stub_dc_10, 10, DC) | |
afba61d1 | 721 | #endif |
eb774d8d | 722 | #endif /* !__mips_single_float */ |
ddaf8125 | 723 | |
08d0963a | 724 | #endif |
22c4c869 | 725 | #endif /* __mips_micromips */ |