1 /* mips16 floating point support code
2 Copyright (C) 1996, 1997, 1998 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 2, or (at your option) any
10 In addition to the permissions in the GNU General Public License, the
11 Free Software Foundation gives you unlimited permission to link the
12 compiled version of this file with other programs, and to distribute
13 those programs without any restriction coming from the use of this
14 file. (The General Public License restrictions do apply in other
15 respects; for example, they cover modification of the file, and
16 distribution when not linked into another program.)
18 This file is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program; see the file COPYING. If not, write to
25 the Free Software Foundation, 51 Franklin Street, Fifth Floor,
26 Boston, MA 02110-1301, USA. */
28 /* As a special exception, if you link this library with other files,
29 some of which are compiled with GCC, to produce an executable,
30 this library does not by itself cause the resulting executable
31 to be covered by the GNU General Public License.
32 This exception does not however invalidate any other reasons why
33 the executable file might be covered by the GNU General Public License. */
35 /* This file contains mips16 floating point support functions. These
36 functions are called by mips16 code to handle floating point when
37 -msoft-float is not used. They accept the arguments and return
38 values using the soft-float calling convention, but do the actual
39 operation using the hard floating point instructions. */
41 /* This file contains 32-bit assembly code. */
44 /* Start a function. */
46 #define STARTFN(NAME) .globl NAME; .ent NAME; NAME:
48 /* Finish a function. */
50 #define ENDFN(NAME) .end NAME
53 The FPR that holds the first floating-point argument.
56 The FPR that holds the second floating-point argument.
59 The FPR that holds a floating-point return value. */
69 /* Set 64-bit register GPR so that its high 32 bits contain HIGH_FPR
70 and so that its low 32 bits contain LOW_FPR. */
71 #define MERGE_GPRf(GPR, HIGH_FPR, LOW_FPR) \
79 /* Move the high 32 bits of GPR to HIGH_FPR and the low 32 bits of
81 #define MERGE_GPRt(GPR, HIGH_FPR, LOW_FPR) \
88 /* Jump to T, and use "OPCODE, OP2" to implement a delayed move. */
89 #define DELAYt(T, OPCODE, OP2) \
95 /* Use "OPCODE. OP2" and jump to T. */
96 #define DELAYf(T, OPCODE, OP2) OPCODE, OP2; jr T
99 Move the first single-precision floating-point argument between
103 Likewise the first single-precision integer argument.
106 Move the second single-precision floating-point argument between
107 GPRs and FPRs, given that the first argument occupies 4 bytes.
110 Move the second single-precision floating-point argument between
111 GPRs and FPRs, given that the first argument occupies 8 bytes.
114 Move the first double-precision floating-point argument between
118 Likewise the second double-precision floating-point argument.
121 Likewise a single-precision floating-point return value,
125 Likewise a complex single-precision floating-point return value.
128 Likewise a double-precision floating-point return value.
131 Likewise a complex double-precision floating-point return value.
134 Likewise a single-precision integer return value.
136 The D argument is "t" to move to FPRs and "f" to move from FPRs.
137 The return macros may assume that the target of the jump does not
138 use a floating-point register. */
140 #define MOVE_SF_RET(D, T) DELAY##D (T, m##D##c1 $2,$f0)
141 #define MOVE_SI_RET(D, T) DELAY##D (T, m##D##c1 $2,$f0)
143 #if defined(__mips64) && defined(__MIPSEB__)
144 #define MOVE_SC_RET(D, T) MERGE_GPR##D ($2, $f0, $f1); jr T
145 #elif defined(__mips64)
146 /* The high 32 bits of $2 correspond to the second word in memory;
147 i.e. the imaginary part. */
148 #define MOVE_SC_RET(D, T) MERGE_GPR##D ($2, $f1, $f0); jr T
149 #elif __mips_fpr == 64
150 #define MOVE_SC_RET(D, T) m##D##c1 $2,$f0; DELAY##D (T, m##D##c1 $3,$f1)
152 #define MOVE_SC_RET(D, T) m##D##c1 $2,$f0; DELAY##D (T, m##D##c1 $3,$f2)
155 #if defined(__mips64)
156 #define MOVE_SF_BYTE0(D) m##D##c1 $4,$f12
157 #define MOVE_SF_BYTE4(D) m##D##c1 $5,$f13
158 #define MOVE_SF_BYTE8(D) m##D##c1 $5,$f13
160 #define MOVE_SF_BYTE0(D) m##D##c1 $4,$f12
161 #define MOVE_SF_BYTE4(D) m##D##c1 $5,$f14
162 #define MOVE_SF_BYTE8(D) m##D##c1 $6,$f14
164 #define MOVE_SI_BYTE0(D) MOVE_SF_BYTE0(D)
166 #if defined(__mips64)
167 #define MOVE_DF_BYTE0(D) dm##D##c1 $4,$f12
168 #define MOVE_DF_BYTE8(D) dm##D##c1 $5,$f13
169 #define MOVE_DF_RET(D, T) DELAY##D (T, dm##D##c1 $2,$f0)
170 #define MOVE_DC_RET(D, T) dm##D##c1 $3,$f1; MOVE_DF_RET (D, T)
171 #elif __mips_fpr == 64 && defined(__MIPSEB__)
172 #define MOVE_DF_BYTE0(D) m##D##c1 $5,$f12; m##D##hc1 $4,$f12
173 #define MOVE_DF_BYTE8(D) m##D##c1 $7,$f14; m##D##hc1 $6,$f14
174 #define MOVE_DF_RET(D, T) m##D##c1 $3,$f0; DELAY##D (T, m##D##hc1 $2,$f0)
175 #define MOVE_DC_RET(D, T) m##D##c1 $5,$f1; m##D##hc1 $4,$f1; MOVE_DF_RET (D, T)
176 #elif __mips_fpr == 64
177 #define MOVE_DF_BYTE0(D) m##D##c1 $4,$f12; m##D##hc1 $5,$f12
178 #define MOVE_DF_BYTE8(D) m##D##c1 $6,$f14; m##D##hc1 $7,$f14
179 #define MOVE_DF_RET(D, T) m##D##c1 $2,$f0; DELAY##D (T, m##D##hc1 $3,$f0)
180 #define MOVE_DC_RET(D, T) m##D##c1 $4,$f1; m##D##hc1 $5,$f1; MOVE_DF_RET (D, T)
181 #elif defined(__MIPSEB__)
182 /* FPRs are little-endian. */
183 #define MOVE_DF_BYTE0(D) m##D##c1 $4,$f13; m##D##c1 $5,$f12
184 #define MOVE_DF_BYTE8(D) m##D##c1 $6,$f15; m##D##c1 $7,$f14
185 #define MOVE_DF_RET(D, T) m##D##c1 $2,$f1; DELAY##D (T, m##D##c1 $3,$f0)
186 #define MOVE_DC_RET(D, T) m##D##c1 $4,$f3; m##D##c1 $5,$f2; MOVE_DF_RET (D, T)
188 #define MOVE_DF_BYTE0(D) m##D##c1 $4,$f12; m##D##c1 $5,$f13
189 #define MOVE_DF_BYTE8(D) m##D##c1 $6,$f14; m##D##c1 $7,$f15
190 #define MOVE_DF_RET(D, T) m##D##c1 $2,$f0; DELAY##D (T, m##D##c1 $3,$f1)
191 #define MOVE_DC_RET(D, T) m##D##c1 $4,$f2; m##D##c1 $5,$f3; MOVE_DF_RET (D, T)
194 /* Single-precision math. */
196 /* Define a function NAME that loads two single-precision values,
197 performs FPU operation OPCODE on them, and returns the single-
200 #define OPSF3(NAME, OPCODE) \
204 OPCODE RET,ARG1,ARG2; \
205 MOVE_SF_RET (f, $31); \
209 OPSF3 (__mips16_addsf3, add.s)
212 OPSF3 (__mips16_subsf3, sub.s)
215 OPSF3 (__mips16_mulsf3, mul.s)
218 OPSF3 (__mips16_divsf3, div.s)
221 /* Define a function NAME that loads a single-precision value,
222 performs FPU operation OPCODE on it, and returns the single-
225 #define OPSF2(NAME, OPCODE) \
229 MOVE_SF_RET (f, $31); \
233 OPSF2 (__mips16_negsf2, neg.s)
236 OPSF2 (__mips16_abssf2, abs.s)
239 /* Single-precision comparisons. */
241 /* Define a function NAME that loads two single-precision values,
242 performs floating point comparison OPCODE, and returns TRUE or
243 FALSE depending on the result. */
245 #define CMPSF(NAME, OPCODE, TRUE, FALSE) \
257 /* Like CMPSF, but reverse the comparison operands. */
259 #define REVCMPSF(NAME, OPCODE, TRUE, FALSE) \
272 CMPSF (__mips16_eqsf2, c.eq.s, 0, 1)
275 CMPSF (__mips16_nesf2, c.eq.s, 0, 1)
278 REVCMPSF (__mips16_gtsf2, c.lt.s, 1, 0)
281 REVCMPSF (__mips16_gesf2, c.le.s, 0, -1)
284 CMPSF (__mips16_lesf2, c.le.s, 0, 1)
287 CMPSF (__mips16_ltsf2, c.lt.s, -1, 0)
290 CMPSF(__mips16_unordsf2, c.un.s, 1, 0)
294 /* Single-precision conversions. */
297 STARTFN (__mips16_floatsisf)
301 ENDFN (__mips16_floatsisf)
304 #ifdef L_m16fltunsisf
305 STARTFN (__mips16_floatunsisf)
316 ENDFN (__mips16_floatunsisf)
319 #ifdef L_m16fix_truncsfsi
320 STARTFN (__mips16_fix_truncsfsi)
322 trunc.w.s RET,ARG1,$4
324 ENDFN (__mips16_fix_truncsfsi)
327 #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
329 /* Double-precision math. */
331 /* Define a function NAME that loads two double-precision values,
332 performs FPU operation OPCODE on them, and returns the double-
335 #define OPDF3(NAME, OPCODE) \
339 OPCODE RET,ARG1,ARG2; \
340 MOVE_DF_RET (f, $31); \
344 OPDF3 (__mips16_adddf3, add.d)
347 OPDF3 (__mips16_subdf3, sub.d)
350 OPDF3 (__mips16_muldf3, mul.d)
353 OPDF3 (__mips16_divdf3, div.d)
356 /* Define a function NAME that loads a double-precision value,
357 performs FPU operation OPCODE on it, and returns the double-
360 #define OPDF2(NAME, OPCODE) \
364 MOVE_DF_RET (f, $31); \
368 OPDF2 (__mips16_negdf2, neg.d)
371 OPDF2 (__mips16_absdf2, abs.d)
374 /* Conversions between single and double precision. */
377 STARTFN (__mips16_extendsfdf2)
381 ENDFN (__mips16_extendsfdf2)
385 STARTFN (__mips16_truncdfsf2)
389 ENDFN (__mips16_truncdfsf2)
392 /* Double-precision comparisons. */
394 /* Define a function NAME that loads two double-precision values,
395 performs floating point comparison OPCODE, and returns TRUE or
396 FALSE depending on the result. */
398 #define CMPDF(NAME, OPCODE, TRUE, FALSE) \
410 /* Like CMPDF, but reverse the comparison operands. */
412 #define REVCMPDF(NAME, OPCODE, TRUE, FALSE) \
425 CMPDF (__mips16_eqdf2, c.eq.d, 0, 1)
428 CMPDF (__mips16_nedf2, c.eq.d, 0, 1)
431 REVCMPDF (__mips16_gtdf2, c.lt.d, 1, 0)
434 REVCMPDF (__mips16_gedf2, c.le.d, 0, -1)
437 CMPDF (__mips16_ledf2, c.le.d, 0, 1)
440 CMPDF (__mips16_ltdf2, c.lt.d, -1, 0)
443 CMPDF(__mips16_unorddf2, c.un.d, 1, 0)
446 /* Double-precision conversions. */
449 STARTFN (__mips16_floatsidf)
453 ENDFN (__mips16_floatsidf)
456 #ifdef L_m16fltunsidf
457 STARTFN (__mips16_floatunsidf)
461 li.d ARG1, 4.294967296e+9
463 1: MOVE_DF_RET (f, $31)
464 ENDFN (__mips16_floatunsidf)
467 #ifdef L_m16fix_truncdfsi
468 STARTFN (__mips16_fix_truncdfsi)
470 trunc.w.d RET,ARG1,$4
472 ENDFN (__mips16_fix_truncdfsi)
474 #endif /* !__mips_single_float */
476 /* Define a function NAME that moves a return value of mode MODE from
479 #define RET_FUNCTION(NAME, MODE) \
481 MOVE_##MODE##_RET (t, $31); \
485 RET_FUNCTION (__mips16_ret_sf, SF)
489 RET_FUNCTION (__mips16_ret_sc, SC)
492 #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
494 RET_FUNCTION (__mips16_ret_df, DF)
498 RET_FUNCTION (__mips16_ret_dc, DC)
500 #endif /* !__mips_single_float */
502 /* STUB_ARGS_X copies the arguments from GPRs to FPRs for argument
503 code X. X is calculated as ARG1 + ARG2 * 4, where ARG1 and ARG2
504 classify the first and second arguments as follows:
506 1: a single-precision argument
507 2: a double-precision argument
508 0: no argument, or not one of the above. */
510 #define STUB_ARGS_0 /* () */
511 #define STUB_ARGS_1 MOVE_SF_BYTE0 (t) /* (sf) */
512 #define STUB_ARGS_5 MOVE_SF_BYTE0 (t); MOVE_SF_BYTE4 (t) /* (sf, sf) */
513 #define STUB_ARGS_9 MOVE_SF_BYTE0 (t); MOVE_DF_BYTE8 (t) /* (sf, df) */
514 #define STUB_ARGS_2 MOVE_DF_BYTE0 (t) /* (df) */
515 #define STUB_ARGS_6 MOVE_DF_BYTE0 (t); MOVE_SF_BYTE8 (t) /* (df, sf) */
516 #define STUB_ARGS_10 MOVE_DF_BYTE0 (t); MOVE_DF_BYTE8 (t) /* (df, df) */
518 /* These functions are used by 16-bit code when calling via a function
519 pointer. They must copy the floating point arguments from the GPRs
520 to FPRs and then call function $2. */
522 #define CALL_STUB_NO_RET(NAME, CODE) \
529 CALL_STUB_NO_RET (__mips16_call_stub_1, 1)
533 CALL_STUB_NO_RET (__mips16_call_stub_5, 5)
536 #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
539 CALL_STUB_NO_RET (__mips16_call_stub_2, 2)
543 CALL_STUB_NO_RET (__mips16_call_stub_6, 6)
547 CALL_STUB_NO_RET (__mips16_call_stub_9, 9)
551 CALL_STUB_NO_RET (__mips16_call_stub_10, 10)
553 #endif /* !__mips_single_float */
555 /* Now we have the same set of functions, except that this time the
556 function being called returns an SFmode, SCmode, DFmode or DCmode
557 value; we need to instantiate a set for each case. The calling
558 function will arrange to preserve $18, so these functions are free
559 to use it to hold the return address.
561 Note that we do not know whether the function we are calling is 16
562 bit or 32 bit. However, it does not matter, because 16-bit
563 functions always return floating point values in both the gp and
564 the fp regs. It would be possible to check whether the function
565 being called is 16 bits, in which case the copy is unnecessary;
566 however, it's faster to always do the copy. */
568 #define CALL_STUB_RET(NAME, CODE, MODE) \
573 MOVE_##MODE##_RET (f, $18); \
576 /* First, instantiate the single-float set. */
579 CALL_STUB_RET (__mips16_call_stub_sf_0, 0, SF)
583 CALL_STUB_RET (__mips16_call_stub_sf_1, 1, SF)
587 CALL_STUB_RET (__mips16_call_stub_sf_5, 5, SF)
590 #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
592 CALL_STUB_RET (__mips16_call_stub_sf_2, 2, SF)
596 CALL_STUB_RET (__mips16_call_stub_sf_6, 6, SF)
600 CALL_STUB_RET (__mips16_call_stub_sf_9, 9, SF)
604 CALL_STUB_RET (__mips16_call_stub_sf_10, 10, SF)
606 #endif /* !__mips_single_float */
609 /* Now we have the same set of functions again, except that this time
610 the function being called returns an DFmode value. */
612 #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
614 CALL_STUB_RET (__mips16_call_stub_df_0, 0, DF)
618 CALL_STUB_RET (__mips16_call_stub_df_1, 1, DF)
622 CALL_STUB_RET (__mips16_call_stub_df_5, 5, DF)
626 CALL_STUB_RET (__mips16_call_stub_df_2, 2, DF)
630 CALL_STUB_RET (__mips16_call_stub_df_6, 6, DF)
634 CALL_STUB_RET (__mips16_call_stub_df_9, 9, DF)
638 CALL_STUB_RET (__mips16_call_stub_df_10, 10, DF)
640 #endif /* !__mips_single_float */
643 /* Ho hum. Here we have the same set of functions again, this time
644 for when the function being called returns an SCmode value. */
647 CALL_STUB_RET (__mips16_call_stub_sc_0, 0, SC)
651 CALL_STUB_RET (__mips16_call_stub_sc_1, 1, SC)
655 CALL_STUB_RET (__mips16_call_stub_sc_5, 5, SC)
658 #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
660 CALL_STUB_RET (__mips16_call_stub_sc_2, 2, SC)
664 CALL_STUB_RET (__mips16_call_stub_sc_6, 6, SC)
668 CALL_STUB_RET (__mips16_call_stub_sc_9, 9, SC)
672 CALL_STUB_RET (__mips16_call_stub_sc_10, 10, SC)
674 #endif /* !__mips_single_float */
677 /* Finally, another set of functions for DCmode. */
679 #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
681 CALL_STUB_RET (__mips16_call_stub_dc_0, 0, DC)
685 CALL_STUB_RET (__mips16_call_stub_dc_1, 1, DC)
689 CALL_STUB_RET (__mips16_call_stub_dc_5, 5, DC)
693 CALL_STUB_RET (__mips16_call_stub_dc_2, 2, DC)
697 CALL_STUB_RET (__mips16_call_stub_dc_6, 6, DC)
701 CALL_STUB_RET (__mips16_call_stub_dc_9, 9, DC)
705 CALL_STUB_RET (__mips16_call_stub_dc_10, 10, DC)
707 #endif /* !__mips_single_float */