1 /* mips16 floating point support code
2 Copyright (C) 1996, 1997, 1998, 2008, 2009, 2010
3 Free Software Foundation, Inc.
4 Contributed by Cygnus Support
6 This file is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 3, or (at your option) any
11 This file is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 Under Section 7 of GPL version 3, you are granted additional
17 permissions described in the GCC Runtime Library Exception, version
18 3.1, as published by the Free Software Foundation.
20 You should have received a copy of the GNU General Public License and
21 a copy of the GCC Runtime Library Exception along with this program;
22 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 <http://www.gnu.org/licenses/>. */
25 /* This file contains mips16 floating point support functions. These
26 functions are called by mips16 code to handle floating point when
27 -msoft-float is not used. They accept the arguments and return
28 values using the soft-float calling convention, but do the actual
29 operation using the hard floating point instructions. */
31 #if defined _MIPS_SIM && (_MIPS_SIM == _ABIO32 || _MIPS_SIM == _ABIO64)
33 /* This file contains 32-bit assembly code. */
36 /* Start a function. */
38 #define STARTFN(NAME) .globl NAME; .ent NAME; NAME:
40 /* Finish a function. */
42 #define ENDFN(NAME) .end NAME
45 The FPR that holds the first floating-point argument.
48 The FPR that holds the second floating-point argument.
51 The FPR that holds a floating-point return value. */
61 /* Set 64-bit register GPR so that its high 32 bits contain HIGH_FPR
62 and so that its low 32 bits contain LOW_FPR. */
63 #define MERGE_GPRf(GPR, HIGH_FPR, LOW_FPR) \
73 /* Move the high 32 bits of GPR to HIGH_FPR and the low 32 bits of
75 #define MERGE_GPRt(GPR, HIGH_FPR, LOW_FPR) \
82 /* Jump to T, and use "OPCODE, OP2" to implement a delayed move. */
83 #define DELAYt(T, OPCODE, OP2) \
89 /* Use "OPCODE. OP2" and jump to T. */
90 #define DELAYf(T, OPCODE, OP2) OPCODE, OP2; jr T
93 Move the first single-precision floating-point argument between
97 Likewise the first single-precision integer argument.
100 Move the second single-precision floating-point argument between
101 GPRs and FPRs, given that the first argument occupies 4 bytes.
104 Move the second single-precision floating-point argument between
105 GPRs and FPRs, given that the first argument occupies 8 bytes.
108 Move the first double-precision floating-point argument between
112 Likewise the second double-precision floating-point argument.
115 Likewise a single-precision floating-point return value,
119 Likewise a complex single-precision floating-point return value.
122 Likewise a double-precision floating-point return value.
125 Likewise a complex double-precision floating-point return value.
128 Likewise a single-precision integer return value.
130 The D argument is "t" to move to FPRs and "f" to move from FPRs.
131 The return macros may assume that the target of the jump does not
132 use a floating-point register. */
134 #define MOVE_SF_RET(D, T) DELAY##D (T, m##D##c1 $2,$f0)
135 #define MOVE_SI_RET(D, T) DELAY##D (T, m##D##c1 $2,$f0)
137 #if defined(__mips64) && defined(__MIPSEB__)
138 #define MOVE_SC_RET(D, T) MERGE_GPR##D ($2, $f0, $f1); jr T
139 #elif defined(__mips64)
140 /* The high 32 bits of $2 correspond to the second word in memory;
141 i.e. the imaginary part. */
142 #define MOVE_SC_RET(D, T) MERGE_GPR##D ($2, $f1, $f0); jr T
143 #elif __mips_fpr == 64
144 #define MOVE_SC_RET(D, T) m##D##c1 $2,$f0; DELAY##D (T, m##D##c1 $3,$f1)
146 #define MOVE_SC_RET(D, T) m##D##c1 $2,$f0; DELAY##D (T, m##D##c1 $3,$f2)
149 #if defined(__mips64)
150 #define MOVE_SF_BYTE0(D) m##D##c1 $4,$f12
151 #define MOVE_SF_BYTE4(D) m##D##c1 $5,$f13
152 #define MOVE_SF_BYTE8(D) m##D##c1 $5,$f13
154 #define MOVE_SF_BYTE0(D) m##D##c1 $4,$f12
155 #define MOVE_SF_BYTE4(D) m##D##c1 $5,$f14
156 #define MOVE_SF_BYTE8(D) m##D##c1 $6,$f14
158 #define MOVE_SI_BYTE0(D) MOVE_SF_BYTE0(D)
160 #if defined(__mips64)
161 #define MOVE_DF_BYTE0(D) dm##D##c1 $4,$f12
162 #define MOVE_DF_BYTE8(D) dm##D##c1 $5,$f13
163 #define MOVE_DF_RET(D, T) DELAY##D (T, dm##D##c1 $2,$f0)
164 #define MOVE_DC_RET(D, T) dm##D##c1 $3,$f1; MOVE_DF_RET (D, T)
165 #elif __mips_fpr == 64 && defined(__MIPSEB__)
166 #define MOVE_DF_BYTE0(D) m##D##c1 $5,$f12; m##D##hc1 $4,$f12
167 #define MOVE_DF_BYTE8(D) m##D##c1 $7,$f14; m##D##hc1 $6,$f14
168 #define MOVE_DF_RET(D, T) m##D##c1 $3,$f0; DELAY##D (T, m##D##hc1 $2,$f0)
169 #define MOVE_DC_RET(D, T) m##D##c1 $5,$f1; m##D##hc1 $4,$f1; MOVE_DF_RET (D, T)
170 #elif __mips_fpr == 64
171 #define MOVE_DF_BYTE0(D) m##D##c1 $4,$f12; m##D##hc1 $5,$f12
172 #define MOVE_DF_BYTE8(D) m##D##c1 $6,$f14; m##D##hc1 $7,$f14
173 #define MOVE_DF_RET(D, T) m##D##c1 $2,$f0; DELAY##D (T, m##D##hc1 $3,$f0)
174 #define MOVE_DC_RET(D, T) m##D##c1 $4,$f1; m##D##hc1 $5,$f1; MOVE_DF_RET (D, T)
175 #elif defined(__MIPSEB__)
176 /* FPRs are little-endian. */
177 #define MOVE_DF_BYTE0(D) m##D##c1 $4,$f13; m##D##c1 $5,$f12
178 #define MOVE_DF_BYTE8(D) m##D##c1 $6,$f15; m##D##c1 $7,$f14
179 #define MOVE_DF_RET(D, T) m##D##c1 $2,$f1; DELAY##D (T, m##D##c1 $3,$f0)
180 #define MOVE_DC_RET(D, T) m##D##c1 $4,$f3; m##D##c1 $5,$f2; MOVE_DF_RET (D, T)
182 #define MOVE_DF_BYTE0(D) m##D##c1 $4,$f12; m##D##c1 $5,$f13
183 #define MOVE_DF_BYTE8(D) m##D##c1 $6,$f14; m##D##c1 $7,$f15
184 #define MOVE_DF_RET(D, T) m##D##c1 $2,$f0; DELAY##D (T, m##D##c1 $3,$f1)
185 #define MOVE_DC_RET(D, T) m##D##c1 $4,$f2; m##D##c1 $5,$f3; MOVE_DF_RET (D, T)
188 /* Single-precision math. */
190 /* Define a function NAME that loads two single-precision values,
191 performs FPU operation OPCODE on them, and returns the single-
194 #define OPSF3(NAME, OPCODE) \
198 OPCODE RET,ARG1,ARG2; \
199 MOVE_SF_RET (f, $31); \
203 OPSF3 (__mips16_addsf3, add.s)
206 OPSF3 (__mips16_subsf3, sub.s)
209 OPSF3 (__mips16_mulsf3, mul.s)
212 OPSF3 (__mips16_divsf3, div.s)
215 /* Define a function NAME that loads a single-precision value,
216 performs FPU operation OPCODE on it, and returns the single-
219 #define OPSF2(NAME, OPCODE) \
223 MOVE_SF_RET (f, $31); \
227 OPSF2 (__mips16_negsf2, neg.s)
230 OPSF2 (__mips16_abssf2, abs.s)
233 /* Single-precision comparisons. */
235 /* Define a function NAME that loads two single-precision values,
236 performs floating point comparison OPCODE, and returns TRUE or
237 FALSE depending on the result. */
239 #define CMPSF(NAME, OPCODE, TRUE, FALSE) \
251 /* Like CMPSF, but reverse the comparison operands. */
253 #define REVCMPSF(NAME, OPCODE, TRUE, FALSE) \
266 CMPSF (__mips16_eqsf2, c.eq.s, 0, 1)
269 CMPSF (__mips16_nesf2, c.eq.s, 0, 1)
272 REVCMPSF (__mips16_gtsf2, c.lt.s, 1, 0)
275 REVCMPSF (__mips16_gesf2, c.le.s, 0, -1)
278 CMPSF (__mips16_lesf2, c.le.s, 0, 1)
281 CMPSF (__mips16_ltsf2, c.lt.s, -1, 0)
284 CMPSF(__mips16_unordsf2, c.un.s, 1, 0)
288 /* Single-precision conversions. */
291 STARTFN (__mips16_floatsisf)
295 ENDFN (__mips16_floatsisf)
298 #ifdef L_m16fltunsisf
299 STARTFN (__mips16_floatunsisf)
314 ENDFN (__mips16_floatunsisf)
317 #ifdef L_m16fix_truncsfsi
318 STARTFN (__mips16_fix_truncsfsi)
320 trunc.w.s RET,ARG1,$4
322 ENDFN (__mips16_fix_truncsfsi)
325 #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
327 /* Double-precision math. */
329 /* Define a function NAME that loads two double-precision values,
330 performs FPU operation OPCODE on them, and returns the double-
333 #define OPDF3(NAME, OPCODE) \
337 OPCODE RET,ARG1,ARG2; \
338 MOVE_DF_RET (f, $31); \
342 OPDF3 (__mips16_adddf3, add.d)
345 OPDF3 (__mips16_subdf3, sub.d)
348 OPDF3 (__mips16_muldf3, mul.d)
351 OPDF3 (__mips16_divdf3, div.d)
354 /* Define a function NAME that loads a double-precision value,
355 performs FPU operation OPCODE on it, and returns the double-
358 #define OPDF2(NAME, OPCODE) \
362 MOVE_DF_RET (f, $31); \
366 OPDF2 (__mips16_negdf2, neg.d)
369 OPDF2 (__mips16_absdf2, abs.d)
372 /* Conversions between single and double precision. */
375 STARTFN (__mips16_extendsfdf2)
379 ENDFN (__mips16_extendsfdf2)
383 STARTFN (__mips16_truncdfsf2)
387 ENDFN (__mips16_truncdfsf2)
390 /* Double-precision comparisons. */
392 /* Define a function NAME that loads two double-precision values,
393 performs floating point comparison OPCODE, and returns TRUE or
394 FALSE depending on the result. */
396 #define CMPDF(NAME, OPCODE, TRUE, FALSE) \
408 /* Like CMPDF, but reverse the comparison operands. */
410 #define REVCMPDF(NAME, OPCODE, TRUE, FALSE) \
423 CMPDF (__mips16_eqdf2, c.eq.d, 0, 1)
426 CMPDF (__mips16_nedf2, c.eq.d, 0, 1)
429 REVCMPDF (__mips16_gtdf2, c.lt.d, 1, 0)
432 REVCMPDF (__mips16_gedf2, c.le.d, 0, -1)
435 CMPDF (__mips16_ledf2, c.le.d, 0, 1)
438 CMPDF (__mips16_ltdf2, c.lt.d, -1, 0)
441 CMPDF(__mips16_unorddf2, c.un.d, 1, 0)
444 /* Double-precision conversions. */
447 STARTFN (__mips16_floatsidf)
451 ENDFN (__mips16_floatsidf)
454 #ifdef L_m16fltunsidf
455 STARTFN (__mips16_floatunsidf)
459 li.d ARG1, 4.294967296e+9
461 1: MOVE_DF_RET (f, $31)
462 ENDFN (__mips16_floatunsidf)
465 #ifdef L_m16fix_truncdfsi
466 STARTFN (__mips16_fix_truncdfsi)
468 trunc.w.d RET,ARG1,$4
470 ENDFN (__mips16_fix_truncdfsi)
472 #endif /* !__mips_single_float */
474 /* Define a function NAME that moves a return value of mode MODE from
477 #define RET_FUNCTION(NAME, MODE) \
479 MOVE_##MODE##_RET (t, $31); \
483 RET_FUNCTION (__mips16_ret_sf, SF)
487 RET_FUNCTION (__mips16_ret_sc, SC)
490 #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
492 RET_FUNCTION (__mips16_ret_df, DF)
496 RET_FUNCTION (__mips16_ret_dc, DC)
498 #endif /* !__mips_single_float */
500 /* STUB_ARGS_X copies the arguments from GPRs to FPRs for argument
501 code X. X is calculated as ARG1 + ARG2 * 4, where ARG1 and ARG2
502 classify the first and second arguments as follows:
504 1: a single-precision argument
505 2: a double-precision argument
506 0: no argument, or not one of the above. */
508 #define STUB_ARGS_0 /* () */
509 #define STUB_ARGS_1 MOVE_SF_BYTE0 (t) /* (sf) */
510 #define STUB_ARGS_5 MOVE_SF_BYTE0 (t); MOVE_SF_BYTE4 (t) /* (sf, sf) */
511 #define STUB_ARGS_9 MOVE_SF_BYTE0 (t); MOVE_DF_BYTE8 (t) /* (sf, df) */
512 #define STUB_ARGS_2 MOVE_DF_BYTE0 (t) /* (df) */
513 #define STUB_ARGS_6 MOVE_DF_BYTE0 (t); MOVE_SF_BYTE8 (t) /* (df, sf) */
514 #define STUB_ARGS_10 MOVE_DF_BYTE0 (t); MOVE_DF_BYTE8 (t) /* (df, df) */
516 /* These functions are used by 16-bit code when calling via a function
517 pointer. They must copy the floating point arguments from the GPRs
518 to FPRs and then call function $2. */
520 #define CALL_STUB_NO_RET(NAME, CODE) \
530 CALL_STUB_NO_RET (__mips16_call_stub_1, 1)
534 CALL_STUB_NO_RET (__mips16_call_stub_5, 5)
537 #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
540 CALL_STUB_NO_RET (__mips16_call_stub_2, 2)
544 CALL_STUB_NO_RET (__mips16_call_stub_6, 6)
548 CALL_STUB_NO_RET (__mips16_call_stub_9, 9)
552 CALL_STUB_NO_RET (__mips16_call_stub_10, 10)
554 #endif /* !__mips_single_float */
556 /* Now we have the same set of functions, except that this time the
557 function being called returns an SFmode, SCmode, DFmode or DCmode
558 value; we need to instantiate a set for each case. The calling
559 function will arrange to preserve $18, so these functions are free
560 to use it to hold the return address.
562 Note that we do not know whether the function we are calling is 16
563 bit or 32 bit. However, it does not matter, because 16-bit
564 functions always return floating point values in both the gp and
565 the fp regs. It would be possible to check whether the function
566 being called is 16 bits, in which case the copy is unnecessary;
567 however, it's faster to always do the copy. */
569 #define CALL_STUB_RET(NAME, CODE, MODE) \
577 MOVE_##MODE##_RET (f, $18); \
580 /* First, instantiate the single-float set. */
583 CALL_STUB_RET (__mips16_call_stub_sf_0, 0, SF)
587 CALL_STUB_RET (__mips16_call_stub_sf_1, 1, SF)
591 CALL_STUB_RET (__mips16_call_stub_sf_5, 5, SF)
594 #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
596 CALL_STUB_RET (__mips16_call_stub_sf_2, 2, SF)
600 CALL_STUB_RET (__mips16_call_stub_sf_6, 6, SF)
604 CALL_STUB_RET (__mips16_call_stub_sf_9, 9, SF)
608 CALL_STUB_RET (__mips16_call_stub_sf_10, 10, SF)
610 #endif /* !__mips_single_float */
613 /* Now we have the same set of functions again, except that this time
614 the function being called returns an DFmode value. */
616 #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
618 CALL_STUB_RET (__mips16_call_stub_df_0, 0, DF)
622 CALL_STUB_RET (__mips16_call_stub_df_1, 1, DF)
626 CALL_STUB_RET (__mips16_call_stub_df_5, 5, DF)
630 CALL_STUB_RET (__mips16_call_stub_df_2, 2, DF)
634 CALL_STUB_RET (__mips16_call_stub_df_6, 6, DF)
638 CALL_STUB_RET (__mips16_call_stub_df_9, 9, DF)
642 CALL_STUB_RET (__mips16_call_stub_df_10, 10, DF)
644 #endif /* !__mips_single_float */
647 /* Ho hum. Here we have the same set of functions again, this time
648 for when the function being called returns an SCmode value. */
651 CALL_STUB_RET (__mips16_call_stub_sc_0, 0, SC)
655 CALL_STUB_RET (__mips16_call_stub_sc_1, 1, SC)
659 CALL_STUB_RET (__mips16_call_stub_sc_5, 5, SC)
662 #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
664 CALL_STUB_RET (__mips16_call_stub_sc_2, 2, SC)
668 CALL_STUB_RET (__mips16_call_stub_sc_6, 6, SC)
672 CALL_STUB_RET (__mips16_call_stub_sc_9, 9, SC)
676 CALL_STUB_RET (__mips16_call_stub_sc_10, 10, SC)
678 #endif /* !__mips_single_float */
681 /* Finally, another set of functions for DCmode. */
683 #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
685 CALL_STUB_RET (__mips16_call_stub_dc_0, 0, DC)
689 CALL_STUB_RET (__mips16_call_stub_dc_1, 1, DC)
693 CALL_STUB_RET (__mips16_call_stub_dc_5, 5, DC)
697 CALL_STUB_RET (__mips16_call_stub_dc_2, 2, DC)
701 CALL_STUB_RET (__mips16_call_stub_dc_6, 6, DC)
705 CALL_STUB_RET (__mips16_call_stub_dc_9, 9, DC)
709 CALL_STUB_RET (__mips16_call_stub_dc_10, 10, DC)
711 #endif /* !__mips_single_float */