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