Daily bump.
[official-gcc.git] / libgcc / config / mips / mips16.S
blob46e3509d9f51aa18d8cd098d9b6df2d404e36749
1 /* mips16 floating point support code
2    Copyright (C) 1996-2024 Free Software Foundation, Inc.
3    Contributed by Cygnus Support
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.
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.
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.
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/>.  */
24 /* An executable stack is *not* required for these functions.  */
25 #include "gnustack.h"
27 #include "auto-host.h"
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
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
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.  */
54 #if defined _MIPS_SIM && (_MIPS_SIM == _ABIO32 || _MIPS_SIM == _ABIO64)
56 /* This file contains 32-bit assembly code.  */
57         .set nomips16
59 /* Start a function.  */
61 #define STARTFN(NAME) .globl NAME; .ent NAME; NAME:
63 /* Finish a function.  */
65 #define ENDFN(NAME) .end NAME
67 /* ARG1
68         The FPR that holds the first floating-point argument.
70    ARG2
71         The FPR that holds the second floating-point argument.
73    RET
74         The FPR that holds a floating-point return value.  */
76 #define RET $f0
77 #define ARG1 $f12
78 #ifdef __mips64
79 #define ARG2 $f13
80 #else
81 #define ARG2 $f14
82 #endif
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
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
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
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
120 /* MOVE_SF_BYTE0(D)
121         Move the first single-precision floating-point argument between
122         GPRs and FPRs.
124    MOVE_SI_BYTE0(D)
125         Likewise the first single-precision integer argument.
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.
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.
135    MOVE_DF_BYTE0(D)
136         Move the first double-precision floating-point argument between
137         GPRs and FPRs.
139    MOVE_DF_BYTE8(D)
140         Likewise the second double-precision floating-point argument.
142    MOVE_SF_RET(D, T)
143         Likewise a single-precision floating-point return value,
144         then jump to T.
146    MOVE_SC_RET(D, T)
147         Likewise a complex single-precision floating-point return value.
149    MOVE_DF_RET(D, T)
150         Likewise a double-precision floating-point return value.
152    MOVE_DC_RET(D, T)
153         Likewise a complex double-precision floating-point return value.
155    MOVE_SI_RET(D, T)
156         Likewise a single-precision integer return value.
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.  */
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)
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
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)
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
227 /* Single-precision math.  */
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.  */
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)
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
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.  */
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)
265 #ifdef L_m16negsf2
266 OPSF2 (__mips16_negsf2, neg.s)
267 #endif
268 #ifdef L_m16abssf2
269 OPSF2 (__mips16_abssf2, abs.s)
270 #endif
272 /* Single-precision comparisons.  */
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.  */
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)
290 /* Like CMPSF, but reverse the comparison operands.  */
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)
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
327 /* Single-precision conversions.  */
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
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
364 #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
366 /* Double-precision math.  */
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.  */
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)
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
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.  */
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)
404 #ifdef L_m16negdf2
405 OPDF2 (__mips16_negdf2, neg.d)
406 #endif
407 #ifdef L_m16absdf2
408 OPDF2 (__mips16_absdf2, abs.d)
409 #endif
411 /* Conversions between single and double precision.  */
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
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
429 /* Double-precision comparisons.  */
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.  */
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)
447 /* Like CMPDF, but reverse the comparison operands.  */
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)
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
483 /* Double-precision conversions.  */
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 */
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.
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.  */
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
535 /* Define a function NAME that moves a return value of mode MODE from
536    FPRs to GPRs.  */
538 #define RET_FUNCTION(NAME, MODE)        \
539 CE_STARTFN (NAME);                      \
540         MOVE_##MODE##_RET (t, $31);     \
541         CE_ENDFN (NAME)
543 #ifdef L_m16retsf
544 RET_FUNCTION (__mips16_ret_sf, SF)
545 #endif
547 #ifdef L_m16retsc
548 RET_FUNCTION (__mips16_ret_sc, SC)
549 #endif
551 #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
552 #ifdef L_m16retdf
553 RET_FUNCTION (__mips16_ret_df, DF)
554 #endif
556 #ifdef L_m16retdc
557 RET_FUNCTION (__mips16_ret_dc, DC)
558 #endif
559 #endif /* !__mips_single_float */
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:
565         1: a single-precision argument
566         2: a double-precision argument
567         0: no argument, or not one of the above.  */
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) */
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.  */
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)
590 #ifdef L_m16stub1
591 CALL_STUB_NO_RET (__mips16_call_stub_1, 1)
592 #endif
594 #ifdef L_m16stub5
595 CALL_STUB_NO_RET (__mips16_call_stub_5, 5)
596 #endif
598 #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
600 #ifdef L_m16stub2
601 CALL_STUB_NO_RET (__mips16_call_stub_2, 2)
602 #endif
604 #ifdef L_m16stub6
605 CALL_STUB_NO_RET (__mips16_call_stub_6, 6)
606 #endif
608 #ifdef L_m16stub9
609 CALL_STUB_NO_RET (__mips16_call_stub_9, 9)
610 #endif
612 #ifdef L_m16stub10
613 CALL_STUB_NO_RET (__mips16_call_stub_10, 10)
614 #endif
615 #endif /* !__mips_single_float */
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.
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.  */
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)
649 /* First, instantiate the single-float set.  */
651 #ifdef L_m16stubsf0
652 CALL_STUB_RET (__mips16_call_stub_sf_0, 0, SF)
653 #endif
655 #ifdef L_m16stubsf1
656 CALL_STUB_RET (__mips16_call_stub_sf_1, 1, SF)
657 #endif
659 #ifdef L_m16stubsf5
660 CALL_STUB_RET (__mips16_call_stub_sf_5, 5, SF)
661 #endif
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
668 #ifdef L_m16stubsf6
669 CALL_STUB_RET (__mips16_call_stub_sf_6, 6, SF)
670 #endif
672 #ifdef L_m16stubsf9
673 CALL_STUB_RET (__mips16_call_stub_sf_9, 9, SF)
674 #endif
676 #ifdef L_m16stubsf10
677 CALL_STUB_RET (__mips16_call_stub_sf_10, 10, SF)
678 #endif
679 #endif /* !__mips_single_float */
682 /* Now we have the same set of functions again, except that this time
683    the function being called returns an DFmode value.  */
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
690 #ifdef L_m16stubdf1
691 CALL_STUB_RET (__mips16_call_stub_df_1, 1, DF)
692 #endif
694 #ifdef L_m16stubdf5
695 CALL_STUB_RET (__mips16_call_stub_df_5, 5, DF)
696 #endif
698 #ifdef L_m16stubdf2
699 CALL_STUB_RET (__mips16_call_stub_df_2, 2, DF)
700 #endif
702 #ifdef L_m16stubdf6
703 CALL_STUB_RET (__mips16_call_stub_df_6, 6, DF)
704 #endif
706 #ifdef L_m16stubdf9
707 CALL_STUB_RET (__mips16_call_stub_df_9, 9, DF)
708 #endif
710 #ifdef L_m16stubdf10
711 CALL_STUB_RET (__mips16_call_stub_df_10, 10, DF)
712 #endif
713 #endif /* !__mips_single_float */
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.  */
719 #ifdef L_m16stubsc0
720 CALL_STUB_RET (__mips16_call_stub_sc_0, 0, SC)
721 #endif
723 #ifdef L_m16stubsc1
724 CALL_STUB_RET (__mips16_call_stub_sc_1, 1, SC)
725 #endif
727 #ifdef L_m16stubsc5
728 CALL_STUB_RET (__mips16_call_stub_sc_5, 5, SC)
729 #endif
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
736 #ifdef L_m16stubsc6
737 CALL_STUB_RET (__mips16_call_stub_sc_6, 6, SC)
738 #endif
740 #ifdef L_m16stubsc9
741 CALL_STUB_RET (__mips16_call_stub_sc_9, 9, SC)
742 #endif
744 #ifdef L_m16stubsc10
745 CALL_STUB_RET (__mips16_call_stub_sc_10, 10, SC)
746 #endif
747 #endif /* !__mips_single_float */
750 /* Finally, another set of functions for DCmode.  */
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
757 #ifdef L_m16stubdc1
758 CALL_STUB_RET (__mips16_call_stub_dc_1, 1, DC)
759 #endif
761 #ifdef L_m16stubdc5
762 CALL_STUB_RET (__mips16_call_stub_dc_5, 5, DC)
763 #endif
765 #ifdef L_m16stubdc2
766 CALL_STUB_RET (__mips16_call_stub_dc_2, 2, DC)
767 #endif
769 #ifdef L_m16stubdc6
770 CALL_STUB_RET (__mips16_call_stub_dc_6, 6, DC)
771 #endif
773 #ifdef L_m16stubdc9
774 CALL_STUB_RET (__mips16_call_stub_dc_9, 9, DC)
775 #endif
777 #ifdef L_m16stubdc10
778 CALL_STUB_RET (__mips16_call_stub_dc_10, 10, DC)
779 #endif
780 #endif /* !__mips_single_float */
782 #endif
783 #endif /* defined(__mips_micromips) || defined(__mips_soft_float) */