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