mips16.S revision 169690
133965Sjdp/* mips16 floating point support code
233965Sjdp   Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
338889Sjdp   Contributed by Cygnus Support
460484Sobrien
533965SjdpThis file is free software; you can redistribute it and/or modify it
633965Sjdpunder the terms of the GNU General Public License as published by the
738889SjdpFree Software Foundation; either version 2, or (at your option) any
838889Sjdplater version.
938889Sjdp
1092828SobrienIn addition to the permissions in the GNU General Public License, the
1189857SobrienFree Software Foundation gives you unlimited permission to link the
1292828Sobriencompiled version of this file with other programs, and to distribute
1338889Sjdpthose programs without any restriction coming from the use of this
1489857Sobrienfile.  (The General Public License restrictions do apply in other
1589857Sobrienrespects; for example, they cover modification of the file, and
1689857Sobriendistribution when not linked into another program.)
1789857Sobrien
1889857SobrienThis file is distributed in the hope that it will be useful, but
1989857SobrienWITHOUT ANY WARRANTY; without even the implied warranty of
2089857SobrienMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
2189857SobrienGeneral Public License for more details.
2289857Sobrien
2389857SobrienYou should have received a copy of the GNU General Public License
2489857Sobrienalong with this program; see the file COPYING.  If not, write to
2589857Sobrienthe Free Software Foundation, 51 Franklin Street, Fifth Floor,
2689857SobrienBoston, MA 02110-1301, USA.  */
2789857Sobrien
2889857Sobrien/* As a special exception, if you link this library with other files,
2989857Sobrien   some of which are compiled with GCC, to produce an executable,
3089857Sobrien   this library does not by itself cause the resulting executable
3189857Sobrien   to be covered by the GNU General Public License.
3238889Sjdp   This exception does not however invalidate any other reasons why
3338889Sjdp   the executable file might be covered by the GNU General Public License.  */
3438889Sjdp
3538889Sjdp/* This file contains mips16 floating point support functions.  These
3638889Sjdp   functions are called by mips16 code to handle floating point when
3738889Sjdp   -msoft-float is not used.  They accept the arguments and return
3838889Sjdp   values using the soft-float calling convention, but do the actual
3938889Sjdp   operation using the hard floating point instructions.  */
4038889Sjdp
4138889Sjdp/* This file contains 32 bit assembly code.  */
4238889Sjdp	.set nomips16
4333965Sjdp
4433965Sjdp/* Start a function.  */
4533965Sjdp
4633965Sjdp#define STARTFN(NAME) .globl NAME; .ent NAME; NAME:
4733965Sjdp
4833965Sjdp/* Finish a function.  */
4933965Sjdp
5033965Sjdp#define ENDFN(NAME) .end NAME
5133965Sjdp
5233965Sjdp/* Single precision math.  */
5333965Sjdp
5433965Sjdp/* This macro defines a function which loads two single precision
5533965Sjdp   values, performs an operation, and returns the single precision
5633965Sjdp   result.  */
5733965Sjdp
5833965Sjdp#define SFOP(NAME, OPCODE)	\
5933965SjdpSTARTFN (NAME);			\
6033965Sjdp	.set	noreorder;	\
6133965Sjdp	mtc1	$4,$f0;		\
6233965Sjdp	mtc1	$5,$f2;		\
6333965Sjdp	nop;			\
6433965Sjdp	OPCODE	$f0,$f0,$f2;	\
6533965Sjdp	mfc1	$2,$f0;		\
6633965Sjdp	j	$31;		\
6733965Sjdp	nop;			\
6833965Sjdp	.set	reorder;	\
6933965Sjdp	ENDFN (NAME)
7033965Sjdp
7133965Sjdp#ifdef L_m16addsf3
7233965SjdpSFOP(__mips16_addsf3, add.s)
7389857Sobrien#endif
7477298Sobrien#ifdef L_m16subsf3
7577298SobrienSFOP(__mips16_subsf3, sub.s)
7677298Sobrien#endif
7777298Sobrien#ifdef L_m16mulsf3
7877298SobrienSFOP(__mips16_mulsf3, mul.s)
7977298Sobrien#endif
8077298Sobrien#ifdef L_m16divsf3
8177298SobrienSFOP(__mips16_divsf3, div.s)
8277298Sobrien#endif
8377298Sobrien
8477298Sobrien#define SFOP2(NAME, OPCODE)	\
8577298SobrienSTARTFN (NAME);			\
8677298Sobrien	.set	noreorder;	\
8777298Sobrien	mtc1	$4,$f0;		\
8877298Sobrien	nop;			\
8977298Sobrien	OPCODE	$f0,$f0;	\
9077298Sobrien	mfc1	$2,$f0;		\
9177298Sobrien	j	$31;		\
9277298Sobrien	nop;			\
9377298Sobrien	.set	reorder;	\
9438889Sjdp	ENDFN (NAME)
9533965Sjdp
9633965Sjdp#ifdef L_m16negsf2
9733965SjdpSFOP2(__mips16_negsf2, neg.s)
9833965Sjdp#endif
9933965Sjdp#ifdef L_m16abssf2
10038889SjdpSFOP2(__mips16_abssf2, abs.s)
10160484Sobrien#endif
10238889Sjdp
10333965Sjdp/* Single precision comparisons.  */
10433965Sjdp
10589857Sobrien/* This macro defines a function which loads two single precision
10633965Sjdp   values, performs a floating point comparison, and returns the
10733965Sjdp   specified values according to whether the comparison is true or
10833965Sjdp   false.  */
10933965Sjdp
11033965Sjdp#define SFCMP(NAME, OPCODE, TRUE, FALSE)	\
11189857SobrienSTARTFN (NAME);					\
11260484Sobrien	mtc1	$4,$f0;				\
11360484Sobrien	mtc1	$5,$f2;				\
11433965Sjdp	OPCODE	$f0,$f2;			\
11533965Sjdp	li	$2,TRUE;			\
11633965Sjdp	bc1t	1f;				\
11733965Sjdp	li	$2,FALSE;			\
11860484Sobrien1:;						\
11933965Sjdp	j	$31;				\
12033965Sjdp	ENDFN (NAME)
12133965Sjdp
12233965Sjdp/* This macro is like SFCMP, but it reverses the comparison.  */
12333965Sjdp
12433965Sjdp#define SFREVCMP(NAME, OPCODE, TRUE, FALSE)	\
12533965SjdpSTARTFN (NAME);					\
12633965Sjdp	mtc1	$4,$f0;				\
12733965Sjdp	mtc1	$5,$f2;				\
12833965Sjdp	OPCODE	$f2,$f0;			\
12933965Sjdp	li	$2,TRUE;			\
13033965Sjdp	bc1t	1f;				\
13133965Sjdp	li	$2,FALSE;			\
13233965Sjdp1:;						\
13333965Sjdp	j	$31;				\
13433965Sjdp	ENDFN (NAME)
13533965Sjdp
13633965Sjdp#ifdef L_m16eqsf2
13733965SjdpSFCMP(__mips16_eqsf2, c.eq.s, 0, 1)
13833965Sjdp#endif
13933965Sjdp#ifdef L_m16nesf2
14033965SjdpSFCMP(__mips16_nesf2, c.eq.s, 0, 1)
14160484Sobrien#endif
14260484Sobrien#ifdef L_m16gtsf2
14333965SjdpSFREVCMP(__mips16_gtsf2, c.lt.s, 1, 0)
14433965Sjdp#endif
14533965Sjdp#ifdef L_m16gesf2
14633965SjdpSFREVCMP(__mips16_gesf2, c.le.s, 0, -1)
14733965Sjdp#endif
14833965Sjdp#ifdef L_m16lesf2
14933965SjdpSFCMP(__mips16_lesf2, c.le.s, 0, 1)
15033965Sjdp#endif
15133965Sjdp#ifdef L_m16ltsf2
15233965SjdpSFCMP(__mips16_ltsf2, c.lt.s, -1, 0)
15333965Sjdp#endif
15433965Sjdp
15560484Sobrien/* Single precision conversions.  */
15633965Sjdp
15733965Sjdp#ifdef L_m16fltsisf
15877298SobrienSTARTFN (__mips16_floatsisf)
15977298Sobrien	.set	noreorder
16077298Sobrien	mtc1	$4,$f0
16138889Sjdp	nop
16238889Sjdp	cvt.s.w	$f0,$f0
16360484Sobrien	mfc1	$2,$f0
16433965Sjdp	j	$31
16538889Sjdp	nop
16638889Sjdp	.set	reorder
16777298Sobrien	ENDFN (__mips16_floatsisf)
16889857Sobrien#endif
16938889Sjdp
17038889Sjdp#ifdef L_m16fix_truncsfsi
17138889SjdpSTARTFN (__mips16_fix_truncsfsi)
17260484Sobrien	.set	noreorder
17338889Sjdp	mtc1	$4,$f0
17433965Sjdp	nop
17589857Sobrien	trunc.w.s $f0,$f0,$4
17660484Sobrien	mfc1	$2,$f0
17760484Sobrien	j	$31
17860484Sobrien	nop
17960484Sobrien	.set	reorder
18033965Sjdp	ENDFN (__mips16_fix_truncsfsi)
18133965Sjdp#endif
18233965Sjdp
18360484Sobrien#if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
18460484Sobrien
18533965Sjdp/* The double precision operations.  We need to use different code
18633965Sjdp   based on the preprocessor symbol __mips64, because the way in which
18733965Sjdp   double precision values will change.  Without __mips64, the value
18833965Sjdp   is passed in two 32 bit registers.  With __mips64, the value is
18933965Sjdp   passed in a single 64 bit register.  */
19038889Sjdp
19160484Sobrien/* Load the first double precision operand.  */
19233965Sjdp
19333965Sjdp#if defined(__mips64)
19489857Sobrien#define LDDBL1 dmtc1 $4,$f12
19589857Sobrien#elif defined(__mipsfp64)
19689857Sobrien#define LDDBL1 sw $4,0($29); sw $5,4($29); l.d $f12,0($29)
19789857Sobrien#elif defined(__MIPSEB__)
19889857Sobrien#define LDDBL1 mtc1 $4,$f13; mtc1 $5,$f12
19991041Sobrien#else
20033965Sjdp#define LDDBL1 mtc1 $4,$f12; mtc1 $5,$f13
20138889Sjdp#endif
20260484Sobrien
20333965Sjdp/* Load the second double precision operand.  */
20433965Sjdp
20577298Sobrien#if defined(__mips64)
20677298Sobrien/* XXX this should be $6 for Algo arg passing model */
20777298Sobrien#define LDDBL2 dmtc1 $5,$f14
20877298Sobrien#elif defined(__mipsfp64)
20977298Sobrien#define LDDBL2 sw $6,8($29); sw $7,12($29); l.d $f14,8($29)
21077298Sobrien#elif defined(__MIPSEB__)
21133965Sjdp#define LDDBL2 mtc1 $6,$f15; mtc1 $7,$f14
21233965Sjdp#else
21338889Sjdp#define LDDBL2 mtc1 $6,$f14; mtc1 $7,$f15
21433965Sjdp#endif
21533965Sjdp
21633965Sjdp/* Move the double precision return value to the right place.  */
21733965Sjdp
21838889Sjdp#if defined(__mips64)
21960484Sobrien#define RETDBL dmfc1 $2,$f0
22033965Sjdp#elif defined(__mipsfp64)
22133965Sjdp#define RETDBL s.d $f0,0($29); lw $2,0($29); lw $3,4($29)
22260484Sobrien#elif defined(__MIPSEB__)
22360484Sobrien#define RETDBL mfc1 $2,$f1; mfc1 $3,$f0
22460484Sobrien#else
22560484Sobrien#define RETDBL mfc1 $2,$f0; mfc1 $3,$f1
22660484Sobrien#endif
22733965Sjdp
22833965Sjdp/* Double precision math.  */
22938889Sjdp
23060484Sobrien/* This macro defines a function which loads two double precision
23133965Sjdp   values, performs an operation, and returns the double precision
23233965Sjdp   result.  */
23333965Sjdp
23433965Sjdp#define DFOP(NAME, OPCODE)	\
23538889SjdpSTARTFN (NAME);			\
23660484Sobrien	.set	noreorder;	\
23733965Sjdp	LDDBL1;			\
23833965Sjdp	LDDBL2;			\
23938889Sjdp	nop;			\
24033965Sjdp	OPCODE	$f0,$f12,$f14;	\
24138889Sjdp	RETDBL;			\
24260484Sobrien	j	$31;		\
24333965Sjdp	nop;			\
24433965Sjdp	.set	reorder;	\
24538889Sjdp	ENDFN (NAME)
24638889Sjdp
24733965Sjdp#ifdef L_m16adddf3
24833965SjdpDFOP(__mips16_adddf3, add.d)
24938889Sjdp#endif
25060484Sobrien#ifdef L_m16subdf3
25133965SjdpDFOP(__mips16_subdf3, sub.d)
25233965Sjdp#endif
25338889Sjdp#ifdef L_m16muldf3
25460484SobrienDFOP(__mips16_muldf3, mul.d)
25533965Sjdp#endif
25633965Sjdp#ifdef L_m16divdf3
25738889SjdpDFOP(__mips16_divdf3, div.d)
25860484Sobrien#endif
25933965Sjdp
26033965Sjdp#define DFOP2(NAME, OPCODE)	\
26138889SjdpSTARTFN (NAME);			\
26233965Sjdp	.set	noreorder;	\
26333965Sjdp	LDDBL1;			\
26438889Sjdp	nop;			\
26560484Sobrien	OPCODE	$f0,$f12;	\
26633965Sjdp	RETDBL;			\
26738889Sjdp	j	$31;		\
26838889Sjdp	nop;			\
26938889Sjdp	.set	reorder;	\
27033965Sjdp	ENDFN (NAME)
27138889Sjdp
27260484Sobrien#ifdef L_m16negdf2
27333965SjdpDFOP2(__mips16_negdf2, neg.d)
27433965Sjdp#endif
27533965Sjdp#ifdef L_m16absdf2
27638889SjdpDFOP2(__mips16_absdf2, abs.d)
27760484Sobrien#endif
27833965Sjdp
27933965Sjdp
28038889Sjdp/* Conversions between single and double precision.  */
28160484Sobrien
28233965Sjdp#ifdef L_m16extsfdf2
28333965SjdpSTARTFN (__mips16_extendsfdf2)
28438889Sjdp	.set	noreorder
28560484Sobrien	mtc1	$4,$f12
28633965Sjdp	nop
28738889Sjdp	cvt.d.s	$f0,$f12
28833965Sjdp	RETDBL
28938889Sjdp	j	$31
29060484Sobrien	nop
29133965Sjdp	.set	reorder
29238889Sjdp	ENDFN (__mips16_extendsfdf2)
29338889Sjdp#endif
29460484Sobrien
29533965Sjdp#ifdef L_m16trdfsf2
29633965SjdpSTARTFN (__mips16_truncdfsf2)
29738889Sjdp	.set	noreorder
29860484Sobrien	LDDBL1
29933965Sjdp	nop
30033965Sjdp	cvt.s.d	$f0,$f12
30138889Sjdp	mfc1	$2,$f0
30260484Sobrien	j	$31
30333965Sjdp	nop
30433965Sjdp	.set	reorder
30538889Sjdp	ENDFN (__mips16_truncdfsf2)
30633965Sjdp#endif
30733965Sjdp
30838889Sjdp/* Double precision comparisons.  */
30960484Sobrien
31033965Sjdp/* This macro defines a function which loads two double precision
31133965Sjdp   values, performs a floating point comparison, and returns the
31238889Sjdp   specified values according to whether the comparison is true or
31333965Sjdp   false.  */
31438889Sjdp
31560484Sobrien#define DFCMP(NAME, OPCODE, TRUE, FALSE)	\
31633965SjdpSTARTFN (NAME);					\
31733965Sjdp	LDDBL1;					\
31838889Sjdp	LDDBL2;					\
31960484Sobrien	OPCODE	$f12,$f14;			\
32033965Sjdp	li	$2,TRUE;			\
32133965Sjdp	bc1t	1f;				\
32238889Sjdp	li	$2,FALSE;			\
32333965Sjdp1:;						\
32438889Sjdp	j	$31;				\
32577298Sobrien	ENDFN (NAME)
32677298Sobrien
32777298Sobrien/* This macro is like DFCMP, but it reverses the comparison.  */
32877298Sobrien
32977298Sobrien#define DFREVCMP(NAME, OPCODE, TRUE, FALSE)	\
33077298SobrienSTARTFN (NAME);					\
33138889Sjdp	LDDBL1;					\
33238889Sjdp	LDDBL2;					\
33338889Sjdp	OPCODE	$f14,$f12;			\
33438889Sjdp	li	$2,TRUE;			\
33533965Sjdp	bc1t	1f;				\
33677298Sobrien	li	$2,FALSE;			\
33738889Sjdp1:;						\
33878828Sobrien	j	$31;				\
33989857Sobrien	ENDFN (NAME)
34089857Sobrien
34133965Sjdp#ifdef L_m16eqdf2
34238889SjdpDFCMP(__mips16_eqdf2, c.eq.d, 0, 1)
34333965Sjdp#endif
34433965Sjdp#ifdef L_m16nedf2
34538889SjdpDFCMP(__mips16_nedf2, c.eq.d, 0, 1)
34660484Sobrien#endif
34733965Sjdp#ifdef L_m16gtdf2
34833965SjdpDFREVCMP(__mips16_gtdf2, c.lt.d, 1, 0)
34938889Sjdp#endif
35060484Sobrien#ifdef L_m16gedf2
35133965SjdpDFREVCMP(__mips16_gedf2, c.le.d, 0, -1)
35233965Sjdp#endif
35338889Sjdp#ifdef L_m16ledf2
35460484SobrienDFCMP(__mips16_ledf2, c.le.d, 0, 1)
35533965Sjdp#endif
35633965Sjdp#ifdef L_m16ltdf2
35738889SjdpDFCMP(__mips16_ltdf2, c.lt.d, -1, 0)
35860484Sobrien#endif
35933965Sjdp
36089857Sobrien/* Double precision conversions.  */
36133965Sjdp
36233965Sjdp#ifdef L_m16fltsidf
36333965SjdpSTARTFN (__mips16_floatsidf)
36438889Sjdp	.set	noreorder
36538889Sjdp	mtc1	$4,$f12
36638889Sjdp	nop
36738889Sjdp	cvt.d.w	$f0,$f12
36838889Sjdp	RETDBL
36938889Sjdp	j	$31
37038889Sjdp	nop
37138889Sjdp	.set	reorder
37238889Sjdp	ENDFN (__mips16_floatsidf)
37360484Sobrien#endif
37438889Sjdp
37533965Sjdp#ifdef L_m16fix_truncdfsi
37633965SjdpSTARTFN (__mips16_fix_truncdfsi)
37760484Sobrien	.set	noreorder
37860484Sobrien	LDDBL1
37960484Sobrien	nop
38060484Sobrien	trunc.w.d $f0,$f12,$4
38160484Sobrien	mfc1	$2,$f0
38277298Sobrien	j	$31
38360484Sobrien	nop
38477298Sobrien	.set	reorder
38560484Sobrien	ENDFN (__mips16_fix_truncdfsi)
38677298Sobrien#endif
38777298Sobrien#endif /* !__mips_single_float */
38860484Sobrien
38977298Sobrien/* These functions are used to return floating point values from
39060484Sobrien   mips16 functions.  In this case we can put mtc1 in a jump delay slot,
39177298Sobrien   because we know that the next instruction will not refer to a floating
39260484Sobrien   point register.  */
39377298Sobrien
39460484Sobrien#ifdef L_m16retsf
39560484SobrienSTARTFN (__mips16_ret_sf)
39660484Sobrien	.set	noreorder
39733965Sjdp	j	$31
39833965Sjdp	mtc1	$2,$f0
39933965Sjdp	.set	reorder
40033965Sjdp	ENDFN (__mips16_ret_sf)
40177298Sobrien#endif
40277298Sobrien
40377298Sobrien#if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
40477298Sobrien#ifdef L_m16retdf
40533965SjdpSTARTFN (__mips16_ret_df)
40660484Sobrien	.set	noreorder
40760484Sobrien#if defined(__mips64)
40860484Sobrien	j	$31
40960484Sobrien	dmtc1	$2,$f0
41060484Sobrien#elif defined(__mipsfp64)
41160484Sobrien	sw	$2,0($29)
41260484Sobrien	sw	$3,4($29)
41360484Sobrien	l.d	$f0,0($29)
41460484Sobrien#elif defined(__MIPSEB__)
41560484Sobrien	mtc1	$2,$f1
41689857Sobrien	j	$31
41789857Sobrien	mtc1	$3,$f0
41889857Sobrien#else
41989857Sobrien	mtc1	$2,$f0
42089857Sobrien	j	$31
42189857Sobrien	mtc1	$3,$f1
42289857Sobrien#endif
42389857Sobrien	.set	reorder
42489857Sobrien	ENDFN (__mips16_ret_df)
42589857Sobrien#endif
42689857Sobrien#endif /* !__mips_single_float */
42792828Sobrien
42892828Sobrien/* These functions are used by 16 bit code when calling via a function
42992828Sobrien   pointer.  They must copy the floating point arguments from the gp
43092828Sobrien   regs into the fp regs.  The function to call will be in $2.  The
43189857Sobrien   exact set of floating point arguments to copy is encoded in the
43289857Sobrien   function name; the final number is an fp_code, as described in
43389857Sobrien   mips.h in the comment about CUMULATIVE_ARGS.  */
43489857Sobrien
43589857Sobrien#ifdef L_m16stub1
43660484Sobrien/* (float) */
43760484SobrienSTARTFN (__mips16_call_stub_1)
43860484Sobrien	.set	noreorder
43960484Sobrien	mtc1	$4,$f12
44033965Sjdp	j	$2
44133965Sjdp	nop
44233965Sjdp	.set	reorder
44333965Sjdp	ENDFN (__mips16_call_stub_1)
44433965Sjdp#endif
44533965Sjdp
44660484Sobrien#ifdef L_m16stub5
44733965Sjdp/* (float, float) */
44833965SjdpSTARTFN (__mips16_call_stub_5)
44933965Sjdp	.set	noreorder
45033965Sjdp	mtc1	$4,$f12
45133965Sjdp	mtc1	$5,$f14
45233965Sjdp	j	$2
45333965Sjdp	nop
45433965Sjdp	.set	reorder
45533965Sjdp	ENDFN (__mips16_call_stub_5)
45633965Sjdp#endif
45733965Sjdp
45833965Sjdp#if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
45933965Sjdp
46033965Sjdp#ifdef L_m16stub2
46133965Sjdp/* (double) */
46233965SjdpSTARTFN (__mips16_call_stub_2)
46333965Sjdp	.set	noreorder
46433965Sjdp	LDDBL1
46533965Sjdp	j	$2
46633965Sjdp	nop
46733965Sjdp	.set	reorder
46833965Sjdp	ENDFN (__mips16_call_stub_2)
46933965Sjdp#endif
47033965Sjdp
47133965Sjdp#ifdef L_m16stub6
47233965Sjdp/* (double, float) */
47333965SjdpSTARTFN (__mips16_call_stub_6)
47433965Sjdp	.set	noreorder
47533965Sjdp	LDDBL1
47633965Sjdp	mtc1	$6,$f14
47733965Sjdp	j	$2
47833965Sjdp	nop
47933965Sjdp	.set	reorder
48033965Sjdp	ENDFN (__mips16_call_stub_6)
48160484Sobrien#endif
48233965Sjdp
48333965Sjdp#ifdef L_m16stub9
48433965Sjdp/* (float, double) */
48533965SjdpSTARTFN (__mips16_call_stub_9)
48633965Sjdp	.set	noreorder
48733965Sjdp	mtc1	$4,$f12
48833965Sjdp	LDDBL2
48933965Sjdp	j	$2
49033965Sjdp	nop
49133965Sjdp	.set	reorder
49233965Sjdp	ENDFN (__mips16_call_stub_9)
49333965Sjdp#endif
49438889Sjdp
49533965Sjdp#ifdef L_m16stub10
49633965Sjdp/* (double, double) */
49733965SjdpSTARTFN (__mips16_call_stub_10)
49833965Sjdp	.set	noreorder
49933965Sjdp	LDDBL1
50033965Sjdp	LDDBL2
50133965Sjdp	j	$2
50233965Sjdp	nop
50333965Sjdp	.set	reorder
50433965Sjdp	ENDFN (__mips16_call_stub_10)
50533965Sjdp#endif
50633965Sjdp#endif /* !__mips_single_float */
50733965Sjdp
50889857Sobrien/* Now we have the same set of functions, except that this time the
50933965Sjdp   function being called returns an SFmode value.  The calling
51033965Sjdp   function will arrange to preserve $18, so these functions are free
51133965Sjdp   to use it to hold the return address.
51289857Sobrien
51333965Sjdp   Note that we do not know whether the function we are calling is 16
51433965Sjdp   bit or 32 bit.  However, it does not matter, because 16 bit
51589857Sobrien   functions always return floating point values in both the gp and
51689857Sobrien   the fp regs.  It would be possible to check whether the function
51791041Sobrien   being called is 16 bits, in which case the copy is unnecessary;
51891041Sobrien   however, it's faster to always do the copy.  */
51991041Sobrien
52091041Sobrien#ifdef L_m16stubsf0
52191041Sobrien/* () */
52291041SobrienSTARTFN (__mips16_call_stub_sf_0)
52391041Sobrien	.set	noreorder
52491041Sobrien	move	$18,$31
52591041Sobrien	jal	$2
52691041Sobrien	nop
52791041Sobrien	mfc1	$2,$f0
52838889Sjdp	j	$18
52938889Sjdp	nop
53038889Sjdp	.set	reorder
53138889Sjdp	ENDFN (__mips16_call_stub_sf_0)
53238889Sjdp#endif
53338889Sjdp
53438889Sjdp#ifdef L_m16stubsf1
53538889Sjdp/* (float) */
53689857SobrienSTARTFN (__mips16_call_stub_sf_1)
53789857Sobrien	.set	noreorder
53889857Sobrien	mtc1	$4,$f12
53989857Sobrien	move	$18,$31
54089857Sobrien	jal	$2
54189857Sobrien	nop
54289857Sobrien	mfc1	$2,$f0
54389857Sobrien	j	$18
54489857Sobrien	nop
54589857Sobrien	.set	reorder
54689857Sobrien	ENDFN (__mips16_call_stub_sf_1)
54738889Sjdp#endif
54838889Sjdp
54977298Sobrien#ifdef L_m16stubsf5
55089857Sobrien/* (float, float) */
55160484SobrienSTARTFN (__mips16_call_stub_sf_5)
55289857Sobrien	.set	noreorder
55338889Sjdp	mtc1	$4,$f12
55489857Sobrien	mtc1	$5,$f14
55560484Sobrien	move	$18,$31
55638889Sjdp	jal	$2
55777298Sobrien	nop
55838889Sjdp	mfc1	$2,$f0
55960484Sobrien	j	$18
56060484Sobrien	nop
56189857Sobrien	.set	reorder
56289857Sobrien	ENDFN (__mips16_call_stub_sf_5)
56389857Sobrien#endif
56460484Sobrien
56538889Sjdp#if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
56689857Sobrien#ifdef L_m16stubsf2
56738889Sjdp/* (double) */
56860484SobrienSTARTFN (__mips16_call_stub_sf_2)
56989857Sobrien	.set	noreorder
57089857Sobrien	LDDBL1
57138889Sjdp	move	$18,$31
57289857Sobrien	jal	$2
57389857Sobrien	nop
57489857Sobrien	mfc1	$2,$f0
57538889Sjdp	j	$18
57638889Sjdp	nop
57777298Sobrien	.set	reorder
57877298Sobrien	ENDFN (__mips16_call_stub_sf_2)
57938889Sjdp#endif
58038889Sjdp
58160484Sobrien#ifdef L_m16stubsf6
58260484Sobrien/* (double, float) */
58338889SjdpSTARTFN (__mips16_call_stub_sf_6)
58438889Sjdp	.set	noreorder
58589857Sobrien	LDDBL1
58691041Sobrien	mtc1	$6,$f14
58760484Sobrien	move	$18,$31
58860484Sobrien	jal	$2
58938889Sjdp	nop
59038889Sjdp	mfc1	$2,$f0
59189857Sobrien	j	$18
59238889Sjdp	nop
59389857Sobrien	.set	reorder
59438889Sjdp	ENDFN (__mips16_call_stub_sf_6)
59577298Sobrien#endif
59689857Sobrien
59789857Sobrien#ifdef L_m16stubsf9
59838889Sjdp/* (float, double) */
59977298SobrienSTARTFN (__mips16_call_stub_sf_9)
60077298Sobrien	.set	noreorder
60189857Sobrien	mtc1	$4,$f12
60238889Sjdp	LDDBL2
60389857Sobrien	move	$18,$31
60489857Sobrien	jal	$2
60589857Sobrien	nop
60689857Sobrien	mfc1	$2,$f0
60789857Sobrien	j	$18
60889857Sobrien	nop
60989857Sobrien	.set	reorder
61089857Sobrien	ENDFN (__mips16_call_stub_sf_9)
61189857Sobrien#endif
61289857Sobrien
61389857Sobrien#ifdef L_m16stubsf10
61489857Sobrien/* (double, double) */
61589857SobrienSTARTFN (__mips16_call_stub_sf_10)
61689857Sobrien	.set	noreorder
61789857Sobrien	LDDBL1
61889857Sobrien	LDDBL2
61989857Sobrien	move	$18,$31
62089857Sobrien	jal	$2
62189857Sobrien	nop
62289857Sobrien	mfc1	$2,$f0
62389857Sobrien	j	$18
62489857Sobrien	nop
62589857Sobrien	.set	reorder
62689857Sobrien	ENDFN (__mips16_call_stub_sf_10)
62789857Sobrien#endif
62889857Sobrien
62960484Sobrien/* Now we have the same set of functions again, except that this time
63060484Sobrien   the function being called returns an DFmode value.  */
63177298Sobrien
63289857Sobrien#ifdef L_m16stubdf0
63338889Sjdp/* () */
63489857SobrienSTARTFN (__mips16_call_stub_df_0)
63538889Sjdp	.set	noreorder
63689857Sobrien	move	$18,$31
63738889Sjdp	jal	$2
63838889Sjdp	nop
63938889Sjdp	RETDBL
64038889Sjdp	j	$18
64138889Sjdp	nop
64238889Sjdp	.set	reorder
64338889Sjdp	ENDFN (__mips16_call_stub_df_0)
64438889Sjdp#endif
64538889Sjdp
64638889Sjdp#ifdef L_m16stubdf1
64738889Sjdp/* (float) */
64838889SjdpSTARTFN (__mips16_call_stub_df_1)
64938889Sjdp	.set	noreorder
65038889Sjdp	mtc1	$4,$f12
65138889Sjdp	move	$18,$31
65238889Sjdp	jal	$2
65389857Sobrien	nop
65438889Sjdp	RETDBL
65538889Sjdp	j	$18
65689857Sobrien	nop
65789857Sobrien	.set	reorder
65838889Sjdp	ENDFN (__mips16_call_stub_df_1)
65938889Sjdp#endif
66038889Sjdp
66138889Sjdp#ifdef L_m16stubdf2
66289857Sobrien/* (double) */
66389857SobrienSTARTFN (__mips16_call_stub_df_2)
66438889Sjdp	.set	noreorder
66538889Sjdp	LDDBL1
66638889Sjdp	move	$18,$31
66738889Sjdp	jal	$2
66838889Sjdp	nop
66938889Sjdp	RETDBL
67038889Sjdp	j	$18
67138889Sjdp	nop
67260484Sobrien	.set	reorder
67360484Sobrien	ENDFN (__mips16_call_stub_df_2)
67460484Sobrien#endif
67560484Sobrien
67689857Sobrien#ifdef L_m16stubdf5
67789857Sobrien/* (float, float) */
67838889SjdpSTARTFN (__mips16_call_stub_df_5)
67989857Sobrien	.set	noreorder
68038889Sjdp	mtc1	$4,$f12
68189857Sobrien	mtc1	$5,$f14
68238889Sjdp	move	$18,$31
68391041Sobrien	jal	$2
68489857Sobrien	nop
68589857Sobrien	RETDBL
68689857Sobrien	j	$18
68789857Sobrien	nop
68889857Sobrien	.set	reorder
68938889Sjdp	ENDFN (__mips16_call_stub_df_5)
69089857Sobrien#endif
69138889Sjdp
69289857Sobrien#ifdef L_m16stubdf6
69338889Sjdp/* (double, float) */
69489857SobrienSTARTFN (__mips16_call_stub_df_6)
69538889Sjdp	.set	noreorder
69677298Sobrien	LDDBL1
69777298Sobrien	mtc1	$6,$f14
69838889Sjdp	move	$18,$31
69989857Sobrien	jal	$2
70038889Sjdp	nop
70138889Sjdp	RETDBL
70238889Sjdp	j	$18
70338889Sjdp	nop
70438889Sjdp	.set	reorder
70538889Sjdp	ENDFN (__mips16_call_stub_df_6)
70638889Sjdp#endif
70738889Sjdp
70838889Sjdp#ifdef L_m16stubdf9
70938889Sjdp/* (float, double) */
71038889SjdpSTARTFN (__mips16_call_stub_df_9)
71189857Sobrien	.set	noreorder
71277298Sobrien	mtc1	$4,$f12
71389857Sobrien	LDDBL2
71477298Sobrien	move	$18,$31
71589857Sobrien	jal	$2
71677298Sobrien	nop
71760484Sobrien	RETDBL
71860484Sobrien	j	$18
71989857Sobrien	nop
72060484Sobrien	.set	reorder
72160484Sobrien	ENDFN (__mips16_call_stub_df_9)
72238889Sjdp#endif
72338889Sjdp
72433965Sjdp#ifdef L_m16stubdf10
72533965Sjdp/* (double, double) */
72633965SjdpSTARTFN (__mips16_call_stub_df_10)
72733965Sjdp	.set	noreorder
72889857Sobrien	LDDBL1
72989857Sobrien	LDDBL2
73089857Sobrien	move	$18,$31
73189857Sobrien	jal	$2
73289857Sobrien	nop
73389857Sobrien	RETDBL
73489857Sobrien	j	$18
73533965Sjdp	nop
73633965Sjdp	.set	reorder
73733965Sjdp	ENDFN (__mips16_call_stub_df_10)
73833965Sjdp#endif
73933965Sjdp#endif /* !__mips_single_float */
74038889Sjdp