]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgcc/config/mips/mips16.S
Update copyright years in libgcc/
[thirdparty/gcc.git] / libgcc / config / mips / mips16.S
CommitLineData
afba61d1 1/* mips16 floating point support code
ac1dca3c 2 Copyright (C) 1996-2014 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
22c4c869
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
72be589b
MR
92#if __mips >= 4
93/* Coprocessor moves are interlocked from the MIPS IV ISA up. */
94#define DELAYf(T, OPCODE, OP2) DELAYt (T, OPCODE, OP2)
95#else
a38e0142
SL
96/* Use "OPCODE. OP2" and jump to T. */
97#define DELAYf(T, OPCODE, OP2) OPCODE, OP2; jr T
72be589b 98#endif
a38e0142
SL
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) \
afba61d1 203STARTFN (NAME); \
a38e0142
SL
204 MOVE_SF_BYTE0 (t); \
205 MOVE_SF_BYTE4 (t); \
206 OPCODE RET,ARG1,ARG2; \
207 MOVE_SF_RET (f, $31); \
afba61d1
ILT
208 ENDFN (NAME)
209
210#ifdef L_m16addsf3
a38e0142 211OPSF3 (__mips16_addsf3, add.s)
afba61d1
ILT
212#endif
213#ifdef L_m16subsf3
a38e0142 214OPSF3 (__mips16_subsf3, sub.s)
afba61d1
ILT
215#endif
216#ifdef L_m16mulsf3
a38e0142 217OPSF3 (__mips16_mulsf3, mul.s)
afba61d1
ILT
218#endif
219#ifdef L_m16divsf3
a38e0142 220OPSF3 (__mips16_divsf3, div.s)
afba61d1
ILT
221#endif
222
a38e0142
SL
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) \
eb774d8d 228STARTFN (NAME); \
a38e0142
SL
229 MOVE_SF_BYTE0 (t); \
230 OPCODE RET,ARG1; \
231 MOVE_SF_RET (f, $31); \
eb774d8d 232 ENDFN (NAME)
91e01231 233
eb774d8d 234#ifdef L_m16negsf2
a38e0142 235OPSF2 (__mips16_negsf2, neg.s)
eb774d8d
NS
236#endif
237#ifdef L_m16abssf2
a38e0142 238OPSF2 (__mips16_abssf2, abs.s)
eb774d8d 239#endif
91e01231 240
a38e0142 241/* Single-precision comparisons. */
afba61d1 242
a38e0142
SL
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. */
afba61d1 246
a38e0142 247#define CMPSF(NAME, OPCODE, TRUE, FALSE) \
afba61d1 248STARTFN (NAME); \
a38e0142
SL
249 MOVE_SF_BYTE0 (t); \
250 MOVE_SF_BYTE4 (t); \
251 OPCODE ARG1,ARG2; \
afba61d1
ILT
252 li $2,TRUE; \
253 bc1t 1f; \
254 li $2,FALSE; \
2551:; \
256 j $31; \
257 ENDFN (NAME)
258
a38e0142 259/* Like CMPSF, but reverse the comparison operands. */
afba61d1 260
a38e0142 261#define REVCMPSF(NAME, OPCODE, TRUE, FALSE) \
afba61d1 262STARTFN (NAME); \
a38e0142
SL
263 MOVE_SF_BYTE0 (t); \
264 MOVE_SF_BYTE4 (t); \
265 OPCODE ARG2,ARG1; \
afba61d1
ILT
266 li $2,TRUE; \
267 bc1t 1f; \
268 li $2,FALSE; \
2691:; \
270 j $31; \
271 ENDFN (NAME)
272
273#ifdef L_m16eqsf2
a38e0142 274CMPSF (__mips16_eqsf2, c.eq.s, 0, 1)
afba61d1
ILT
275#endif
276#ifdef L_m16nesf2
a38e0142 277CMPSF (__mips16_nesf2, c.eq.s, 0, 1)
afba61d1
ILT
278#endif
279#ifdef L_m16gtsf2
a38e0142 280REVCMPSF (__mips16_gtsf2, c.lt.s, 1, 0)
afba61d1
ILT
281#endif
282#ifdef L_m16gesf2
a38e0142 283REVCMPSF (__mips16_gesf2, c.le.s, 0, -1)
afba61d1
ILT
284#endif
285#ifdef L_m16lesf2
a38e0142 286CMPSF (__mips16_lesf2, c.le.s, 0, 1)
afba61d1
ILT
287#endif
288#ifdef L_m16ltsf2
a38e0142 289CMPSF (__mips16_ltsf2, c.lt.s, -1, 0)
afba61d1 290#endif
45059ab1
SL
291#ifdef L_m16unordsf2
292CMPSF(__mips16_unordsf2, c.un.s, 1, 0)
293#endif
294
afba61d1 295
a38e0142 296/* Single-precision conversions. */
afba61d1
ILT
297
298#ifdef L_m16fltsisf
299STARTFN (__mips16_floatsisf)
a38e0142
SL
300 MOVE_SF_BYTE0 (t)
301 cvt.s.w RET,ARG1
302 MOVE_SF_RET (f, $31)
afba61d1
ILT
303 ENDFN (__mips16_floatsisf)
304#endif
305
45059ab1
SL
306#ifdef L_m16fltunsisf
307STARTFN (__mips16_floatunsisf)
08d0963a 308 .set noreorder
45059ab1 309 bltz $4,1f
08d0963a
RS
310 MOVE_SF_BYTE0 (t)
311 .set reorder
312 cvt.s.w RET,ARG1
313 MOVE_SF_RET (f, $31)
45059ab1
SL
3141:
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
91e01231
EC
325#ifdef L_m16fix_truncsfsi
326STARTFN (__mips16_fix_truncsfsi)
a38e0142
SL
327 MOVE_SF_BYTE0 (t)
328 trunc.w.s RET,ARG1,$4
329 MOVE_SI_RET (f, $31)
91e01231 330 ENDFN (__mips16_fix_truncsfsi)
afba61d1
ILT
331#endif
332
eb774d8d 333#if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
91e01231 334
a38e0142 335/* Double-precision math. */
afba61d1 336
a38e0142
SL
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. */
afba61d1 340
a38e0142 341#define OPDF3(NAME, OPCODE) \
afba61d1 342STARTFN (NAME); \
a38e0142
SL
343 MOVE_DF_BYTE0 (t); \
344 MOVE_DF_BYTE8 (t); \
345 OPCODE RET,ARG1,ARG2; \
346 MOVE_DF_RET (f, $31); \
afba61d1
ILT
347 ENDFN (NAME)
348
349#ifdef L_m16adddf3
a38e0142 350OPDF3 (__mips16_adddf3, add.d)
afba61d1
ILT
351#endif
352#ifdef L_m16subdf3
a38e0142 353OPDF3 (__mips16_subdf3, sub.d)
afba61d1
ILT
354#endif
355#ifdef L_m16muldf3
a38e0142 356OPDF3 (__mips16_muldf3, mul.d)
afba61d1
ILT
357#endif
358#ifdef L_m16divdf3
a38e0142 359OPDF3 (__mips16_divdf3, div.d)
afba61d1
ILT
360#endif
361
a38e0142
SL
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) \
eb774d8d 367STARTFN (NAME); \
a38e0142
SL
368 MOVE_DF_BYTE0 (t); \
369 OPCODE RET,ARG1; \
370 MOVE_DF_RET (f, $31); \
eb774d8d 371 ENDFN (NAME)
91e01231 372
eb774d8d 373#ifdef L_m16negdf2
a38e0142 374OPDF2 (__mips16_negdf2, neg.d)
eb774d8d
NS
375#endif
376#ifdef L_m16absdf2
a38e0142 377OPDF2 (__mips16_absdf2, abs.d)
eb774d8d
NS
378#endif
379
afba61d1
ILT
380/* Conversions between single and double precision. */
381
382#ifdef L_m16extsfdf2
383STARTFN (__mips16_extendsfdf2)
a38e0142
SL
384 MOVE_SF_BYTE0 (t)
385 cvt.d.s RET,ARG1
386 MOVE_DF_RET (f, $31)
afba61d1
ILT
387 ENDFN (__mips16_extendsfdf2)
388#endif
389
390#ifdef L_m16trdfsf2
391STARTFN (__mips16_truncdfsf2)
a38e0142
SL
392 MOVE_DF_BYTE0 (t)
393 cvt.s.d RET,ARG1
394 MOVE_SF_RET (f, $31)
afba61d1
ILT
395 ENDFN (__mips16_truncdfsf2)
396#endif
397
a38e0142 398/* Double-precision comparisons. */
afba61d1 399
a38e0142
SL
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. */
afba61d1 403
a38e0142 404#define CMPDF(NAME, OPCODE, TRUE, FALSE) \
afba61d1 405STARTFN (NAME); \
a38e0142
SL
406 MOVE_DF_BYTE0 (t); \
407 MOVE_DF_BYTE8 (t); \
408 OPCODE ARG1,ARG2; \
afba61d1
ILT
409 li $2,TRUE; \
410 bc1t 1f; \
411 li $2,FALSE; \
4121:; \
413 j $31; \
414 ENDFN (NAME)
415
a38e0142 416/* Like CMPDF, but reverse the comparison operands. */
afba61d1 417
a38e0142 418#define REVCMPDF(NAME, OPCODE, TRUE, FALSE) \
afba61d1 419STARTFN (NAME); \
a38e0142
SL
420 MOVE_DF_BYTE0 (t); \
421 MOVE_DF_BYTE8 (t); \
422 OPCODE ARG2,ARG1; \
afba61d1
ILT
423 li $2,TRUE; \
424 bc1t 1f; \
425 li $2,FALSE; \
4261:; \
427 j $31; \
428 ENDFN (NAME)
429
430#ifdef L_m16eqdf2
a38e0142 431CMPDF (__mips16_eqdf2, c.eq.d, 0, 1)
afba61d1
ILT
432#endif
433#ifdef L_m16nedf2
a38e0142 434CMPDF (__mips16_nedf2, c.eq.d, 0, 1)
afba61d1
ILT
435#endif
436#ifdef L_m16gtdf2
a38e0142 437REVCMPDF (__mips16_gtdf2, c.lt.d, 1, 0)
afba61d1
ILT
438#endif
439#ifdef L_m16gedf2
a38e0142 440REVCMPDF (__mips16_gedf2, c.le.d, 0, -1)
afba61d1
ILT
441#endif
442#ifdef L_m16ledf2
a38e0142 443CMPDF (__mips16_ledf2, c.le.d, 0, 1)
afba61d1
ILT
444#endif
445#ifdef L_m16ltdf2
a38e0142 446CMPDF (__mips16_ltdf2, c.lt.d, -1, 0)
afba61d1 447#endif
45059ab1
SL
448#ifdef L_m16unorddf2
449CMPDF(__mips16_unorddf2, c.un.d, 1, 0)
450#endif
afba61d1 451
a38e0142 452/* Double-precision conversions. */
afba61d1
ILT
453
454#ifdef L_m16fltsidf
455STARTFN (__mips16_floatsidf)
a38e0142
SL
456 MOVE_SI_BYTE0 (t)
457 cvt.d.w RET,ARG1
458 MOVE_DF_RET (f, $31)
afba61d1
ILT
459 ENDFN (__mips16_floatsidf)
460#endif
45059ab1
SL
461
462#ifdef L_m16fltunsidf
463STARTFN (__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
4691: MOVE_DF_RET (f, $31)
470 ENDFN (__mips16_floatunsidf)
471#endif
472
91e01231
EC
473#ifdef L_m16fix_truncdfsi
474STARTFN (__mips16_fix_truncdfsi)
a38e0142
SL
475 MOVE_DF_BYTE0 (t)
476 trunc.w.d RET,ARG1,$4
477 MOVE_SI_RET (f, $31)
91e01231 478 ENDFN (__mips16_fix_truncdfsi)
afba61d1 479#endif
eb774d8d 480#endif /* !__mips_single_float */
afba61d1 481
0f9bde1f
MR
482/* We don't export stubs from libgcc_s.so and always require static
483 versions to be pulled from libgcc.a as needed because they use $2
484 and possibly $3 as arguments, diverging from the standard SysV ABI,
485 and as such would require severe pessimisation of MIPS16 PLT entries
486 just for this single special case.
487
488 For compatibility with old binaries that used safe standard MIPS PLT
489 entries and referred to these functions we still export them at
490 version GCC_4.4.0 for run-time loading only. */
491
492#ifdef SHARED
493#define CE_STARTFN(NAME) \
494STARTFN (NAME##_compat); \
495 .symver NAME##_compat, NAME@GCC_4.4.0
496#define CE_ENDFN(NAME) ENDFN (NAME##_compat)
497#else
498#define CE_STARTFN(NAME) \
499STARTFN (NAME); \
500 .hidden NAME
501#define CE_ENDFN(NAME) ENDFN (NAME)
502#endif
503
a38e0142
SL
504/* Define a function NAME that moves a return value of mode MODE from
505 FPRs to GPRs. */
506
507#define RET_FUNCTION(NAME, MODE) \
0f9bde1f 508CE_STARTFN (NAME); \
a38e0142 509 MOVE_##MODE##_RET (t, $31); \
0f9bde1f 510 CE_ENDFN (NAME)
afba61d1
ILT
511
512#ifdef L_m16retsf
a38e0142
SL
513RET_FUNCTION (__mips16_ret_sf, SF)
514#endif
515
516#ifdef L_m16retsc
517RET_FUNCTION (__mips16_ret_sc, SC)
afba61d1
ILT
518#endif
519
eb774d8d 520#if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
afba61d1 521#ifdef L_m16retdf
a38e0142 522RET_FUNCTION (__mips16_ret_df, DF)
eb774d8d 523#endif
a38e0142
SL
524
525#ifdef L_m16retdc
526RET_FUNCTION (__mips16_ret_dc, DC)
afba61d1 527#endif
eb774d8d 528#endif /* !__mips_single_float */
afba61d1 529
a38e0142
SL
530/* STUB_ARGS_X copies the arguments from GPRs to FPRs for argument
531 code X. X is calculated as ARG1 + ARG2 * 4, where ARG1 and ARG2
532 classify the first and second arguments as follows:
533
534 1: a single-precision argument
535 2: a double-precision argument
536 0: no argument, or not one of the above. */
537
538#define STUB_ARGS_0 /* () */
539#define STUB_ARGS_1 MOVE_SF_BYTE0 (t) /* (sf) */
540#define STUB_ARGS_5 MOVE_SF_BYTE0 (t); MOVE_SF_BYTE4 (t) /* (sf, sf) */
541#define STUB_ARGS_9 MOVE_SF_BYTE0 (t); MOVE_DF_BYTE8 (t) /* (sf, df) */
542#define STUB_ARGS_2 MOVE_DF_BYTE0 (t) /* (df) */
543#define STUB_ARGS_6 MOVE_DF_BYTE0 (t); MOVE_SF_BYTE8 (t) /* (df, sf) */
544#define STUB_ARGS_10 MOVE_DF_BYTE0 (t); MOVE_DF_BYTE8 (t) /* (df, df) */
545
85f65093 546/* These functions are used by 16-bit code when calling via a function
a38e0142
SL
547 pointer. They must copy the floating point arguments from the GPRs
548 to FPRs and then call function $2. */
549
550#define CALL_STUB_NO_RET(NAME, CODE) \
0f9bde1f 551CE_STARTFN (NAME); \
a38e0142 552 STUB_ARGS_##CODE; \
08d0963a 553 .set noreorder; \
a38e0142 554 jr $2; \
08d0963a
RS
555 move $25,$2; \
556 .set reorder; \
0f9bde1f 557 CE_ENDFN (NAME)
afba61d1
ILT
558
559#ifdef L_m16stub1
a38e0142 560CALL_STUB_NO_RET (__mips16_call_stub_1, 1)
afba61d1
ILT
561#endif
562
afba61d1 563#ifdef L_m16stub5
a38e0142 564CALL_STUB_NO_RET (__mips16_call_stub_5, 5)
afba61d1
ILT
565#endif
566
eb774d8d
NS
567#if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
568
569#ifdef L_m16stub2
a38e0142 570CALL_STUB_NO_RET (__mips16_call_stub_2, 2)
eb774d8d
NS
571#endif
572
afba61d1 573#ifdef L_m16stub6
a38e0142 574CALL_STUB_NO_RET (__mips16_call_stub_6, 6)
afba61d1
ILT
575#endif
576
577#ifdef L_m16stub9
a38e0142 578CALL_STUB_NO_RET (__mips16_call_stub_9, 9)
afba61d1
ILT
579#endif
580
581#ifdef L_m16stub10
a38e0142 582CALL_STUB_NO_RET (__mips16_call_stub_10, 10)
afba61d1 583#endif
eb774d8d 584#endif /* !__mips_single_float */
afba61d1
ILT
585
586/* Now we have the same set of functions, except that this time the
a38e0142
SL
587 function being called returns an SFmode, SCmode, DFmode or DCmode
588 value; we need to instantiate a set for each case. The calling
afba61d1
ILT
589 function will arrange to preserve $18, so these functions are free
590 to use it to hold the return address.
591
592 Note that we do not know whether the function we are calling is 16
85f65093 593 bit or 32 bit. However, it does not matter, because 16-bit
afba61d1
ILT
594 functions always return floating point values in both the gp and
595 the fp regs. It would be possible to check whether the function
596 being called is 16 bits, in which case the copy is unnecessary;
597 however, it's faster to always do the copy. */
598
5adeb246 599#define CALL_STUB_RET(NAME, CODE, MODE) \
0f9bde1f 600CE_STARTFN (NAME); \
5adeb246
RS
601 .cfi_startproc; \
602 /* Create a fake CFA 4 bytes below the stack pointer. */ \
603 .cfi_def_cfa 29,-4; \
604 /* "Save" $sp in itself so we don't use the fake CFA. \
605 This is: DW_CFA_val_expression r29, { DW_OP_reg29 }. */ \
606 .cfi_escape 0x16,29,1,0x6d; \
607 move $18,$31; \
608 .cfi_register 31,18; \
609 STUB_ARGS_##CODE; \
610 .set noreorder; \
611 jalr $2; \
612 move $25,$2; \
613 .set reorder; \
614 MOVE_##MODE##_RET (f, $18); \
615 .cfi_endproc; \
0f9bde1f 616 CE_ENDFN (NAME)
a38e0142
SL
617
618/* First, instantiate the single-float set. */
619
afba61d1 620#ifdef L_m16stubsf0
a38e0142 621CALL_STUB_RET (__mips16_call_stub_sf_0, 0, SF)
afba61d1
ILT
622#endif
623
624#ifdef L_m16stubsf1
a38e0142 625CALL_STUB_RET (__mips16_call_stub_sf_1, 1, SF)
afba61d1
ILT
626#endif
627
eb774d8d 628#ifdef L_m16stubsf5
a38e0142 629CALL_STUB_RET (__mips16_call_stub_sf_5, 5, SF)
afba61d1
ILT
630#endif
631
eb774d8d
NS
632#if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
633#ifdef L_m16stubsf2
a38e0142 634CALL_STUB_RET (__mips16_call_stub_sf_2, 2, SF)
afba61d1
ILT
635#endif
636
637#ifdef L_m16stubsf6
a38e0142 638CALL_STUB_RET (__mips16_call_stub_sf_6, 6, SF)
afba61d1
ILT
639#endif
640
641#ifdef L_m16stubsf9
a38e0142 642CALL_STUB_RET (__mips16_call_stub_sf_9, 9, SF)
afba61d1
ILT
643#endif
644
645#ifdef L_m16stubsf10
a38e0142 646CALL_STUB_RET (__mips16_call_stub_sf_10, 10, SF)
afba61d1 647#endif
a38e0142
SL
648#endif /* !__mips_single_float */
649
afba61d1
ILT
650
651/* Now we have the same set of functions again, except that this time
652 the function being called returns an DFmode value. */
653
a38e0142 654#if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
afba61d1 655#ifdef L_m16stubdf0
a38e0142 656CALL_STUB_RET (__mips16_call_stub_df_0, 0, DF)
afba61d1
ILT
657#endif
658
659#ifdef L_m16stubdf1
a38e0142 660CALL_STUB_RET (__mips16_call_stub_df_1, 1, DF)
afba61d1
ILT
661#endif
662
a38e0142
SL
663#ifdef L_m16stubdf5
664CALL_STUB_RET (__mips16_call_stub_df_5, 5, DF)
afba61d1
ILT
665#endif
666
a38e0142
SL
667#ifdef L_m16stubdf2
668CALL_STUB_RET (__mips16_call_stub_df_2, 2, DF)
afba61d1
ILT
669#endif
670
671#ifdef L_m16stubdf6
a38e0142 672CALL_STUB_RET (__mips16_call_stub_df_6, 6, DF)
afba61d1
ILT
673#endif
674
675#ifdef L_m16stubdf9
a38e0142 676CALL_STUB_RET (__mips16_call_stub_df_9, 9, DF)
afba61d1
ILT
677#endif
678
679#ifdef L_m16stubdf10
a38e0142
SL
680CALL_STUB_RET (__mips16_call_stub_df_10, 10, DF)
681#endif
682#endif /* !__mips_single_float */
683
684
685/* Ho hum. Here we have the same set of functions again, this time
686 for when the function being called returns an SCmode value. */
687
688#ifdef L_m16stubsc0
689CALL_STUB_RET (__mips16_call_stub_sc_0, 0, SC)
690#endif
691
692#ifdef L_m16stubsc1
693CALL_STUB_RET (__mips16_call_stub_sc_1, 1, SC)
694#endif
695
696#ifdef L_m16stubsc5
697CALL_STUB_RET (__mips16_call_stub_sc_5, 5, SC)
698#endif
699
700#if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
701#ifdef L_m16stubsc2
702CALL_STUB_RET (__mips16_call_stub_sc_2, 2, SC)
703#endif
704
705#ifdef L_m16stubsc6
706CALL_STUB_RET (__mips16_call_stub_sc_6, 6, SC)
707#endif
708
709#ifdef L_m16stubsc9
710CALL_STUB_RET (__mips16_call_stub_sc_9, 9, SC)
711#endif
712
713#ifdef L_m16stubsc10
714CALL_STUB_RET (__mips16_call_stub_sc_10, 10, SC)
715#endif
716#endif /* !__mips_single_float */
717
718
719/* Finally, another set of functions for DCmode. */
720
721#if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
722#ifdef L_m16stubdc0
723CALL_STUB_RET (__mips16_call_stub_dc_0, 0, DC)
724#endif
725
726#ifdef L_m16stubdc1
727CALL_STUB_RET (__mips16_call_stub_dc_1, 1, DC)
728#endif
729
730#ifdef L_m16stubdc5
731CALL_STUB_RET (__mips16_call_stub_dc_5, 5, DC)
732#endif
733
734#ifdef L_m16stubdc2
735CALL_STUB_RET (__mips16_call_stub_dc_2, 2, DC)
736#endif
737
738#ifdef L_m16stubdc6
739CALL_STUB_RET (__mips16_call_stub_dc_6, 6, DC)
740#endif
741
742#ifdef L_m16stubdc9
743CALL_STUB_RET (__mips16_call_stub_dc_9, 9, DC)
744#endif
745
746#ifdef L_m16stubdc10
747CALL_STUB_RET (__mips16_call_stub_dc_10, 10, DC)
afba61d1 748#endif
eb774d8d 749#endif /* !__mips_single_float */
ddaf8125 750
08d0963a 751#endif
22c4c869 752#endif /* __mips_micromips */