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