1 /* mips16 floating point support code
2 Copyright (C) 1996-2013 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 #ifdef __mips_micromips
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. */
34 #if defined _MIPS_SIM && (_MIPS_SIM == _ABIO32 || _MIPS_SIM == _ABIO64)
36 /* This file contains 32-bit assembly code. */
39 /* Start a function. */
41 #define STARTFN(NAME) .globl NAME; .ent NAME; NAME:
43 /* Finish a function. */
45 #define ENDFN(NAME) .end NAME
48 The FPR that holds the first floating-point argument.
51 The FPR that holds the second floating-point argument.
54 The FPR that holds a floating-point return value. */
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) \
76 /* Move the high 32 bits of GPR to HIGH_FPR and the low 32 bits of
78 #define MERGE_GPRt(GPR, HIGH_FPR, LOW_FPR) \
85 /* Jump to T, and use "OPCODE, OP2" to implement a delayed move. */
86 #define DELAYt(T, OPCODE, OP2) \
92 /* Use "OPCODE. OP2" and jump to T. */
93 #define DELAYf(T, OPCODE, OP2) OPCODE, OP2; jr T
96 Move the first single-precision floating-point argument between
100 Likewise the first single-precision integer argument.
103 Move the second single-precision floating-point argument between
104 GPRs and FPRs, given that the first argument occupies 4 bytes.
107 Move the second single-precision floating-point argument between
108 GPRs and FPRs, given that the first argument occupies 8 bytes.
111 Move the first double-precision floating-point argument between
115 Likewise the second double-precision floating-point argument.
118 Likewise a single-precision floating-point return value,
122 Likewise a complex single-precision floating-point return value.
125 Likewise a double-precision floating-point return value.
128 Likewise a complex double-precision floating-point return value.
131 Likewise a single-precision integer return value.
133 The D argument is "t" to move to FPRs and "f" to move from FPRs.
134 The return macros may assume that the target of the jump does not
135 use a floating-point register. */
137 #define MOVE_SF_RET(D, T) DELAY##D (T, m##D##c1 $2,$f0)
138 #define MOVE_SI_RET(D, T) DELAY##D (T, m##D##c1 $2,$f0)
140 #if defined(__mips64) && defined(__MIPSEB__)
141 #define MOVE_SC_RET(D, T) MERGE_GPR##D ($2, $f0, $f1); jr T
142 #elif defined(__mips64)
143 /* The high 32 bits of $2 correspond to the second word in memory;
144 i.e. the imaginary part. */
145 #define MOVE_SC_RET(D, T) MERGE_GPR##D ($2, $f1, $f0); jr T
146 #elif __mips_fpr == 64
147 #define MOVE_SC_RET(D, T) m##D##c1 $2,$f0; DELAY##D (T, m##D##c1 $3,$f1)
149 #define MOVE_SC_RET(D, T) m##D##c1 $2,$f0; DELAY##D (T, m##D##c1 $3,$f2)
152 #if defined(__mips64)
153 #define MOVE_SF_BYTE0(D) m##D##c1 $4,$f12
154 #define MOVE_SF_BYTE4(D) m##D##c1 $5,$f13
155 #define MOVE_SF_BYTE8(D) m##D##c1 $5,$f13
157 #define MOVE_SF_BYTE0(D) m##D##c1 $4,$f12
158 #define MOVE_SF_BYTE4(D) m##D##c1 $5,$f14
159 #define MOVE_SF_BYTE8(D) m##D##c1 $6,$f14
161 #define MOVE_SI_BYTE0(D) MOVE_SF_BYTE0(D)
163 #if defined(__mips64)
164 #define MOVE_DF_BYTE0(D) dm##D##c1 $4,$f12
165 #define MOVE_DF_BYTE8(D) dm##D##c1 $5,$f13
166 #define MOVE_DF_RET(D, T) DELAY##D (T, dm##D##c1 $2,$f0)
167 #define MOVE_DC_RET(D, T) dm##D##c1 $3,$f1; MOVE_DF_RET (D, T)
168 #elif __mips_fpr == 64 && defined(__MIPSEB__)
169 #define MOVE_DF_BYTE0(D) m##D##c1 $5,$f12; m##D##hc1 $4,$f12
170 #define MOVE_DF_BYTE8(D) m##D##c1 $7,$f14; m##D##hc1 $6,$f14
171 #define MOVE_DF_RET(D, T) m##D##c1 $3,$f0; DELAY##D (T, m##D##hc1 $2,$f0)
172 #define MOVE_DC_RET(D, T) m##D##c1 $5,$f1; m##D##hc1 $4,$f1; MOVE_DF_RET (D, T)
173 #elif __mips_fpr == 64
174 #define MOVE_DF_BYTE0(D) m##D##c1 $4,$f12; m##D##hc1 $5,$f12
175 #define MOVE_DF_BYTE8(D) m##D##c1 $6,$f14; m##D##hc1 $7,$f14
176 #define MOVE_DF_RET(D, T) m##D##c1 $2,$f0; DELAY##D (T, m##D##hc1 $3,$f0)
177 #define MOVE_DC_RET(D, T) m##D##c1 $4,$f1; m##D##hc1 $5,$f1; MOVE_DF_RET (D, T)
178 #elif defined(__MIPSEB__)
179 /* FPRs are little-endian. */
180 #define MOVE_DF_BYTE0(D) m##D##c1 $4,$f13; m##D##c1 $5,$f12
181 #define MOVE_DF_BYTE8(D) m##D##c1 $6,$f15; m##D##c1 $7,$f14
182 #define MOVE_DF_RET(D, T) m##D##c1 $2,$f1; DELAY##D (T, m##D##c1 $3,$f0)
183 #define MOVE_DC_RET(D, T) m##D##c1 $4,$f3; m##D##c1 $5,$f2; MOVE_DF_RET (D, T)
185 #define MOVE_DF_BYTE0(D) m##D##c1 $4,$f12; m##D##c1 $5,$f13
186 #define MOVE_DF_BYTE8(D) m##D##c1 $6,$f14; m##D##c1 $7,$f15
187 #define MOVE_DF_RET(D, T) m##D##c1 $2,$f0; DELAY##D (T, m##D##c1 $3,$f1)
188 #define MOVE_DC_RET(D, T) m##D##c1 $4,$f2; m##D##c1 $5,$f3; MOVE_DF_RET (D, T)
191 /* Single-precision math. */
193 /* Define a function NAME that loads two single-precision values,
194 performs FPU operation OPCODE on them, and returns the single-
197 #define OPSF3(NAME, OPCODE) \
201 OPCODE RET,ARG1,ARG2; \
202 MOVE_SF_RET (f, $31); \
206 OPSF3 (__mips16_addsf3, add.s)
209 OPSF3 (__mips16_subsf3, sub.s)
212 OPSF3 (__mips16_mulsf3, mul.s)
215 OPSF3 (__mips16_divsf3, div.s)
218 /* Define a function NAME that loads a single-precision value,
219 performs FPU operation OPCODE on it, and returns the single-
222 #define OPSF2(NAME, OPCODE) \
226 MOVE_SF_RET (f, $31); \
230 OPSF2 (__mips16_negsf2, neg.s)
233 OPSF2 (__mips16_abssf2, abs.s)
236 /* Single-precision comparisons. */
238 /* Define a function NAME that loads two single-precision values,
239 performs floating point comparison OPCODE, and returns TRUE or
240 FALSE depending on the result. */
242 #define CMPSF(NAME, OPCODE, TRUE, FALSE) \
254 /* Like CMPSF, but reverse the comparison operands. */
256 #define REVCMPSF(NAME, OPCODE, TRUE, FALSE) \
269 CMPSF (__mips16_eqsf2, c.eq.s, 0, 1)
272 CMPSF (__mips16_nesf2, c.eq.s, 0, 1)
275 REVCMPSF (__mips16_gtsf2, c.lt.s, 1, 0)
278 REVCMPSF (__mips16_gesf2, c.le.s, 0, -1)
281 CMPSF (__mips16_lesf2, c.le.s, 0, 1)
284 CMPSF (__mips16_ltsf2, c.lt.s, -1, 0)
287 CMPSF(__mips16_unordsf2, c.un.s, 1, 0)
291 /* Single-precision conversions. */
294 STARTFN (__mips16_floatsisf)
298 ENDFN (__mips16_floatsisf)
301 #ifdef L_m16fltunsisf
302 STARTFN (__mips16_floatunsisf)
317 ENDFN (__mips16_floatunsisf)
320 #ifdef L_m16fix_truncsfsi
321 STARTFN (__mips16_fix_truncsfsi)
323 trunc.w.s RET,ARG1,$4
325 ENDFN (__mips16_fix_truncsfsi)
328 #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
330 /* Double-precision math. */
332 /* Define a function NAME that loads two double-precision values,
333 performs FPU operation OPCODE on them, and returns the double-
336 #define OPDF3(NAME, OPCODE) \
340 OPCODE RET,ARG1,ARG2; \
341 MOVE_DF_RET (f, $31); \
345 OPDF3 (__mips16_adddf3, add.d)
348 OPDF3 (__mips16_subdf3, sub.d)
351 OPDF3 (__mips16_muldf3, mul.d)
354 OPDF3 (__mips16_divdf3, div.d)
357 /* Define a function NAME that loads a double-precision value,
358 performs FPU operation OPCODE on it, and returns the double-
361 #define OPDF2(NAME, OPCODE) \
365 MOVE_DF_RET (f, $31); \
369 OPDF2 (__mips16_negdf2, neg.d)
372 OPDF2 (__mips16_absdf2, abs.d)
375 /* Conversions between single and double precision. */
378 STARTFN (__mips16_extendsfdf2)
382 ENDFN (__mips16_extendsfdf2)
386 STARTFN (__mips16_truncdfsf2)
390 ENDFN (__mips16_truncdfsf2)
393 /* Double-precision comparisons. */
395 /* Define a function NAME that loads two double-precision values,
396 performs floating point comparison OPCODE, and returns TRUE or
397 FALSE depending on the result. */
399 #define CMPDF(NAME, OPCODE, TRUE, FALSE) \
411 /* Like CMPDF, but reverse the comparison operands. */
413 #define REVCMPDF(NAME, OPCODE, TRUE, FALSE) \
426 CMPDF (__mips16_eqdf2, c.eq.d, 0, 1)
429 CMPDF (__mips16_nedf2, c.eq.d, 0, 1)
432 REVCMPDF (__mips16_gtdf2, c.lt.d, 1, 0)
435 REVCMPDF (__mips16_gedf2, c.le.d, 0, -1)
438 CMPDF (__mips16_ledf2, c.le.d, 0, 1)
441 CMPDF (__mips16_ltdf2, c.lt.d, -1, 0)
444 CMPDF(__mips16_unorddf2, c.un.d, 1, 0)
447 /* Double-precision conversions. */
450 STARTFN (__mips16_floatsidf)
454 ENDFN (__mips16_floatsidf)
457 #ifdef L_m16fltunsidf
458 STARTFN (__mips16_floatunsidf)
462 li.d ARG1, 4.294967296e+9
464 1: MOVE_DF_RET (f, $31)
465 ENDFN (__mips16_floatunsidf)
468 #ifdef L_m16fix_truncdfsi
469 STARTFN (__mips16_fix_truncdfsi)
471 trunc.w.d RET,ARG1,$4
473 ENDFN (__mips16_fix_truncdfsi)
475 #endif /* !__mips_single_float */
477 /* Define a function NAME that moves a return value of mode MODE from
480 #define RET_FUNCTION(NAME, MODE) \
482 MOVE_##MODE##_RET (t, $31); \
486 RET_FUNCTION (__mips16_ret_sf, SF)
490 RET_FUNCTION (__mips16_ret_sc, SC)
493 #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
495 RET_FUNCTION (__mips16_ret_df, DF)
499 RET_FUNCTION (__mips16_ret_dc, DC)
501 #endif /* !__mips_single_float */
503 /* STUB_ARGS_X copies the arguments from GPRs to FPRs for argument
504 code X. X is calculated as ARG1 + ARG2 * 4, where ARG1 and ARG2
505 classify the first and second arguments as follows:
507 1: a single-precision argument
508 2: a double-precision argument
509 0: no argument, or not one of the above. */
511 #define STUB_ARGS_0 /* () */
512 #define STUB_ARGS_1 MOVE_SF_BYTE0 (t) /* (sf) */
513 #define STUB_ARGS_5 MOVE_SF_BYTE0 (t); MOVE_SF_BYTE4 (t) /* (sf, sf) */
514 #define STUB_ARGS_9 MOVE_SF_BYTE0 (t); MOVE_DF_BYTE8 (t) /* (sf, df) */
515 #define STUB_ARGS_2 MOVE_DF_BYTE0 (t) /* (df) */
516 #define STUB_ARGS_6 MOVE_DF_BYTE0 (t); MOVE_SF_BYTE8 (t) /* (df, sf) */
517 #define STUB_ARGS_10 MOVE_DF_BYTE0 (t); MOVE_DF_BYTE8 (t) /* (df, df) */
519 /* These functions are used by 16-bit code when calling via a function
520 pointer. They must copy the floating point arguments from the GPRs
521 to FPRs and then call function $2. */
523 #define CALL_STUB_NO_RET(NAME, CODE) \
533 CALL_STUB_NO_RET (__mips16_call_stub_1, 1)
537 CALL_STUB_NO_RET (__mips16_call_stub_5, 5)
540 #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
543 CALL_STUB_NO_RET (__mips16_call_stub_2, 2)
547 CALL_STUB_NO_RET (__mips16_call_stub_6, 6)
551 CALL_STUB_NO_RET (__mips16_call_stub_9, 9)
555 CALL_STUB_NO_RET (__mips16_call_stub_10, 10)
557 #endif /* !__mips_single_float */
559 /* Now we have the same set of functions, except that this time the
560 function being called returns an SFmode, SCmode, DFmode or DCmode
561 value; we need to instantiate a set for each case. The calling
562 function will arrange to preserve $18, so these functions are free
563 to use it to hold the return address.
565 Note that we do not know whether the function we are calling is 16
566 bit or 32 bit. However, it does not matter, because 16-bit
567 functions always return floating point values in both the gp and
568 the fp regs. It would be possible to check whether the function
569 being called is 16 bits, in which case the copy is unnecessary;
570 however, it's faster to always do the copy. */
572 #define CALL_STUB_RET(NAME, CODE, MODE) \
575 /* Create a fake CFA 4 bytes below the stack pointer. */ \
576 .cfi_def_cfa 29,-4; \
577 /* "Save" $sp in itself so we don't use the fake CFA. \
578 This is: DW_CFA_val_expression r29, { DW_OP_reg29 }. */ \
579 .cfi_escape 0x16,29,1,0x6d; \
581 .cfi_register 31,18; \
587 MOVE_##MODE##_RET (f, $18); \
591 /* First, instantiate the single-float set. */
594 CALL_STUB_RET (__mips16_call_stub_sf_0, 0, SF)
598 CALL_STUB_RET (__mips16_call_stub_sf_1, 1, SF)
602 CALL_STUB_RET (__mips16_call_stub_sf_5, 5, SF)
605 #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
607 CALL_STUB_RET (__mips16_call_stub_sf_2, 2, SF)
611 CALL_STUB_RET (__mips16_call_stub_sf_6, 6, SF)
615 CALL_STUB_RET (__mips16_call_stub_sf_9, 9, SF)
619 CALL_STUB_RET (__mips16_call_stub_sf_10, 10, SF)
621 #endif /* !__mips_single_float */
624 /* Now we have the same set of functions again, except that this time
625 the function being called returns an DFmode value. */
627 #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
629 CALL_STUB_RET (__mips16_call_stub_df_0, 0, DF)
633 CALL_STUB_RET (__mips16_call_stub_df_1, 1, DF)
637 CALL_STUB_RET (__mips16_call_stub_df_5, 5, DF)
641 CALL_STUB_RET (__mips16_call_stub_df_2, 2, DF)
645 CALL_STUB_RET (__mips16_call_stub_df_6, 6, DF)
649 CALL_STUB_RET (__mips16_call_stub_df_9, 9, DF)
653 CALL_STUB_RET (__mips16_call_stub_df_10, 10, DF)
655 #endif /* !__mips_single_float */
658 /* Ho hum. Here we have the same set of functions again, this time
659 for when the function being called returns an SCmode value. */
662 CALL_STUB_RET (__mips16_call_stub_sc_0, 0, SC)
666 CALL_STUB_RET (__mips16_call_stub_sc_1, 1, SC)
670 CALL_STUB_RET (__mips16_call_stub_sc_5, 5, SC)
673 #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
675 CALL_STUB_RET (__mips16_call_stub_sc_2, 2, SC)
679 CALL_STUB_RET (__mips16_call_stub_sc_6, 6, SC)
683 CALL_STUB_RET (__mips16_call_stub_sc_9, 9, SC)
687 CALL_STUB_RET (__mips16_call_stub_sc_10, 10, SC)
689 #endif /* !__mips_single_float */
692 /* Finally, another set of functions for DCmode. */
694 #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
696 CALL_STUB_RET (__mips16_call_stub_dc_0, 0, DC)
700 CALL_STUB_RET (__mips16_call_stub_dc_1, 1, DC)
704 CALL_STUB_RET (__mips16_call_stub_dc_5, 5, DC)
708 CALL_STUB_RET (__mips16_call_stub_dc_2, 2, DC)
712 CALL_STUB_RET (__mips16_call_stub_dc_6, 6, DC)
716 CALL_STUB_RET (__mips16_call_stub_dc_9, 9, DC)
720 CALL_STUB_RET (__mips16_call_stub_dc_10, 10, DC)
722 #endif /* !__mips_single_float */
725 #endif /* __mips_micromips */