1 /* mips16 floating point support code
2 Copyright (C) 1996-2014 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 #if defined(__mips_micromips) || defined(__mips_soft_float)
25 /* Do nothing because this code is only needed when linking
26 against mips16 hard-float objects. Neither micromips code
27 nor soft-float code can be linked against mips16 hard-float
28 objects so we do not need these routines when building libgcc
32 /* This file contains mips16 floating point support functions. These
33 functions are called by mips16 code to handle floating point when
34 -msoft-float is not used. They accept the arguments and return
35 values using the soft-float calling convention, but do the actual
36 operation using the hard floating point instructions. */
38 #if defined _MIPS_SIM && (_MIPS_SIM == _ABIO32 || _MIPS_SIM == _ABIO64)
40 /* This file contains 32-bit assembly code. */
43 /* Start a function. */
45 #define STARTFN(NAME) .globl NAME; .ent NAME; NAME:
47 /* Finish a function. */
49 #define ENDFN(NAME) .end NAME
52 The FPR that holds the first floating-point argument.
55 The FPR that holds the second floating-point argument.
58 The FPR that holds a floating-point return value. */
68 /* Set 64-bit register GPR so that its high 32 bits contain HIGH_FPR
69 and so that its low 32 bits contain LOW_FPR. */
70 #define MERGE_GPRf(GPR, HIGH_FPR, LOW_FPR) \
80 /* Move the high 32 bits of GPR to HIGH_FPR and the low 32 bits of
82 #define MERGE_GPRt(GPR, HIGH_FPR, LOW_FPR) \
89 /* Jump to T, and use "OPCODE, OP2" to implement a delayed move. */
90 #define DELAYt(T, OPCODE, OP2) \
97 /* Coprocessor moves are interlocked from the MIPS IV ISA up. */
98 #define DELAYf(T, OPCODE, OP2) DELAYt (T, OPCODE, OP2)
100 /* Use "OPCODE. OP2" and jump to T. */
101 #define DELAYf(T, OPCODE, OP2) OPCODE, OP2; jr T
105 Move the first single-precision floating-point argument between
109 Likewise the first single-precision integer argument.
112 Move the second single-precision floating-point argument between
113 GPRs and FPRs, given that the first argument occupies 4 bytes.
116 Move the second single-precision floating-point argument between
117 GPRs and FPRs, given that the first argument occupies 8 bytes.
120 Move the first double-precision floating-point argument between
124 Likewise the second double-precision floating-point argument.
127 Likewise a single-precision floating-point return value,
131 Likewise a complex single-precision floating-point return value.
134 Likewise a double-precision floating-point return value.
137 Likewise a complex double-precision floating-point return value.
140 Likewise a single-precision integer return value.
142 The D argument is "t" to move to FPRs and "f" to move from FPRs.
143 The return macros may assume that the target of the jump does not
144 use a floating-point register. */
146 #define MOVE_SF_RET(D, T) DELAY##D (T, m##D##c1 $2,$f0)
147 #define MOVE_SI_RET(D, T) DELAY##D (T, m##D##c1 $2,$f0)
149 #if defined(__mips64) && defined(__MIPSEB__)
150 #define MOVE_SC_RET(D, T) MERGE_GPR##D ($2, $f0, $f1); jr T
151 #elif defined(__mips64)
152 /* The high 32 bits of $2 correspond to the second word in memory;
153 i.e. the imaginary part. */
154 #define MOVE_SC_RET(D, T) MERGE_GPR##D ($2, $f1, $f0); jr T
155 #elif __mips_fpr == 64
156 #define MOVE_SC_RET(D, T) m##D##c1 $2,$f0; DELAY##D (T, m##D##c1 $3,$f1)
158 #define MOVE_SC_RET(D, T) m##D##c1 $2,$f0; DELAY##D (T, m##D##c1 $3,$f2)
161 #if defined(__mips64)
162 #define MOVE_SF_BYTE0(D) m##D##c1 $4,$f12
163 #define MOVE_SF_BYTE4(D) m##D##c1 $5,$f13
164 #define MOVE_SF_BYTE8(D) m##D##c1 $5,$f13
166 #define MOVE_SF_BYTE0(D) m##D##c1 $4,$f12
167 #define MOVE_SF_BYTE4(D) m##D##c1 $5,$f14
168 #define MOVE_SF_BYTE8(D) m##D##c1 $6,$f14
170 #define MOVE_SI_BYTE0(D) MOVE_SF_BYTE0(D)
172 #if defined(__mips64)
173 #define MOVE_DF_BYTE0(D) dm##D##c1 $4,$f12
174 #define MOVE_DF_BYTE8(D) dm##D##c1 $5,$f13
175 #define MOVE_DF_RET(D, T) DELAY##D (T, dm##D##c1 $2,$f0)
176 #define MOVE_DC_RET(D, T) dm##D##c1 $3,$f1; MOVE_DF_RET (D, T)
177 #elif __mips_fpr == 64 && defined(__MIPSEB__)
178 #define MOVE_DF_BYTE0(D) m##D##c1 $5,$f12; m##D##hc1 $4,$f12
179 #define MOVE_DF_BYTE8(D) m##D##c1 $7,$f14; m##D##hc1 $6,$f14
180 #define MOVE_DF_RET(D, T) m##D##c1 $3,$f0; DELAY##D (T, m##D##hc1 $2,$f0)
181 #define MOVE_DC_RET(D, T) m##D##c1 $5,$f1; m##D##hc1 $4,$f1; MOVE_DF_RET (D, T)
182 #elif __mips_fpr == 64
183 #define MOVE_DF_BYTE0(D) m##D##c1 $4,$f12; m##D##hc1 $5,$f12
184 #define MOVE_DF_BYTE8(D) m##D##c1 $6,$f14; m##D##hc1 $7,$f14
185 #define MOVE_DF_RET(D, T) m##D##c1 $2,$f0; DELAY##D (T, m##D##hc1 $3,$f0)
186 #define MOVE_DC_RET(D, T) m##D##c1 $4,$f1; m##D##hc1 $5,$f1; MOVE_DF_RET (D, T)
187 #elif defined(__MIPSEB__)
188 /* FPRs are little-endian. */
189 #define MOVE_DF_BYTE0(D) m##D##c1 $4,$f13; m##D##c1 $5,$f12
190 #define MOVE_DF_BYTE8(D) m##D##c1 $6,$f15; m##D##c1 $7,$f14
191 #define MOVE_DF_RET(D, T) m##D##c1 $2,$f1; DELAY##D (T, m##D##c1 $3,$f0)
192 #define MOVE_DC_RET(D, T) m##D##c1 $4,$f3; m##D##c1 $5,$f2; MOVE_DF_RET (D, T)
194 #define MOVE_DF_BYTE0(D) m##D##c1 $4,$f12; m##D##c1 $5,$f13
195 #define MOVE_DF_BYTE8(D) m##D##c1 $6,$f14; m##D##c1 $7,$f15
196 #define MOVE_DF_RET(D, T) m##D##c1 $2,$f0; DELAY##D (T, m##D##c1 $3,$f1)
197 #define MOVE_DC_RET(D, T) m##D##c1 $4,$f2; m##D##c1 $5,$f3; MOVE_DF_RET (D, T)
200 /* Single-precision math. */
202 /* Define a function NAME that loads two single-precision values,
203 performs FPU operation OPCODE on them, and returns the single-
206 #define OPSF3(NAME, OPCODE) \
210 OPCODE RET,ARG1,ARG2; \
211 MOVE_SF_RET (f, $31); \
215 OPSF3 (__mips16_addsf3, add.s)
218 OPSF3 (__mips16_subsf3, sub.s)
221 OPSF3 (__mips16_mulsf3, mul.s)
224 OPSF3 (__mips16_divsf3, div.s)
227 /* Define a function NAME that loads a single-precision value,
228 performs FPU operation OPCODE on it, and returns the single-
231 #define OPSF2(NAME, OPCODE) \
235 MOVE_SF_RET (f, $31); \
239 OPSF2 (__mips16_negsf2, neg.s)
242 OPSF2 (__mips16_abssf2, abs.s)
245 /* Single-precision comparisons. */
247 /* Define a function NAME that loads two single-precision values,
248 performs floating point comparison OPCODE, and returns TRUE or
249 FALSE depending on the result. */
251 #define CMPSF(NAME, OPCODE, TRUE, FALSE) \
263 /* Like CMPSF, but reverse the comparison operands. */
265 #define REVCMPSF(NAME, OPCODE, TRUE, FALSE) \
278 CMPSF (__mips16_eqsf2, c.eq.s, 0, 1)
281 CMPSF (__mips16_nesf2, c.eq.s, 0, 1)
284 REVCMPSF (__mips16_gtsf2, c.lt.s, 1, 0)
287 REVCMPSF (__mips16_gesf2, c.le.s, 0, -1)
290 CMPSF (__mips16_lesf2, c.le.s, 0, 1)
293 CMPSF (__mips16_ltsf2, c.lt.s, -1, 0)
296 CMPSF(__mips16_unordsf2, c.un.s, 1, 0)
300 /* Single-precision conversions. */
303 STARTFN (__mips16_floatsisf)
307 ENDFN (__mips16_floatsisf)
310 #ifdef L_m16fltunsisf
311 STARTFN (__mips16_floatunsisf)
326 ENDFN (__mips16_floatunsisf)
329 #ifdef L_m16fix_truncsfsi
330 STARTFN (__mips16_fix_truncsfsi)
332 trunc.w.s RET,ARG1,$4
334 ENDFN (__mips16_fix_truncsfsi)
337 #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
339 /* Double-precision math. */
341 /* Define a function NAME that loads two double-precision values,
342 performs FPU operation OPCODE on them, and returns the double-
345 #define OPDF3(NAME, OPCODE) \
349 OPCODE RET,ARG1,ARG2; \
350 MOVE_DF_RET (f, $31); \
354 OPDF3 (__mips16_adddf3, add.d)
357 OPDF3 (__mips16_subdf3, sub.d)
360 OPDF3 (__mips16_muldf3, mul.d)
363 OPDF3 (__mips16_divdf3, div.d)
366 /* Define a function NAME that loads a double-precision value,
367 performs FPU operation OPCODE on it, and returns the double-
370 #define OPDF2(NAME, OPCODE) \
374 MOVE_DF_RET (f, $31); \
378 OPDF2 (__mips16_negdf2, neg.d)
381 OPDF2 (__mips16_absdf2, abs.d)
384 /* Conversions between single and double precision. */
387 STARTFN (__mips16_extendsfdf2)
391 ENDFN (__mips16_extendsfdf2)
395 STARTFN (__mips16_truncdfsf2)
399 ENDFN (__mips16_truncdfsf2)
402 /* Double-precision comparisons. */
404 /* Define a function NAME that loads two double-precision values,
405 performs floating point comparison OPCODE, and returns TRUE or
406 FALSE depending on the result. */
408 #define CMPDF(NAME, OPCODE, TRUE, FALSE) \
420 /* Like CMPDF, but reverse the comparison operands. */
422 #define REVCMPDF(NAME, OPCODE, TRUE, FALSE) \
435 CMPDF (__mips16_eqdf2, c.eq.d, 0, 1)
438 CMPDF (__mips16_nedf2, c.eq.d, 0, 1)
441 REVCMPDF (__mips16_gtdf2, c.lt.d, 1, 0)
444 REVCMPDF (__mips16_gedf2, c.le.d, 0, -1)
447 CMPDF (__mips16_ledf2, c.le.d, 0, 1)
450 CMPDF (__mips16_ltdf2, c.lt.d, -1, 0)
453 CMPDF(__mips16_unorddf2, c.un.d, 1, 0)
456 /* Double-precision conversions. */
459 STARTFN (__mips16_floatsidf)
463 ENDFN (__mips16_floatsidf)
466 #ifdef L_m16fltunsidf
467 STARTFN (__mips16_floatunsidf)
471 li.d ARG1, 4.294967296e+9
473 1: MOVE_DF_RET (f, $31)
474 ENDFN (__mips16_floatunsidf)
477 #ifdef L_m16fix_truncdfsi
478 STARTFN (__mips16_fix_truncdfsi)
480 trunc.w.d RET,ARG1,$4
482 ENDFN (__mips16_fix_truncdfsi)
484 #endif /* !__mips_single_float */
486 /* We don't export stubs from libgcc_s.so and always require static
487 versions to be pulled from libgcc.a as needed because they use $2
488 and possibly $3 as arguments, diverging from the standard SysV ABI,
489 and as such would require severe pessimisation of MIPS16 PLT entries
490 just for this single special case.
492 For compatibility with old binaries that used safe standard MIPS PLT
493 entries and referred to these functions we still export them at
494 version GCC_4.4.0 for run-time loading only. */
497 #define CE_STARTFN(NAME) \
498 STARTFN (NAME##_compat); \
499 .symver NAME##_compat, NAME@GCC_4.4.0
500 #define CE_ENDFN(NAME) ENDFN (NAME##_compat)
502 #define CE_STARTFN(NAME) \
505 #define CE_ENDFN(NAME) ENDFN (NAME)
508 /* Define a function NAME that moves a return value of mode MODE from
511 #define RET_FUNCTION(NAME, MODE) \
513 MOVE_##MODE##_RET (t, $31); \
517 RET_FUNCTION (__mips16_ret_sf, SF)
521 RET_FUNCTION (__mips16_ret_sc, SC)
524 #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
526 RET_FUNCTION (__mips16_ret_df, DF)
530 RET_FUNCTION (__mips16_ret_dc, DC)
532 #endif /* !__mips_single_float */
534 /* STUB_ARGS_X copies the arguments from GPRs to FPRs for argument
535 code X. X is calculated as ARG1 + ARG2 * 4, where ARG1 and ARG2
536 classify the first and second arguments as follows:
538 1: a single-precision argument
539 2: a double-precision argument
540 0: no argument, or not one of the above. */
542 #define STUB_ARGS_0 /* () */
543 #define STUB_ARGS_1 MOVE_SF_BYTE0 (t) /* (sf) */
544 #define STUB_ARGS_5 MOVE_SF_BYTE0 (t); MOVE_SF_BYTE4 (t) /* (sf, sf) */
545 #define STUB_ARGS_9 MOVE_SF_BYTE0 (t); MOVE_DF_BYTE8 (t) /* (sf, df) */
546 #define STUB_ARGS_2 MOVE_DF_BYTE0 (t) /* (df) */
547 #define STUB_ARGS_6 MOVE_DF_BYTE0 (t); MOVE_SF_BYTE8 (t) /* (df, sf) */
548 #define STUB_ARGS_10 MOVE_DF_BYTE0 (t); MOVE_DF_BYTE8 (t) /* (df, df) */
550 /* These functions are used by 16-bit code when calling via a function
551 pointer. They must copy the floating point arguments from the GPRs
552 to FPRs and then call function $2. */
554 #define CALL_STUB_NO_RET(NAME, CODE) \
564 CALL_STUB_NO_RET (__mips16_call_stub_1, 1)
568 CALL_STUB_NO_RET (__mips16_call_stub_5, 5)
571 #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
574 CALL_STUB_NO_RET (__mips16_call_stub_2, 2)
578 CALL_STUB_NO_RET (__mips16_call_stub_6, 6)
582 CALL_STUB_NO_RET (__mips16_call_stub_9, 9)
586 CALL_STUB_NO_RET (__mips16_call_stub_10, 10)
588 #endif /* !__mips_single_float */
590 /* Now we have the same set of functions, except that this time the
591 function being called returns an SFmode, SCmode, DFmode or DCmode
592 value; we need to instantiate a set for each case. The calling
593 function will arrange to preserve $18, so these functions are free
594 to use it to hold the return address.
596 Note that we do not know whether the function we are calling is 16
597 bit or 32 bit. However, it does not matter, because 16-bit
598 functions always return floating point values in both the gp and
599 the fp regs. It would be possible to check whether the function
600 being called is 16 bits, in which case the copy is unnecessary;
601 however, it's faster to always do the copy. */
603 #define CALL_STUB_RET(NAME, CODE, MODE) \
606 /* Create a fake CFA 4 bytes below the stack pointer. */ \
607 .cfi_def_cfa 29,-4; \
608 /* "Save" $sp in itself so we don't use the fake CFA. \
609 This is: DW_CFA_val_expression r29, { DW_OP_reg29 }. */ \
610 .cfi_escape 0x16,29,1,0x6d; \
612 .cfi_register 31,18; \
618 MOVE_##MODE##_RET (f, $18); \
622 /* First, instantiate the single-float set. */
625 CALL_STUB_RET (__mips16_call_stub_sf_0, 0, SF)
629 CALL_STUB_RET (__mips16_call_stub_sf_1, 1, SF)
633 CALL_STUB_RET (__mips16_call_stub_sf_5, 5, SF)
636 #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
638 CALL_STUB_RET (__mips16_call_stub_sf_2, 2, SF)
642 CALL_STUB_RET (__mips16_call_stub_sf_6, 6, SF)
646 CALL_STUB_RET (__mips16_call_stub_sf_9, 9, SF)
650 CALL_STUB_RET (__mips16_call_stub_sf_10, 10, SF)
652 #endif /* !__mips_single_float */
655 /* Now we have the same set of functions again, except that this time
656 the function being called returns an DFmode value. */
658 #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
660 CALL_STUB_RET (__mips16_call_stub_df_0, 0, DF)
664 CALL_STUB_RET (__mips16_call_stub_df_1, 1, DF)
668 CALL_STUB_RET (__mips16_call_stub_df_5, 5, DF)
672 CALL_STUB_RET (__mips16_call_stub_df_2, 2, DF)
676 CALL_STUB_RET (__mips16_call_stub_df_6, 6, DF)
680 CALL_STUB_RET (__mips16_call_stub_df_9, 9, DF)
684 CALL_STUB_RET (__mips16_call_stub_df_10, 10, DF)
686 #endif /* !__mips_single_float */
689 /* Ho hum. Here we have the same set of functions again, this time
690 for when the function being called returns an SCmode value. */
693 CALL_STUB_RET (__mips16_call_stub_sc_0, 0, SC)
697 CALL_STUB_RET (__mips16_call_stub_sc_1, 1, SC)
701 CALL_STUB_RET (__mips16_call_stub_sc_5, 5, SC)
704 #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
706 CALL_STUB_RET (__mips16_call_stub_sc_2, 2, SC)
710 CALL_STUB_RET (__mips16_call_stub_sc_6, 6, SC)
714 CALL_STUB_RET (__mips16_call_stub_sc_9, 9, SC)
718 CALL_STUB_RET (__mips16_call_stub_sc_10, 10, SC)
720 #endif /* !__mips_single_float */
723 /* Finally, another set of functions for DCmode. */
725 #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
727 CALL_STUB_RET (__mips16_call_stub_dc_0, 0, DC)
731 CALL_STUB_RET (__mips16_call_stub_dc_1, 1, DC)
735 CALL_STUB_RET (__mips16_call_stub_dc_5, 5, DC)
739 CALL_STUB_RET (__mips16_call_stub_dc_2, 2, DC)
743 CALL_STUB_RET (__mips16_call_stub_dc_6, 6, DC)
747 CALL_STUB_RET (__mips16_call_stub_dc_9, 9, DC)
751 CALL_STUB_RET (__mips16_call_stub_dc_10, 10, DC)
753 #endif /* !__mips_single_float */
756 #endif /* defined(__mips_micromips) || defined(__mips_soft_float) */