1 /* mips16 floating point support code
2 Copyright (C) 1996, 1997, 1998, 2008, 2009 Free Software Foundation, Inc.
3 Contributed by Cygnus Support
5 This file is free software; you can redistribute it and/or modify it
6 under the terms of the GNU General Public License as published by the
7 Free Software Foundation; either version 3, or (at your option) any
10 This file is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 Under Section 7 of GPL version 3, you are granted additional
16 permissions described in the GCC Runtime Library Exception, version
17 3.1, as published by the Free Software Foundation.
19 You should have received a copy of the GNU General Public License and
20 a copy of the GCC Runtime Library Exception along with this program;
21 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
22 <http://www.gnu.org/licenses/>. */
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. */
30 #if defined _MIPS_SIM && (_MIPS_SIM == _ABIO32 || _MIPS_SIM == _ABIO64)
32 /* This file contains 32-bit assembly code. */
35 /* Start a function. */
37 #define STARTFN(NAME) .globl NAME; .ent NAME; NAME:
39 /* Finish a function. */
41 #define ENDFN(NAME) .end NAME
44 The FPR that holds the first floating-point argument.
47 The FPR that holds the second floating-point argument.
50 The FPR that holds a floating-point return value. */
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) \
70 /* Move the high 32 bits of GPR to HIGH_FPR and the low 32 bits of
72 #define MERGE_GPRt(GPR, HIGH_FPR, LOW_FPR) \
79 /* Jump to T, and use "OPCODE, OP2" to implement a delayed move. */
80 #define DELAYt(T, OPCODE, OP2) \
86 /* Use "OPCODE. OP2" and jump to T. */
87 #define DELAYf(T, OPCODE, OP2) OPCODE, OP2; jr T
90 Move the first single-precision floating-point argument between
94 Likewise the first single-precision integer argument.
97 Move the second single-precision floating-point argument between
98 GPRs and FPRs, given that the first argument occupies 4 bytes.
101 Move the second single-precision floating-point argument between
102 GPRs and FPRs, given that the first argument occupies 8 bytes.
105 Move the first double-precision floating-point argument between
109 Likewise the second double-precision floating-point argument.
112 Likewise a single-precision floating-point return value,
116 Likewise a complex single-precision floating-point return value.
119 Likewise a double-precision floating-point return value.
122 Likewise a complex double-precision floating-point return value.
125 Likewise a single-precision integer return value.
127 The D argument is "t" to move to FPRs and "f" to move from FPRs.
128 The return macros may assume that the target of the jump does not
129 use a floating-point register. */
131 #define MOVE_SF_RET(D, T) DELAY##D (T, m##D##c1 $2,$f0)
132 #define MOVE_SI_RET(D, T) DELAY##D (T, m##D##c1 $2,$f0)
134 #if defined(__mips64) && defined(__MIPSEB__)
135 #define MOVE_SC_RET(D, T) MERGE_GPR##D ($2, $f0, $f1); jr T
136 #elif defined(__mips64)
137 /* The high 32 bits of $2 correspond to the second word in memory;
138 i.e. the imaginary part. */
139 #define MOVE_SC_RET(D, T) MERGE_GPR##D ($2, $f1, $f0); jr T
140 #elif __mips_fpr == 64
141 #define MOVE_SC_RET(D, T) m##D##c1 $2,$f0; DELAY##D (T, m##D##c1 $3,$f1)
143 #define MOVE_SC_RET(D, T) m##D##c1 $2,$f0; DELAY##D (T, m##D##c1 $3,$f2)
146 #if defined(__mips64)
147 #define MOVE_SF_BYTE0(D) m##D##c1 $4,$f12
148 #define MOVE_SF_BYTE4(D) m##D##c1 $5,$f13
149 #define MOVE_SF_BYTE8(D) m##D##c1 $5,$f13
151 #define MOVE_SF_BYTE0(D) m##D##c1 $4,$f12
152 #define MOVE_SF_BYTE4(D) m##D##c1 $5,$f14
153 #define MOVE_SF_BYTE8(D) m##D##c1 $6,$f14
155 #define MOVE_SI_BYTE0(D) MOVE_SF_BYTE0(D)
157 #if defined(__mips64)
158 #define MOVE_DF_BYTE0(D) dm##D##c1 $4,$f12
159 #define MOVE_DF_BYTE8(D) dm##D##c1 $5,$f13
160 #define MOVE_DF_RET(D, T) DELAY##D (T, dm##D##c1 $2,$f0)
161 #define MOVE_DC_RET(D, T) dm##D##c1 $3,$f1; MOVE_DF_RET (D, T)
162 #elif __mips_fpr == 64 && defined(__MIPSEB__)
163 #define MOVE_DF_BYTE0(D) m##D##c1 $5,$f12; m##D##hc1 $4,$f12
164 #define MOVE_DF_BYTE8(D) m##D##c1 $7,$f14; m##D##hc1 $6,$f14
165 #define MOVE_DF_RET(D, T) m##D##c1 $3,$f0; DELAY##D (T, m##D##hc1 $2,$f0)
166 #define MOVE_DC_RET(D, T) m##D##c1 $5,$f1; m##D##hc1 $4,$f1; MOVE_DF_RET (D, T)
167 #elif __mips_fpr == 64
168 #define MOVE_DF_BYTE0(D) m##D##c1 $4,$f12; m##D##hc1 $5,$f12
169 #define MOVE_DF_BYTE8(D) m##D##c1 $6,$f14; m##D##hc1 $7,$f14
170 #define MOVE_DF_RET(D, T) m##D##c1 $2,$f0; DELAY##D (T, m##D##hc1 $3,$f0)
171 #define MOVE_DC_RET(D, T) m##D##c1 $4,$f1; m##D##hc1 $5,$f1; MOVE_DF_RET (D, T)
172 #elif defined(__MIPSEB__)
173 /* FPRs are little-endian. */
174 #define MOVE_DF_BYTE0(D) m##D##c1 $4,$f13; m##D##c1 $5,$f12
175 #define MOVE_DF_BYTE8(D) m##D##c1 $6,$f15; m##D##c1 $7,$f14
176 #define MOVE_DF_RET(D, T) m##D##c1 $2,$f1; DELAY##D (T, m##D##c1 $3,$f0)
177 #define MOVE_DC_RET(D, T) m##D##c1 $4,$f3; m##D##c1 $5,$f2; MOVE_DF_RET (D, T)
179 #define MOVE_DF_BYTE0(D) m##D##c1 $4,$f12; m##D##c1 $5,$f13
180 #define MOVE_DF_BYTE8(D) m##D##c1 $6,$f14; m##D##c1 $7,$f15
181 #define MOVE_DF_RET(D, T) m##D##c1 $2,$f0; DELAY##D (T, m##D##c1 $3,$f1)
182 #define MOVE_DC_RET(D, T) m##D##c1 $4,$f2; m##D##c1 $5,$f3; MOVE_DF_RET (D, T)
185 /* Single-precision math. */
187 /* Define a function NAME that loads two single-precision values,
188 performs FPU operation OPCODE on them, and returns the single-
191 #define OPSF3(NAME, OPCODE) \
195 OPCODE RET,ARG1,ARG2; \
196 MOVE_SF_RET (f, $31); \
200 OPSF3 (__mips16_addsf3, add.s)
203 OPSF3 (__mips16_subsf3, sub.s)
206 OPSF3 (__mips16_mulsf3, mul.s)
209 OPSF3 (__mips16_divsf3, div.s)
212 /* Define a function NAME that loads a single-precision value,
213 performs FPU operation OPCODE on it, and returns the single-
216 #define OPSF2(NAME, OPCODE) \
220 MOVE_SF_RET (f, $31); \
224 OPSF2 (__mips16_negsf2, neg.s)
227 OPSF2 (__mips16_abssf2, abs.s)
230 /* Single-precision comparisons. */
232 /* Define a function NAME that loads two single-precision values,
233 performs floating point comparison OPCODE, and returns TRUE or
234 FALSE depending on the result. */
236 #define CMPSF(NAME, OPCODE, TRUE, FALSE) \
248 /* Like CMPSF, but reverse the comparison operands. */
250 #define REVCMPSF(NAME, OPCODE, TRUE, FALSE) \
263 CMPSF (__mips16_eqsf2, c.eq.s, 0, 1)
266 CMPSF (__mips16_nesf2, c.eq.s, 0, 1)
269 REVCMPSF (__mips16_gtsf2, c.lt.s, 1, 0)
272 REVCMPSF (__mips16_gesf2, c.le.s, 0, -1)
275 CMPSF (__mips16_lesf2, c.le.s, 0, 1)
278 CMPSF (__mips16_ltsf2, c.lt.s, -1, 0)
281 CMPSF(__mips16_unordsf2, c.un.s, 1, 0)
285 /* Single-precision conversions. */
288 STARTFN (__mips16_floatsisf)
292 ENDFN (__mips16_floatsisf)
295 #ifdef L_m16fltunsisf
296 STARTFN (__mips16_floatunsisf)
311 ENDFN (__mips16_floatunsisf)
314 #ifdef L_m16fix_truncsfsi
315 STARTFN (__mips16_fix_truncsfsi)
317 trunc.w.s RET,ARG1,$4
319 ENDFN (__mips16_fix_truncsfsi)
322 #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
324 /* Double-precision math. */
326 /* Define a function NAME that loads two double-precision values,
327 performs FPU operation OPCODE on them, and returns the double-
330 #define OPDF3(NAME, OPCODE) \
334 OPCODE RET,ARG1,ARG2; \
335 MOVE_DF_RET (f, $31); \
339 OPDF3 (__mips16_adddf3, add.d)
342 OPDF3 (__mips16_subdf3, sub.d)
345 OPDF3 (__mips16_muldf3, mul.d)
348 OPDF3 (__mips16_divdf3, div.d)
351 /* Define a function NAME that loads a double-precision value,
352 performs FPU operation OPCODE on it, and returns the double-
355 #define OPDF2(NAME, OPCODE) \
359 MOVE_DF_RET (f, $31); \
363 OPDF2 (__mips16_negdf2, neg.d)
366 OPDF2 (__mips16_absdf2, abs.d)
369 /* Conversions between single and double precision. */
372 STARTFN (__mips16_extendsfdf2)
376 ENDFN (__mips16_extendsfdf2)
380 STARTFN (__mips16_truncdfsf2)
384 ENDFN (__mips16_truncdfsf2)
387 /* Double-precision comparisons. */
389 /* Define a function NAME that loads two double-precision values,
390 performs floating point comparison OPCODE, and returns TRUE or
391 FALSE depending on the result. */
393 #define CMPDF(NAME, OPCODE, TRUE, FALSE) \
405 /* Like CMPDF, but reverse the comparison operands. */
407 #define REVCMPDF(NAME, OPCODE, TRUE, FALSE) \
420 CMPDF (__mips16_eqdf2, c.eq.d, 0, 1)
423 CMPDF (__mips16_nedf2, c.eq.d, 0, 1)
426 REVCMPDF (__mips16_gtdf2, c.lt.d, 1, 0)
429 REVCMPDF (__mips16_gedf2, c.le.d, 0, -1)
432 CMPDF (__mips16_ledf2, c.le.d, 0, 1)
435 CMPDF (__mips16_ltdf2, c.lt.d, -1, 0)
438 CMPDF(__mips16_unorddf2, c.un.d, 1, 0)
441 /* Double-precision conversions. */
444 STARTFN (__mips16_floatsidf)
448 ENDFN (__mips16_floatsidf)
451 #ifdef L_m16fltunsidf
452 STARTFN (__mips16_floatunsidf)
456 li.d ARG1, 4.294967296e+9
458 1: MOVE_DF_RET (f, $31)
459 ENDFN (__mips16_floatunsidf)
462 #ifdef L_m16fix_truncdfsi
463 STARTFN (__mips16_fix_truncdfsi)
465 trunc.w.d RET,ARG1,$4
467 ENDFN (__mips16_fix_truncdfsi)
469 #endif /* !__mips_single_float */
471 /* Define a function NAME that moves a return value of mode MODE from
474 #define RET_FUNCTION(NAME, MODE) \
476 MOVE_##MODE##_RET (t, $31); \
480 RET_FUNCTION (__mips16_ret_sf, SF)
484 RET_FUNCTION (__mips16_ret_sc, SC)
487 #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
489 RET_FUNCTION (__mips16_ret_df, DF)
493 RET_FUNCTION (__mips16_ret_dc, DC)
495 #endif /* !__mips_single_float */
497 /* STUB_ARGS_X copies the arguments from GPRs to FPRs for argument
498 code X. X is calculated as ARG1 + ARG2 * 4, where ARG1 and ARG2
499 classify the first and second arguments as follows:
501 1: a single-precision argument
502 2: a double-precision argument
503 0: no argument, or not one of the above. */
505 #define STUB_ARGS_0 /* () */
506 #define STUB_ARGS_1 MOVE_SF_BYTE0 (t) /* (sf) */
507 #define STUB_ARGS_5 MOVE_SF_BYTE0 (t); MOVE_SF_BYTE4 (t) /* (sf, sf) */
508 #define STUB_ARGS_9 MOVE_SF_BYTE0 (t); MOVE_DF_BYTE8 (t) /* (sf, df) */
509 #define STUB_ARGS_2 MOVE_DF_BYTE0 (t) /* (df) */
510 #define STUB_ARGS_6 MOVE_DF_BYTE0 (t); MOVE_SF_BYTE8 (t) /* (df, sf) */
511 #define STUB_ARGS_10 MOVE_DF_BYTE0 (t); MOVE_DF_BYTE8 (t) /* (df, df) */
513 /* These functions are used by 16-bit code when calling via a function
514 pointer. They must copy the floating point arguments from the GPRs
515 to FPRs and then call function $2. */
517 #define CALL_STUB_NO_RET(NAME, CODE) \
527 CALL_STUB_NO_RET (__mips16_call_stub_1, 1)
531 CALL_STUB_NO_RET (__mips16_call_stub_5, 5)
534 #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
537 CALL_STUB_NO_RET (__mips16_call_stub_2, 2)
541 CALL_STUB_NO_RET (__mips16_call_stub_6, 6)
545 CALL_STUB_NO_RET (__mips16_call_stub_9, 9)
549 CALL_STUB_NO_RET (__mips16_call_stub_10, 10)
551 #endif /* !__mips_single_float */
553 /* Now we have the same set of functions, except that this time the
554 function being called returns an SFmode, SCmode, DFmode or DCmode
555 value; we need to instantiate a set for each case. The calling
556 function will arrange to preserve $18, so these functions are free
557 to use it to hold the return address.
559 Note that we do not know whether the function we are calling is 16
560 bit or 32 bit. However, it does not matter, because 16-bit
561 functions always return floating point values in both the gp and
562 the fp regs. It would be possible to check whether the function
563 being called is 16 bits, in which case the copy is unnecessary;
564 however, it's faster to always do the copy. */
566 #define CALL_STUB_RET(NAME, CODE, MODE) \
574 MOVE_##MODE##_RET (f, $18); \
577 /* First, instantiate the single-float set. */
580 CALL_STUB_RET (__mips16_call_stub_sf_0, 0, SF)
584 CALL_STUB_RET (__mips16_call_stub_sf_1, 1, SF)
588 CALL_STUB_RET (__mips16_call_stub_sf_5, 5, SF)
591 #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
593 CALL_STUB_RET (__mips16_call_stub_sf_2, 2, SF)
597 CALL_STUB_RET (__mips16_call_stub_sf_6, 6, SF)
601 CALL_STUB_RET (__mips16_call_stub_sf_9, 9, SF)
605 CALL_STUB_RET (__mips16_call_stub_sf_10, 10, SF)
607 #endif /* !__mips_single_float */
610 /* Now we have the same set of functions again, except that this time
611 the function being called returns an DFmode value. */
613 #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
615 CALL_STUB_RET (__mips16_call_stub_df_0, 0, DF)
619 CALL_STUB_RET (__mips16_call_stub_df_1, 1, DF)
623 CALL_STUB_RET (__mips16_call_stub_df_5, 5, DF)
627 CALL_STUB_RET (__mips16_call_stub_df_2, 2, DF)
631 CALL_STUB_RET (__mips16_call_stub_df_6, 6, DF)
635 CALL_STUB_RET (__mips16_call_stub_df_9, 9, DF)
639 CALL_STUB_RET (__mips16_call_stub_df_10, 10, DF)
641 #endif /* !__mips_single_float */
644 /* Ho hum. Here we have the same set of functions again, this time
645 for when the function being called returns an SCmode value. */
648 CALL_STUB_RET (__mips16_call_stub_sc_0, 0, SC)
652 CALL_STUB_RET (__mips16_call_stub_sc_1, 1, SC)
656 CALL_STUB_RET (__mips16_call_stub_sc_5, 5, SC)
659 #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
661 CALL_STUB_RET (__mips16_call_stub_sc_2, 2, SC)
665 CALL_STUB_RET (__mips16_call_stub_sc_6, 6, SC)
669 CALL_STUB_RET (__mips16_call_stub_sc_9, 9, SC)
673 CALL_STUB_RET (__mips16_call_stub_sc_10, 10, SC)
675 #endif /* !__mips_single_float */
678 /* Finally, another set of functions for DCmode. */
680 #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
682 CALL_STUB_RET (__mips16_call_stub_dc_0, 0, DC)
686 CALL_STUB_RET (__mips16_call_stub_dc_1, 1, DC)
690 CALL_STUB_RET (__mips16_call_stub_dc_5, 5, DC)
694 CALL_STUB_RET (__mips16_call_stub_dc_2, 2, DC)
698 CALL_STUB_RET (__mips16_call_stub_dc_6, 6, DC)
702 CALL_STUB_RET (__mips16_call_stub_dc_9, 9, DC)
706 CALL_STUB_RET (__mips16_call_stub_dc_10, 10, DC)
708 #endif /* !__mips_single_float */