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