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