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