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