1/* mips16 floating point support code 2 Copyright (C) 1996-2021 Free Software Foundation, Inc. 3 Contributed by Cygnus Support 4 5This file is free software; you can redistribute it and/or modify it 6under the terms of the GNU General Public License as published by the 7Free Software Foundation; either version 3, or (at your option) any 8later version. 9 10This file is distributed in the hope that it will be useful, but 11WITHOUT ANY WARRANTY; without even the implied warranty of 12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13General Public License for more details. 14 15Under Section 7 of GPL version 3, you are granted additional 16permissions described in the GCC Runtime Library Exception, version 173.1, as published by the Free Software Foundation. 18 19You should have received a copy of the GNU General Public License and 20a copy of the GCC Runtime Library Exception along with this program; 21see 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) \ 234STARTFN (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 242OPSF3 (__mips16_addsf3, add.s) 243#endif 244#ifdef L_m16subsf3 245OPSF3 (__mips16_subsf3, sub.s) 246#endif 247#ifdef L_m16mulsf3 248OPSF3 (__mips16_mulsf3, mul.s) 249#endif 250#ifdef L_m16divsf3 251OPSF3 (__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) \ 259STARTFN (NAME); \ 260 MOVE_SF_BYTE0 (t); \ 261 OPCODE RET,ARG1; \ 262 MOVE_SF_RET (f, $31); \ 263 ENDFN (NAME) 264 265#ifdef L_m16negsf2 266OPSF2 (__mips16_negsf2, neg.s) 267#endif 268#ifdef L_m16abssf2 269OPSF2 (__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) \ 279STARTFN (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; \ 2861:; \ 287 j $31; \ 288 ENDFN (NAME) 289 290/* Like CMPSF, but reverse the comparison operands. */ 291 292#define REVCMPSF(NAME, OPCODE, TRUE, FALSE) \ 293STARTFN (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; \ 3001:; \ 301 j $31; \ 302 ENDFN (NAME) 303 304#ifdef L_m16eqsf2 305CMPSF (__mips16_eqsf2, c.eq.s, 0, 1) 306#endif 307#ifdef L_m16nesf2 308CMPSF (__mips16_nesf2, c.eq.s, 0, 1) 309#endif 310#ifdef L_m16gtsf2 311REVCMPSF (__mips16_gtsf2, c.lt.s, 1, 0) 312#endif 313#ifdef L_m16gesf2 314REVCMPSF (__mips16_gesf2, c.le.s, 0, -1) 315#endif 316#ifdef L_m16lesf2 317CMPSF (__mips16_lesf2, c.le.s, 0, 1) 318#endif 319#ifdef L_m16ltsf2 320CMPSF (__mips16_ltsf2, c.lt.s, -1, 0) 321#endif 322#ifdef L_m16unordsf2 323CMPSF(__mips16_unordsf2, c.un.s, 1, 0) 324#endif 325 326 327/* Single-precision conversions. */ 328 329#ifdef L_m16fltsisf 330STARTFN (__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 338STARTFN (__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) 3451: 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 357STARTFN (__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) \ 373STARTFN (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 381OPDF3 (__mips16_adddf3, add.d) 382#endif 383#ifdef L_m16subdf3 384OPDF3 (__mips16_subdf3, sub.d) 385#endif 386#ifdef L_m16muldf3 387OPDF3 (__mips16_muldf3, mul.d) 388#endif 389#ifdef L_m16divdf3 390OPDF3 (__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) \ 398STARTFN (NAME); \ 399 MOVE_DF_BYTE0 (t); \ 400 OPCODE RET,ARG1; \ 401 MOVE_DF_RET (f, $31); \ 402 ENDFN (NAME) 403 404#ifdef L_m16negdf2 405OPDF2 (__mips16_negdf2, neg.d) 406#endif 407#ifdef L_m16absdf2 408OPDF2 (__mips16_absdf2, abs.d) 409#endif 410 411/* Conversions between single and double precision. */ 412 413#ifdef L_m16extsfdf2 414STARTFN (__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 422STARTFN (__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) \ 436STARTFN (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; \ 4431:; \ 444 j $31; \ 445 ENDFN (NAME) 446 447/* Like CMPDF, but reverse the comparison operands. */ 448 449#define REVCMPDF(NAME, OPCODE, TRUE, FALSE) \ 450STARTFN (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; \ 4571:; \ 458 j $31; \ 459 ENDFN (NAME) 460 461#ifdef L_m16eqdf2 462CMPDF (__mips16_eqdf2, c.eq.d, 0, 1) 463#endif 464#ifdef L_m16nedf2 465CMPDF (__mips16_nedf2, c.eq.d, 0, 1) 466#endif 467#ifdef L_m16gtdf2 468REVCMPDF (__mips16_gtdf2, c.lt.d, 1, 0) 469#endif 470#ifdef L_m16gedf2 471REVCMPDF (__mips16_gedf2, c.le.d, 0, -1) 472#endif 473#ifdef L_m16ledf2 474CMPDF (__mips16_ledf2, c.le.d, 0, 1) 475#endif 476#ifdef L_m16ltdf2 477CMPDF (__mips16_ltdf2, c.lt.d, -1, 0) 478#endif 479#ifdef L_m16unorddf2 480CMPDF(__mips16_unorddf2, c.un.d, 1, 0) 481#endif 482 483/* Double-precision conversions. */ 484 485#ifdef L_m16fltsidf 486STARTFN (__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 494STARTFN (__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 5001: MOVE_DF_RET (f, $31) 501 ENDFN (__mips16_floatunsidf) 502#endif 503 504#ifdef L_m16fix_truncdfsi 505STARTFN (__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) \ 525STARTFN (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) \ 530STARTFN (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) \ 539CE_STARTFN (NAME); \ 540 MOVE_##MODE##_RET (t, $31); \ 541 CE_ENDFN (NAME) 542 543#ifdef L_m16retsf 544RET_FUNCTION (__mips16_ret_sf, SF) 545#endif 546 547#ifdef L_m16retsc 548RET_FUNCTION (__mips16_ret_sc, SC) 549#endif 550 551#if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT) 552#ifdef L_m16retdf 553RET_FUNCTION (__mips16_ret_df, DF) 554#endif 555 556#ifdef L_m16retdc 557RET_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) \ 582CE_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 591CALL_STUB_NO_RET (__mips16_call_stub_1, 1) 592#endif 593 594#ifdef L_m16stub5 595CALL_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 601CALL_STUB_NO_RET (__mips16_call_stub_2, 2) 602#endif 603 604#ifdef L_m16stub6 605CALL_STUB_NO_RET (__mips16_call_stub_6, 6) 606#endif 607 608#ifdef L_m16stub9 609CALL_STUB_NO_RET (__mips16_call_stub_9, 9) 610#endif 611 612#ifdef L_m16stub10 613CALL_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) \ 631CE_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 652CALL_STUB_RET (__mips16_call_stub_sf_0, 0, SF) 653#endif 654 655#ifdef L_m16stubsf1 656CALL_STUB_RET (__mips16_call_stub_sf_1, 1, SF) 657#endif 658 659#ifdef L_m16stubsf5 660CALL_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 665CALL_STUB_RET (__mips16_call_stub_sf_2, 2, SF) 666#endif 667 668#ifdef L_m16stubsf6 669CALL_STUB_RET (__mips16_call_stub_sf_6, 6, SF) 670#endif 671 672#ifdef L_m16stubsf9 673CALL_STUB_RET (__mips16_call_stub_sf_9, 9, SF) 674#endif 675 676#ifdef L_m16stubsf10 677CALL_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 687CALL_STUB_RET (__mips16_call_stub_df_0, 0, DF) 688#endif 689 690#ifdef L_m16stubdf1 691CALL_STUB_RET (__mips16_call_stub_df_1, 1, DF) 692#endif 693 694#ifdef L_m16stubdf5 695CALL_STUB_RET (__mips16_call_stub_df_5, 5, DF) 696#endif 697 698#ifdef L_m16stubdf2 699CALL_STUB_RET (__mips16_call_stub_df_2, 2, DF) 700#endif 701 702#ifdef L_m16stubdf6 703CALL_STUB_RET (__mips16_call_stub_df_6, 6, DF) 704#endif 705 706#ifdef L_m16stubdf9 707CALL_STUB_RET (__mips16_call_stub_df_9, 9, DF) 708#endif 709 710#ifdef L_m16stubdf10 711CALL_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 720CALL_STUB_RET (__mips16_call_stub_sc_0, 0, SC) 721#endif 722 723#ifdef L_m16stubsc1 724CALL_STUB_RET (__mips16_call_stub_sc_1, 1, SC) 725#endif 726 727#ifdef L_m16stubsc5 728CALL_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 733CALL_STUB_RET (__mips16_call_stub_sc_2, 2, SC) 734#endif 735 736#ifdef L_m16stubsc6 737CALL_STUB_RET (__mips16_call_stub_sc_6, 6, SC) 738#endif 739 740#ifdef L_m16stubsc9 741CALL_STUB_RET (__mips16_call_stub_sc_9, 9, SC) 742#endif 743 744#ifdef L_m16stubsc10 745CALL_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 754CALL_STUB_RET (__mips16_call_stub_dc_0, 0, DC) 755#endif 756 757#ifdef L_m16stubdc1 758CALL_STUB_RET (__mips16_call_stub_dc_1, 1, DC) 759#endif 760 761#ifdef L_m16stubdc5 762CALL_STUB_RET (__mips16_call_stub_dc_5, 5, DC) 763#endif 764 765#ifdef L_m16stubdc2 766CALL_STUB_RET (__mips16_call_stub_dc_2, 2, DC) 767#endif 768 769#ifdef L_m16stubdc6 770CALL_STUB_RET (__mips16_call_stub_dc_6, 6, DC) 771#endif 772 773#ifdef L_m16stubdc9 774CALL_STUB_RET (__mips16_call_stub_dc_9, 9, DC) 775#endif 776 777#ifdef L_m16stubdc10 778CALL_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