OSDN Git Service

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