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