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