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