Home | History | Annotate | Line # | Download | only in mips
mips16.S revision 1.1
      1  1.1  mrg /* mips16 floating point support code
      2  1.1  mrg    Copyright (C) 1996-2013 Free Software Foundation, Inc.
      3  1.1  mrg    Contributed by Cygnus Support
      4  1.1  mrg 
      5  1.1  mrg This file is free software; you can redistribute it and/or modify it
      6  1.1  mrg under the terms of the GNU General Public License as published by the
      7  1.1  mrg Free Software Foundation; either version 3, or (at your option) any
      8  1.1  mrg later version.
      9  1.1  mrg 
     10  1.1  mrg This file is distributed in the hope that it will be useful, but
     11  1.1  mrg WITHOUT ANY WARRANTY; without even the implied warranty of
     12  1.1  mrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13  1.1  mrg General Public License for more details.
     14  1.1  mrg 
     15  1.1  mrg Under Section 7 of GPL version 3, you are granted additional
     16  1.1  mrg permissions described in the GCC Runtime Library Exception, version
     17  1.1  mrg 3.1, as published by the Free Software Foundation.
     18  1.1  mrg 
     19  1.1  mrg You should have received a copy of the GNU General Public License and
     20  1.1  mrg a copy of the GCC Runtime Library Exception along with this program;
     21  1.1  mrg see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
     22  1.1  mrg <http://www.gnu.org/licenses/>.  */
     23  1.1  mrg 
     24  1.1  mrg /* This file contains mips16 floating point support functions.  These
     25  1.1  mrg    functions are called by mips16 code to handle floating point when
     26  1.1  mrg    -msoft-float is not used.  They accept the arguments and return
     27  1.1  mrg    values using the soft-float calling convention, but do the actual
     28  1.1  mrg    operation using the hard floating point instructions.  */
     29  1.1  mrg 
     30  1.1  mrg #if defined _MIPS_SIM && (_MIPS_SIM == _ABIO32 || _MIPS_SIM == _ABIO64)
     31  1.1  mrg 
     32  1.1  mrg /* This file contains 32-bit assembly code.  */
     33  1.1  mrg 	.set nomips16
     34  1.1  mrg 
     35  1.1  mrg /* Start a function.  */
     36  1.1  mrg 
     37  1.1  mrg #define STARTFN(NAME) .globl NAME; .ent NAME; NAME:
     38  1.1  mrg 
     39  1.1  mrg /* Finish a function.  */
     40  1.1  mrg 
     41  1.1  mrg #define ENDFN(NAME) .end NAME
     42  1.1  mrg 
     43  1.1  mrg /* ARG1
     44  1.1  mrg 	The FPR that holds the first floating-point argument.
     45  1.1  mrg 
     46  1.1  mrg    ARG2
     47  1.1  mrg 	The FPR that holds the second floating-point argument.
     48  1.1  mrg 
     49  1.1  mrg    RET
     50  1.1  mrg 	The FPR that holds a floating-point return value.  */
     51  1.1  mrg 
     52  1.1  mrg #define RET $f0
     53  1.1  mrg #define ARG1 $f12
     54  1.1  mrg #ifdef __mips64
     55  1.1  mrg #define ARG2 $f13
     56  1.1  mrg #else
     57  1.1  mrg #define ARG2 $f14
     58  1.1  mrg #endif
     59  1.1  mrg 
     60  1.1  mrg /* Set 64-bit register GPR so that its high 32 bits contain HIGH_FPR
     61  1.1  mrg    and so that its low 32 bits contain LOW_FPR.  */
     62  1.1  mrg #define MERGE_GPRf(GPR, HIGH_FPR, LOW_FPR)	\
     63  1.1  mrg 	.set	noat;				\
     64  1.1  mrg 	mfc1	$1, LOW_FPR;			\
     65  1.1  mrg 	mfc1	GPR, HIGH_FPR;			\
     66  1.1  mrg 	dsll	$1, $1, 32;			\
     67  1.1  mrg 	dsll	GPR, GPR, 32;			\
     68  1.1  mrg 	dsrl	$1, $1, 32;			\
     69  1.1  mrg 	or	GPR, GPR, $1;			\
     70  1.1  mrg 	.set	at
     71  1.1  mrg 
     72  1.1  mrg /* Move the high 32 bits of GPR to HIGH_FPR and the low 32 bits of
     73  1.1  mrg    GPR to LOW_FPR.  */
     74  1.1  mrg #define MERGE_GPRt(GPR, HIGH_FPR, LOW_FPR)	\
     75  1.1  mrg 	.set	noat;				\
     76  1.1  mrg 	dsrl	$1, GPR, 32;			\
     77  1.1  mrg 	mtc1	GPR, LOW_FPR;			\
     78  1.1  mrg 	mtc1	$1, HIGH_FPR;			\
     79  1.1  mrg 	.set	at
     80  1.1  mrg 
     81  1.1  mrg /* Jump to T, and use "OPCODE, OP2" to implement a delayed move.  */
     82  1.1  mrg #define DELAYt(T, OPCODE, OP2)			\
     83  1.1  mrg 	.set	noreorder;			\
     84  1.1  mrg 	jr	T;				\
     85  1.1  mrg 	OPCODE, OP2;				\
     86  1.1  mrg 	.set	reorder
     87  1.1  mrg 
     88  1.1  mrg /* Use "OPCODE. OP2" and jump to T.  */
     89  1.1  mrg #define DELAYf(T, OPCODE, OP2) OPCODE, OP2; jr T
     90  1.1  mrg 
     91  1.1  mrg /* MOVE_SF_BYTE0(D)
     92  1.1  mrg 	Move the first single-precision floating-point argument between
     93  1.1  mrg 	GPRs and FPRs.
     94  1.1  mrg 
     95  1.1  mrg    MOVE_SI_BYTE0(D)
     96  1.1  mrg 	Likewise the first single-precision integer argument.
     97  1.1  mrg 
     98  1.1  mrg    MOVE_SF_BYTE4(D)
     99  1.1  mrg 	Move the second single-precision floating-point argument between
    100  1.1  mrg 	GPRs and FPRs, given that the first argument occupies 4 bytes.
    101  1.1  mrg 
    102  1.1  mrg    MOVE_SF_BYTE8(D)
    103  1.1  mrg 	Move the second single-precision floating-point argument between
    104  1.1  mrg 	GPRs and FPRs, given that the first argument occupies 8 bytes.
    105  1.1  mrg 
    106  1.1  mrg    MOVE_DF_BYTE0(D)
    107  1.1  mrg 	Move the first double-precision floating-point argument between
    108  1.1  mrg 	GPRs and FPRs.
    109  1.1  mrg 
    110  1.1  mrg    MOVE_DF_BYTE8(D)
    111  1.1  mrg 	Likewise the second double-precision floating-point argument.
    112  1.1  mrg 
    113  1.1  mrg    MOVE_SF_RET(D, T)
    114  1.1  mrg 	Likewise a single-precision floating-point return value,
    115  1.1  mrg 	then jump to T.
    116  1.1  mrg 
    117  1.1  mrg    MOVE_SC_RET(D, T)
    118  1.1  mrg 	Likewise a complex single-precision floating-point return value.
    119  1.1  mrg 
    120  1.1  mrg    MOVE_DF_RET(D, T)
    121  1.1  mrg 	Likewise a double-precision floating-point return value.
    122  1.1  mrg 
    123  1.1  mrg    MOVE_DC_RET(D, T)
    124  1.1  mrg 	Likewise a complex double-precision floating-point return value.
    125  1.1  mrg 
    126  1.1  mrg    MOVE_SI_RET(D, T)
    127  1.1  mrg 	Likewise a single-precision integer return value.
    128  1.1  mrg 
    129  1.1  mrg    The D argument is "t" to move to FPRs and "f" to move from FPRs.
    130  1.1  mrg    The return macros may assume that the target of the jump does not
    131  1.1  mrg    use a floating-point register.  */
    132  1.1  mrg 
    133  1.1  mrg #define MOVE_SF_RET(D, T) DELAY##D (T, m##D##c1 $2,$f0)
    134  1.1  mrg #define MOVE_SI_RET(D, T) DELAY##D (T, m##D##c1 $2,$f0)
    135  1.1  mrg 
    136  1.1  mrg #if defined(__mips64) && defined(__MIPSEB__)
    137  1.1  mrg #define MOVE_SC_RET(D, T) MERGE_GPR##D ($2, $f0, $f1); jr T
    138  1.1  mrg #elif defined(__mips64)
    139  1.1  mrg /* The high 32 bits of $2 correspond to the second word in memory;
    140  1.1  mrg    i.e. the imaginary part.  */
    141  1.1  mrg #define MOVE_SC_RET(D, T) MERGE_GPR##D ($2, $f1, $f0); jr T
    142  1.1  mrg #elif __mips_fpr == 64
    143  1.1  mrg #define MOVE_SC_RET(D, T) m##D##c1 $2,$f0; DELAY##D (T, m##D##c1 $3,$f1)
    144  1.1  mrg #else
    145  1.1  mrg #define MOVE_SC_RET(D, T) m##D##c1 $2,$f0; DELAY##D (T, m##D##c1 $3,$f2)
    146  1.1  mrg #endif
    147  1.1  mrg 
    148  1.1  mrg #if defined(__mips64)
    149  1.1  mrg #define MOVE_SF_BYTE0(D) m##D##c1 $4,$f12
    150  1.1  mrg #define MOVE_SF_BYTE4(D) m##D##c1 $5,$f13
    151  1.1  mrg #define MOVE_SF_BYTE8(D) m##D##c1 $5,$f13
    152  1.1  mrg #else
    153  1.1  mrg #define MOVE_SF_BYTE0(D) m##D##c1 $4,$f12
    154  1.1  mrg #define MOVE_SF_BYTE4(D) m##D##c1 $5,$f14
    155  1.1  mrg #define MOVE_SF_BYTE8(D) m##D##c1 $6,$f14
    156  1.1  mrg #endif
    157  1.1  mrg #define MOVE_SI_BYTE0(D) MOVE_SF_BYTE0(D)
    158  1.1  mrg 
    159  1.1  mrg #if defined(__mips64)
    160  1.1  mrg #define MOVE_DF_BYTE0(D) dm##D##c1 $4,$f12
    161  1.1  mrg #define MOVE_DF_BYTE8(D) dm##D##c1 $5,$f13
    162  1.1  mrg #define MOVE_DF_RET(D, T) DELAY##D (T, dm##D##c1 $2,$f0)
    163  1.1  mrg #define MOVE_DC_RET(D, T) dm##D##c1 $3,$f1; MOVE_DF_RET (D, T)
    164  1.1  mrg #elif __mips_fpr == 64 && defined(__MIPSEB__)
    165  1.1  mrg #define MOVE_DF_BYTE0(D) m##D##c1 $5,$f12; m##D##hc1 $4,$f12
    166  1.1  mrg #define MOVE_DF_BYTE8(D) m##D##c1 $7,$f14; m##D##hc1 $6,$f14
    167  1.1  mrg #define MOVE_DF_RET(D, T) m##D##c1 $3,$f0; DELAY##D (T, m##D##hc1 $2,$f0)
    168  1.1  mrg #define MOVE_DC_RET(D, T) m##D##c1 $5,$f1; m##D##hc1 $4,$f1; MOVE_DF_RET (D, T)
    169  1.1  mrg #elif __mips_fpr == 64
    170  1.1  mrg #define MOVE_DF_BYTE0(D) m##D##c1 $4,$f12; m##D##hc1 $5,$f12
    171  1.1  mrg #define MOVE_DF_BYTE8(D) m##D##c1 $6,$f14; m##D##hc1 $7,$f14
    172  1.1  mrg #define MOVE_DF_RET(D, T) m##D##c1 $2,$f0; DELAY##D (T, m##D##hc1 $3,$f0)
    173  1.1  mrg #define MOVE_DC_RET(D, T) m##D##c1 $4,$f1; m##D##hc1 $5,$f1; MOVE_DF_RET (D, T)
    174  1.1  mrg #elif defined(__MIPSEB__)
    175  1.1  mrg /* FPRs are little-endian.  */
    176  1.1  mrg #define MOVE_DF_BYTE0(D) m##D##c1 $4,$f13; m##D##c1 $5,$f12
    177  1.1  mrg #define MOVE_DF_BYTE8(D) m##D##c1 $6,$f15; m##D##c1 $7,$f14
    178  1.1  mrg #define MOVE_DF_RET(D, T) m##D##c1 $2,$f1; DELAY##D (T, m##D##c1 $3,$f0)
    179  1.1  mrg #define MOVE_DC_RET(D, T) m##D##c1 $4,$f3; m##D##c1 $5,$f2; MOVE_DF_RET (D, T)
    180  1.1  mrg #else
    181  1.1  mrg #define MOVE_DF_BYTE0(D) m##D##c1 $4,$f12; m##D##c1 $5,$f13
    182  1.1  mrg #define MOVE_DF_BYTE8(D) m##D##c1 $6,$f14; m##D##c1 $7,$f15
    183  1.1  mrg #define MOVE_DF_RET(D, T) m##D##c1 $2,$f0; DELAY##D (T, m##D##c1 $3,$f1)
    184  1.1  mrg #define MOVE_DC_RET(D, T) m##D##c1 $4,$f2; m##D##c1 $5,$f3; MOVE_DF_RET (D, T)
    185  1.1  mrg #endif
    186  1.1  mrg 
    187  1.1  mrg /* Single-precision math.  */
    188  1.1  mrg 
    189  1.1  mrg /* Define a function NAME that loads two single-precision values,
    190  1.1  mrg    performs FPU operation OPCODE on them, and returns the single-
    191  1.1  mrg    precision result.  */
    192  1.1  mrg 
    193  1.1  mrg #define OPSF3(NAME, OPCODE)	\
    194  1.1  mrg STARTFN (NAME);			\
    195  1.1  mrg 	MOVE_SF_BYTE0 (t);	\
    196  1.1  mrg 	MOVE_SF_BYTE4 (t);	\
    197  1.1  mrg 	OPCODE	RET,ARG1,ARG2;	\
    198  1.1  mrg 	MOVE_SF_RET (f, $31);	\
    199  1.1  mrg 	ENDFN (NAME)
    200  1.1  mrg 
    201  1.1  mrg #ifdef L_m16addsf3
    202  1.1  mrg OPSF3 (__mips16_addsf3, add.s)
    203  1.1  mrg #endif
    204  1.1  mrg #ifdef L_m16subsf3
    205  1.1  mrg OPSF3 (__mips16_subsf3, sub.s)
    206  1.1  mrg #endif
    207  1.1  mrg #ifdef L_m16mulsf3
    208  1.1  mrg OPSF3 (__mips16_mulsf3, mul.s)
    209  1.1  mrg #endif
    210  1.1  mrg #ifdef L_m16divsf3
    211  1.1  mrg OPSF3 (__mips16_divsf3, div.s)
    212  1.1  mrg #endif
    213  1.1  mrg 
    214  1.1  mrg /* Define a function NAME that loads a single-precision value,
    215  1.1  mrg    performs FPU operation OPCODE on it, and returns the single-
    216  1.1  mrg    precision result.  */
    217  1.1  mrg 
    218  1.1  mrg #define OPSF2(NAME, OPCODE)	\
    219  1.1  mrg STARTFN (NAME);			\
    220  1.1  mrg 	MOVE_SF_BYTE0 (t);	\
    221  1.1  mrg 	OPCODE	RET,ARG1;	\
    222  1.1  mrg 	MOVE_SF_RET (f, $31);	\
    223  1.1  mrg 	ENDFN (NAME)
    224  1.1  mrg 
    225  1.1  mrg #ifdef L_m16negsf2
    226  1.1  mrg OPSF2 (__mips16_negsf2, neg.s)
    227  1.1  mrg #endif
    228  1.1  mrg #ifdef L_m16abssf2
    229  1.1  mrg OPSF2 (__mips16_abssf2, abs.s)
    230  1.1  mrg #endif
    231  1.1  mrg 
    232  1.1  mrg /* Single-precision comparisons.  */
    233  1.1  mrg 
    234  1.1  mrg /* Define a function NAME that loads two single-precision values,
    235  1.1  mrg    performs floating point comparison OPCODE, and returns TRUE or
    236  1.1  mrg    FALSE depending on the result.  */
    237  1.1  mrg 
    238  1.1  mrg #define CMPSF(NAME, OPCODE, TRUE, FALSE)	\
    239  1.1  mrg STARTFN (NAME);					\
    240  1.1  mrg 	MOVE_SF_BYTE0 (t);			\
    241  1.1  mrg 	MOVE_SF_BYTE4 (t);			\
    242  1.1  mrg 	OPCODE	ARG1,ARG2;			\
    243  1.1  mrg 	li	$2,TRUE;			\
    244  1.1  mrg 	bc1t	1f;				\
    245  1.1  mrg 	li	$2,FALSE;			\
    246  1.1  mrg 1:;						\
    247  1.1  mrg 	j	$31;				\
    248  1.1  mrg 	ENDFN (NAME)
    249  1.1  mrg 
    250  1.1  mrg /* Like CMPSF, but reverse the comparison operands.  */
    251  1.1  mrg 
    252  1.1  mrg #define REVCMPSF(NAME, OPCODE, TRUE, FALSE)	\
    253  1.1  mrg STARTFN (NAME);					\
    254  1.1  mrg 	MOVE_SF_BYTE0 (t);			\
    255  1.1  mrg 	MOVE_SF_BYTE4 (t);			\
    256  1.1  mrg 	OPCODE	ARG2,ARG1;			\
    257  1.1  mrg 	li	$2,TRUE;			\
    258  1.1  mrg 	bc1t	1f;				\
    259  1.1  mrg 	li	$2,FALSE;			\
    260  1.1  mrg 1:;						\
    261  1.1  mrg 	j	$31;				\
    262  1.1  mrg 	ENDFN (NAME)
    263  1.1  mrg 
    264  1.1  mrg #ifdef L_m16eqsf2
    265  1.1  mrg CMPSF (__mips16_eqsf2, c.eq.s, 0, 1)
    266  1.1  mrg #endif
    267  1.1  mrg #ifdef L_m16nesf2
    268  1.1  mrg CMPSF (__mips16_nesf2, c.eq.s, 0, 1)
    269  1.1  mrg #endif
    270  1.1  mrg #ifdef L_m16gtsf2
    271  1.1  mrg REVCMPSF (__mips16_gtsf2, c.lt.s, 1, 0)
    272  1.1  mrg #endif
    273  1.1  mrg #ifdef L_m16gesf2
    274  1.1  mrg REVCMPSF (__mips16_gesf2, c.le.s, 0, -1)
    275  1.1  mrg #endif
    276  1.1  mrg #ifdef L_m16lesf2
    277  1.1  mrg CMPSF (__mips16_lesf2, c.le.s, 0, 1)
    278  1.1  mrg #endif
    279  1.1  mrg #ifdef L_m16ltsf2
    280  1.1  mrg CMPSF (__mips16_ltsf2, c.lt.s, -1, 0)
    281  1.1  mrg #endif
    282  1.1  mrg #ifdef L_m16unordsf2
    283  1.1  mrg CMPSF(__mips16_unordsf2, c.un.s, 1, 0)
    284  1.1  mrg #endif
    285  1.1  mrg 
    286  1.1  mrg 
    287  1.1  mrg /* Single-precision conversions.  */
    288  1.1  mrg 
    289  1.1  mrg #ifdef L_m16fltsisf
    290  1.1  mrg STARTFN (__mips16_floatsisf)
    291  1.1  mrg 	MOVE_SF_BYTE0 (t)
    292  1.1  mrg 	cvt.s.w	RET,ARG1
    293  1.1  mrg 	MOVE_SF_RET (f, $31)
    294  1.1  mrg 	ENDFN (__mips16_floatsisf)
    295  1.1  mrg #endif
    296  1.1  mrg 
    297  1.1  mrg #ifdef L_m16fltunsisf
    298  1.1  mrg STARTFN (__mips16_floatunsisf)
    299  1.1  mrg 	.set	noreorder
    300  1.1  mrg 	bltz	$4,1f
    301  1.1  mrg 	MOVE_SF_BYTE0 (t)
    302  1.1  mrg 	.set	reorder
    303  1.1  mrg 	cvt.s.w	RET,ARG1
    304  1.1  mrg 	MOVE_SF_RET (f, $31)
    305  1.1  mrg 1:
    306  1.1  mrg 	and	$2,$4,1
    307  1.1  mrg 	srl	$3,$4,1
    308  1.1  mrg 	or	$2,$2,$3
    309  1.1  mrg 	mtc1	$2,RET
    310  1.1  mrg 	cvt.s.w	RET,RET
    311  1.1  mrg 	add.s	RET,RET,RET
    312  1.1  mrg 	MOVE_SF_RET (f, $31)
    313  1.1  mrg 	ENDFN (__mips16_floatunsisf)
    314  1.1  mrg #endif
    315  1.1  mrg 
    316  1.1  mrg #ifdef L_m16fix_truncsfsi
    317  1.1  mrg STARTFN (__mips16_fix_truncsfsi)
    318  1.1  mrg 	MOVE_SF_BYTE0 (t)
    319  1.1  mrg 	trunc.w.s RET,ARG1,$4
    320  1.1  mrg 	MOVE_SI_RET (f, $31)
    321  1.1  mrg 	ENDFN (__mips16_fix_truncsfsi)
    322  1.1  mrg #endif
    323  1.1  mrg 
    324  1.1  mrg #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
    325  1.1  mrg 
    326  1.1  mrg /* Double-precision math.  */
    327  1.1  mrg 
    328  1.1  mrg /* Define a function NAME that loads two double-precision values,
    329  1.1  mrg    performs FPU operation OPCODE on them, and returns the double-
    330  1.1  mrg    precision result.  */
    331  1.1  mrg 
    332  1.1  mrg #define OPDF3(NAME, OPCODE)	\
    333  1.1  mrg STARTFN (NAME);			\
    334  1.1  mrg 	MOVE_DF_BYTE0 (t);	\
    335  1.1  mrg 	MOVE_DF_BYTE8 (t);	\
    336  1.1  mrg 	OPCODE RET,ARG1,ARG2;	\
    337  1.1  mrg 	MOVE_DF_RET (f, $31);	\
    338  1.1  mrg 	ENDFN (NAME)
    339  1.1  mrg 
    340  1.1  mrg #ifdef L_m16adddf3
    341  1.1  mrg OPDF3 (__mips16_adddf3, add.d)
    342  1.1  mrg #endif
    343  1.1  mrg #ifdef L_m16subdf3
    344  1.1  mrg OPDF3 (__mips16_subdf3, sub.d)
    345  1.1  mrg #endif
    346  1.1  mrg #ifdef L_m16muldf3
    347  1.1  mrg OPDF3 (__mips16_muldf3, mul.d)
    348  1.1  mrg #endif
    349  1.1  mrg #ifdef L_m16divdf3
    350  1.1  mrg OPDF3 (__mips16_divdf3, div.d)
    351  1.1  mrg #endif
    352  1.1  mrg 
    353  1.1  mrg /* Define a function NAME that loads a double-precision value,
    354  1.1  mrg    performs FPU operation OPCODE on it, and returns the double-
    355  1.1  mrg    precision result.  */
    356  1.1  mrg 
    357  1.1  mrg #define OPDF2(NAME, OPCODE)	\
    358  1.1  mrg STARTFN (NAME);			\
    359  1.1  mrg 	MOVE_DF_BYTE0 (t);	\
    360  1.1  mrg 	OPCODE RET,ARG1;	\
    361  1.1  mrg 	MOVE_DF_RET (f, $31);	\
    362  1.1  mrg 	ENDFN (NAME)
    363  1.1  mrg 
    364  1.1  mrg #ifdef L_m16negdf2
    365  1.1  mrg OPDF2 (__mips16_negdf2, neg.d)
    366  1.1  mrg #endif
    367  1.1  mrg #ifdef L_m16absdf2
    368  1.1  mrg OPDF2 (__mips16_absdf2, abs.d)
    369  1.1  mrg #endif
    370  1.1  mrg 
    371  1.1  mrg /* Conversions between single and double precision.  */
    372  1.1  mrg 
    373  1.1  mrg #ifdef L_m16extsfdf2
    374  1.1  mrg STARTFN (__mips16_extendsfdf2)
    375  1.1  mrg 	MOVE_SF_BYTE0 (t)
    376  1.1  mrg 	cvt.d.s	RET,ARG1
    377  1.1  mrg 	MOVE_DF_RET (f, $31)
    378  1.1  mrg 	ENDFN (__mips16_extendsfdf2)
    379  1.1  mrg #endif
    380  1.1  mrg 
    381  1.1  mrg #ifdef L_m16trdfsf2
    382  1.1  mrg STARTFN (__mips16_truncdfsf2)
    383  1.1  mrg 	MOVE_DF_BYTE0 (t)
    384  1.1  mrg 	cvt.s.d	RET,ARG1
    385  1.1  mrg 	MOVE_SF_RET (f, $31)
    386  1.1  mrg 	ENDFN (__mips16_truncdfsf2)
    387  1.1  mrg #endif
    388  1.1  mrg 
    389  1.1  mrg /* Double-precision comparisons.  */
    390  1.1  mrg 
    391  1.1  mrg /* Define a function NAME that loads two double-precision values,
    392  1.1  mrg    performs floating point comparison OPCODE, and returns TRUE or
    393  1.1  mrg    FALSE depending on the result.  */
    394  1.1  mrg 
    395  1.1  mrg #define CMPDF(NAME, OPCODE, TRUE, FALSE)	\
    396  1.1  mrg STARTFN (NAME);					\
    397  1.1  mrg 	MOVE_DF_BYTE0 (t);			\
    398  1.1  mrg 	MOVE_DF_BYTE8 (t);			\
    399  1.1  mrg 	OPCODE	ARG1,ARG2;			\
    400  1.1  mrg 	li	$2,TRUE;			\
    401  1.1  mrg 	bc1t	1f;				\
    402  1.1  mrg 	li	$2,FALSE;			\
    403  1.1  mrg 1:;						\
    404  1.1  mrg 	j	$31;				\
    405  1.1  mrg 	ENDFN (NAME)
    406  1.1  mrg 
    407  1.1  mrg /* Like CMPDF, but reverse the comparison operands.  */
    408  1.1  mrg 
    409  1.1  mrg #define REVCMPDF(NAME, OPCODE, TRUE, FALSE)	\
    410  1.1  mrg STARTFN (NAME);					\
    411  1.1  mrg 	MOVE_DF_BYTE0 (t);			\
    412  1.1  mrg 	MOVE_DF_BYTE8 (t);			\
    413  1.1  mrg 	OPCODE	ARG2,ARG1;			\
    414  1.1  mrg 	li	$2,TRUE;			\
    415  1.1  mrg 	bc1t	1f;				\
    416  1.1  mrg 	li	$2,FALSE;			\
    417  1.1  mrg 1:;						\
    418  1.1  mrg 	j	$31;				\
    419  1.1  mrg 	ENDFN (NAME)
    420  1.1  mrg 
    421  1.1  mrg #ifdef L_m16eqdf2
    422  1.1  mrg CMPDF (__mips16_eqdf2, c.eq.d, 0, 1)
    423  1.1  mrg #endif
    424  1.1  mrg #ifdef L_m16nedf2
    425  1.1  mrg CMPDF (__mips16_nedf2, c.eq.d, 0, 1)
    426  1.1  mrg #endif
    427  1.1  mrg #ifdef L_m16gtdf2
    428  1.1  mrg REVCMPDF (__mips16_gtdf2, c.lt.d, 1, 0)
    429  1.1  mrg #endif
    430  1.1  mrg #ifdef L_m16gedf2
    431  1.1  mrg REVCMPDF (__mips16_gedf2, c.le.d, 0, -1)
    432  1.1  mrg #endif
    433  1.1  mrg #ifdef L_m16ledf2
    434  1.1  mrg CMPDF (__mips16_ledf2, c.le.d, 0, 1)
    435  1.1  mrg #endif
    436  1.1  mrg #ifdef L_m16ltdf2
    437  1.1  mrg CMPDF (__mips16_ltdf2, c.lt.d, -1, 0)
    438  1.1  mrg #endif
    439  1.1  mrg #ifdef L_m16unorddf2
    440  1.1  mrg CMPDF(__mips16_unorddf2, c.un.d, 1, 0)
    441  1.1  mrg #endif
    442  1.1  mrg 
    443  1.1  mrg /* Double-precision conversions.  */
    444  1.1  mrg 
    445  1.1  mrg #ifdef L_m16fltsidf
    446  1.1  mrg STARTFN (__mips16_floatsidf)
    447  1.1  mrg 	MOVE_SI_BYTE0 (t)
    448  1.1  mrg 	cvt.d.w	RET,ARG1
    449  1.1  mrg 	MOVE_DF_RET (f, $31)
    450  1.1  mrg 	ENDFN (__mips16_floatsidf)
    451  1.1  mrg #endif
    452  1.1  mrg 
    453  1.1  mrg #ifdef L_m16fltunsidf
    454  1.1  mrg STARTFN (__mips16_floatunsidf)
    455  1.1  mrg 	MOVE_SI_BYTE0 (t)
    456  1.1  mrg 	cvt.d.w RET,ARG1
    457  1.1  mrg 	bgez	$4,1f
    458  1.1  mrg 	li.d	ARG1, 4.294967296e+9
    459  1.1  mrg 	add.d	RET, RET, ARG1
    460  1.1  mrg 1:	MOVE_DF_RET (f, $31)
    461  1.1  mrg 	ENDFN (__mips16_floatunsidf)
    462  1.1  mrg #endif
    463  1.1  mrg 
    464  1.1  mrg #ifdef L_m16fix_truncdfsi
    465  1.1  mrg STARTFN (__mips16_fix_truncdfsi)
    466  1.1  mrg 	MOVE_DF_BYTE0 (t)
    467  1.1  mrg 	trunc.w.d RET,ARG1,$4
    468  1.1  mrg 	MOVE_SI_RET (f, $31)
    469  1.1  mrg 	ENDFN (__mips16_fix_truncdfsi)
    470  1.1  mrg #endif
    471  1.1  mrg #endif /* !__mips_single_float */
    472  1.1  mrg 
    473  1.1  mrg /* Define a function NAME that moves a return value of mode MODE from
    474  1.1  mrg    FPRs to GPRs.  */
    475  1.1  mrg 
    476  1.1  mrg #define RET_FUNCTION(NAME, MODE)	\
    477  1.1  mrg STARTFN (NAME);				\
    478  1.1  mrg 	MOVE_##MODE##_RET (t, $31);	\
    479  1.1  mrg 	ENDFN (NAME)
    480  1.1  mrg 
    481  1.1  mrg #ifdef L_m16retsf
    482  1.1  mrg RET_FUNCTION (__mips16_ret_sf, SF)
    483  1.1  mrg #endif
    484  1.1  mrg 
    485  1.1  mrg #ifdef L_m16retsc
    486  1.1  mrg RET_FUNCTION (__mips16_ret_sc, SC)
    487  1.1  mrg #endif
    488  1.1  mrg 
    489  1.1  mrg #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
    490  1.1  mrg #ifdef L_m16retdf
    491  1.1  mrg RET_FUNCTION (__mips16_ret_df, DF)
    492  1.1  mrg #endif
    493  1.1  mrg 
    494  1.1  mrg #ifdef L_m16retdc
    495  1.1  mrg RET_FUNCTION (__mips16_ret_dc, DC)
    496  1.1  mrg #endif
    497  1.1  mrg #endif /* !__mips_single_float */
    498  1.1  mrg 
    499  1.1  mrg /* STUB_ARGS_X copies the arguments from GPRs to FPRs for argument
    500  1.1  mrg    code X.  X is calculated as ARG1 + ARG2 * 4, where ARG1 and ARG2
    501  1.1  mrg    classify the first and second arguments as follows:
    502  1.1  mrg 
    503  1.1  mrg 	1: a single-precision argument
    504  1.1  mrg 	2: a double-precision argument
    505  1.1  mrg 	0: no argument, or not one of the above.  */
    506  1.1  mrg 
    507  1.1  mrg #define STUB_ARGS_0						/* () */
    508  1.1  mrg #define STUB_ARGS_1 MOVE_SF_BYTE0 (t)				/* (sf) */
    509  1.1  mrg #define STUB_ARGS_5 MOVE_SF_BYTE0 (t); MOVE_SF_BYTE4 (t)	/* (sf, sf) */
    510  1.1  mrg #define STUB_ARGS_9 MOVE_SF_BYTE0 (t); MOVE_DF_BYTE8 (t)	/* (sf, df) */
    511  1.1  mrg #define STUB_ARGS_2 MOVE_DF_BYTE0 (t)				/* (df) */
    512  1.1  mrg #define STUB_ARGS_6 MOVE_DF_BYTE0 (t); MOVE_SF_BYTE8 (t)	/* (df, sf) */
    513  1.1  mrg #define STUB_ARGS_10 MOVE_DF_BYTE0 (t); MOVE_DF_BYTE8 (t)	/* (df, df) */
    514  1.1  mrg 
    515  1.1  mrg /* These functions are used by 16-bit code when calling via a function
    516  1.1  mrg    pointer.  They must copy the floating point arguments from the GPRs
    517  1.1  mrg    to FPRs and then call function $2.  */
    518  1.1  mrg 
    519  1.1  mrg #define CALL_STUB_NO_RET(NAME, CODE)	\
    520  1.1  mrg STARTFN (NAME);				\
    521  1.1  mrg 	STUB_ARGS_##CODE;		\
    522  1.1  mrg 	.set	noreorder;		\
    523  1.1  mrg 	jr	$2;			\
    524  1.1  mrg 	move	$25,$2;			\
    525  1.1  mrg 	.set	reorder;		\
    526  1.1  mrg 	ENDFN (NAME)
    527  1.1  mrg 
    528  1.1  mrg #ifdef L_m16stub1
    529  1.1  mrg CALL_STUB_NO_RET (__mips16_call_stub_1, 1)
    530  1.1  mrg #endif
    531  1.1  mrg 
    532  1.1  mrg #ifdef L_m16stub5
    533  1.1  mrg CALL_STUB_NO_RET (__mips16_call_stub_5, 5)
    534  1.1  mrg #endif
    535  1.1  mrg 
    536  1.1  mrg #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
    537  1.1  mrg 
    538  1.1  mrg #ifdef L_m16stub2
    539  1.1  mrg CALL_STUB_NO_RET (__mips16_call_stub_2, 2)
    540  1.1  mrg #endif
    541  1.1  mrg 
    542  1.1  mrg #ifdef L_m16stub6
    543  1.1  mrg CALL_STUB_NO_RET (__mips16_call_stub_6, 6)
    544  1.1  mrg #endif
    545  1.1  mrg 
    546  1.1  mrg #ifdef L_m16stub9
    547  1.1  mrg CALL_STUB_NO_RET (__mips16_call_stub_9, 9)
    548  1.1  mrg #endif
    549  1.1  mrg 
    550  1.1  mrg #ifdef L_m16stub10
    551  1.1  mrg CALL_STUB_NO_RET (__mips16_call_stub_10, 10)
    552  1.1  mrg #endif
    553  1.1  mrg #endif /* !__mips_single_float */
    554  1.1  mrg 
    555  1.1  mrg /* Now we have the same set of functions, except that this time the
    556  1.1  mrg    function being called returns an SFmode, SCmode, DFmode or DCmode
    557  1.1  mrg    value; we need to instantiate a set for each case.  The calling
    558  1.1  mrg    function will arrange to preserve $18, so these functions are free
    559  1.1  mrg    to use it to hold the return address.
    560  1.1  mrg 
    561  1.1  mrg    Note that we do not know whether the function we are calling is 16
    562  1.1  mrg    bit or 32 bit.  However, it does not matter, because 16-bit
    563  1.1  mrg    functions always return floating point values in both the gp and
    564  1.1  mrg    the fp regs.  It would be possible to check whether the function
    565  1.1  mrg    being called is 16 bits, in which case the copy is unnecessary;
    566  1.1  mrg    however, it's faster to always do the copy.  */
    567  1.1  mrg 
    568  1.1  mrg #define CALL_STUB_RET(NAME, CODE, MODE)					\
    569  1.1  mrg STARTFN (NAME);								\
    570  1.1  mrg 	.cfi_startproc;							\
    571  1.1  mrg 	/* Create a fake CFA 4 bytes below the stack pointer.  */	\
    572  1.1  mrg 	.cfi_def_cfa 29,-4;						\
    573  1.1  mrg 	/* "Save" $sp in itself so we don't use the fake CFA.		\
    574  1.1  mrg 	   This is: DW_CFA_val_expression r29, { DW_OP_reg29 }.  */	\
    575  1.1  mrg 	.cfi_escape 0x16,29,1,0x6d;					\
    576  1.1  mrg 	move	$18,$31;						\
    577  1.1  mrg 	.cfi_register 31,18;						\
    578  1.1  mrg 	STUB_ARGS_##CODE;						\
    579  1.1  mrg 	.set	noreorder;						\
    580  1.1  mrg 	jalr	$2;							\
    581  1.1  mrg 	move	$25,$2;							\
    582  1.1  mrg 	.set	reorder;						\
    583  1.1  mrg 	MOVE_##MODE##_RET (f, $18);					\
    584  1.1  mrg 	.cfi_endproc;							\
    585  1.1  mrg 	ENDFN (NAME)
    586  1.1  mrg 
    587  1.1  mrg /* First, instantiate the single-float set.  */
    588  1.1  mrg 
    589  1.1  mrg #ifdef L_m16stubsf0
    590  1.1  mrg CALL_STUB_RET (__mips16_call_stub_sf_0, 0, SF)
    591  1.1  mrg #endif
    592  1.1  mrg 
    593  1.1  mrg #ifdef L_m16stubsf1
    594  1.1  mrg CALL_STUB_RET (__mips16_call_stub_sf_1, 1, SF)
    595  1.1  mrg #endif
    596  1.1  mrg 
    597  1.1  mrg #ifdef L_m16stubsf5
    598  1.1  mrg CALL_STUB_RET (__mips16_call_stub_sf_5, 5, SF)
    599  1.1  mrg #endif
    600  1.1  mrg 
    601  1.1  mrg #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
    602  1.1  mrg #ifdef L_m16stubsf2
    603  1.1  mrg CALL_STUB_RET (__mips16_call_stub_sf_2, 2, SF)
    604  1.1  mrg #endif
    605  1.1  mrg 
    606  1.1  mrg #ifdef L_m16stubsf6
    607  1.1  mrg CALL_STUB_RET (__mips16_call_stub_sf_6, 6, SF)
    608  1.1  mrg #endif
    609  1.1  mrg 
    610  1.1  mrg #ifdef L_m16stubsf9
    611  1.1  mrg CALL_STUB_RET (__mips16_call_stub_sf_9, 9, SF)
    612  1.1  mrg #endif
    613  1.1  mrg 
    614  1.1  mrg #ifdef L_m16stubsf10
    615  1.1  mrg CALL_STUB_RET (__mips16_call_stub_sf_10, 10, SF)
    616  1.1  mrg #endif
    617  1.1  mrg #endif /* !__mips_single_float */
    618  1.1  mrg 
    619  1.1  mrg 
    620  1.1  mrg /* Now we have the same set of functions again, except that this time
    621  1.1  mrg    the function being called returns an DFmode value.  */
    622  1.1  mrg 
    623  1.1  mrg #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
    624  1.1  mrg #ifdef L_m16stubdf0
    625  1.1  mrg CALL_STUB_RET (__mips16_call_stub_df_0, 0, DF)
    626  1.1  mrg #endif
    627  1.1  mrg 
    628  1.1  mrg #ifdef L_m16stubdf1
    629  1.1  mrg CALL_STUB_RET (__mips16_call_stub_df_1, 1, DF)
    630  1.1  mrg #endif
    631  1.1  mrg 
    632  1.1  mrg #ifdef L_m16stubdf5
    633  1.1  mrg CALL_STUB_RET (__mips16_call_stub_df_5, 5, DF)
    634  1.1  mrg #endif
    635  1.1  mrg 
    636  1.1  mrg #ifdef L_m16stubdf2
    637  1.1  mrg CALL_STUB_RET (__mips16_call_stub_df_2, 2, DF)
    638  1.1  mrg #endif
    639  1.1  mrg 
    640  1.1  mrg #ifdef L_m16stubdf6
    641  1.1  mrg CALL_STUB_RET (__mips16_call_stub_df_6, 6, DF)
    642  1.1  mrg #endif
    643  1.1  mrg 
    644  1.1  mrg #ifdef L_m16stubdf9
    645  1.1  mrg CALL_STUB_RET (__mips16_call_stub_df_9, 9, DF)
    646  1.1  mrg #endif
    647  1.1  mrg 
    648  1.1  mrg #ifdef L_m16stubdf10
    649  1.1  mrg CALL_STUB_RET (__mips16_call_stub_df_10, 10, DF)
    650  1.1  mrg #endif
    651  1.1  mrg #endif /* !__mips_single_float */
    652  1.1  mrg 
    653  1.1  mrg 
    654  1.1  mrg /* Ho hum.  Here we have the same set of functions again, this time
    655  1.1  mrg    for when the function being called returns an SCmode value.  */
    656  1.1  mrg 
    657  1.1  mrg #ifdef L_m16stubsc0
    658  1.1  mrg CALL_STUB_RET (__mips16_call_stub_sc_0, 0, SC)
    659  1.1  mrg #endif
    660  1.1  mrg 
    661  1.1  mrg #ifdef L_m16stubsc1
    662  1.1  mrg CALL_STUB_RET (__mips16_call_stub_sc_1, 1, SC)
    663  1.1  mrg #endif
    664  1.1  mrg 
    665  1.1  mrg #ifdef L_m16stubsc5
    666  1.1  mrg CALL_STUB_RET (__mips16_call_stub_sc_5, 5, SC)
    667  1.1  mrg #endif
    668  1.1  mrg 
    669  1.1  mrg #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
    670  1.1  mrg #ifdef L_m16stubsc2
    671  1.1  mrg CALL_STUB_RET (__mips16_call_stub_sc_2, 2, SC)
    672  1.1  mrg #endif
    673  1.1  mrg 
    674  1.1  mrg #ifdef L_m16stubsc6
    675  1.1  mrg CALL_STUB_RET (__mips16_call_stub_sc_6, 6, SC)
    676  1.1  mrg #endif
    677  1.1  mrg 
    678  1.1  mrg #ifdef L_m16stubsc9
    679  1.1  mrg CALL_STUB_RET (__mips16_call_stub_sc_9, 9, SC)
    680  1.1  mrg #endif
    681  1.1  mrg 
    682  1.1  mrg #ifdef L_m16stubsc10
    683  1.1  mrg CALL_STUB_RET (__mips16_call_stub_sc_10, 10, SC)
    684  1.1  mrg #endif
    685  1.1  mrg #endif /* !__mips_single_float */
    686  1.1  mrg 
    687  1.1  mrg 
    688  1.1  mrg /* Finally, another set of functions for DCmode.  */
    689  1.1  mrg 
    690  1.1  mrg #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
    691  1.1  mrg #ifdef L_m16stubdc0
    692  1.1  mrg CALL_STUB_RET (__mips16_call_stub_dc_0, 0, DC)
    693  1.1  mrg #endif
    694  1.1  mrg 
    695  1.1  mrg #ifdef L_m16stubdc1
    696  1.1  mrg CALL_STUB_RET (__mips16_call_stub_dc_1, 1, DC)
    697  1.1  mrg #endif
    698  1.1  mrg 
    699  1.1  mrg #ifdef L_m16stubdc5
    700  1.1  mrg CALL_STUB_RET (__mips16_call_stub_dc_5, 5, DC)
    701  1.1  mrg #endif
    702  1.1  mrg 
    703  1.1  mrg #ifdef L_m16stubdc2
    704  1.1  mrg CALL_STUB_RET (__mips16_call_stub_dc_2, 2, DC)
    705  1.1  mrg #endif
    706  1.1  mrg 
    707  1.1  mrg #ifdef L_m16stubdc6
    708  1.1  mrg CALL_STUB_RET (__mips16_call_stub_dc_6, 6, DC)
    709  1.1  mrg #endif
    710  1.1  mrg 
    711  1.1  mrg #ifdef L_m16stubdc9
    712  1.1  mrg CALL_STUB_RET (__mips16_call_stub_dc_9, 9, DC)
    713  1.1  mrg #endif
    714  1.1  mrg 
    715  1.1  mrg #ifdef L_m16stubdc10
    716  1.1  mrg CALL_STUB_RET (__mips16_call_stub_dc_10, 10, DC)
    717  1.1  mrg #endif
    718  1.1  mrg #endif /* !__mips_single_float */
    719  1.1  mrg 
    720  1.1  mrg #endif
    721