1/* mips16 floating point support code 2 Copyright (C) 1996, 1997, 1998 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 2, or (at your option) any 8later version. 9 10In addition to the permissions in the GNU General Public License, the 11Free Software Foundation gives you unlimited permission to link the 12compiled version of this file with other programs, and to distribute 13those programs without any restriction coming from the use of this 14file. (The General Public License restrictions do apply in other 15respects; for example, they cover modification of the file, and 16distribution when not linked into another program.) 17 18This file is distributed in the hope that it will be useful, but 19WITHOUT ANY WARRANTY; without even the implied warranty of 20MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21General Public License for more details. 22 23You should have received a copy of the GNU General Public License 24along with this program; see the file COPYING. If not, write to 25the Free Software Foundation, 51 Franklin Street, Fifth Floor, 26Boston, MA 02110-1301, USA. */ 27 28/* As a special exception, if you link this library with other files, 29 some of which are compiled with GCC, to produce an executable, 30 this library does not by itself cause the resulting executable 31 to be covered by the GNU General Public License. 32 This exception does not however invalidate any other reasons why 33 the executable file might be covered by the GNU General Public License. */ 34 35/* This file contains mips16 floating point support functions. These 36 functions are called by mips16 code to handle floating point when 37 -msoft-float is not used. They accept the arguments and return 38 values using the soft-float calling convention, but do the actual 39 operation using the hard floating point instructions. */ 40 41/* This file contains 32 bit assembly code. */ 42 .set nomips16 43 44/* Start a function. */ 45 46#define STARTFN(NAME) .globl NAME; .ent NAME; NAME: 47 48/* Finish a function. */ 49 50#define ENDFN(NAME) .end NAME 51 52/* Single precision math. */ 53 54/* This macro defines a function which loads two single precision 55 values, performs an operation, and returns the single precision 56 result. */ 57 58#define SFOP(NAME, OPCODE) \ 59STARTFN (NAME); \ 60 .set noreorder; \ 61 mtc1 $4,$f0; \ 62 mtc1 $5,$f2; \ 63 nop; \ 64 OPCODE $f0,$f0,$f2; \ 65 mfc1 $2,$f0; \ 66 j $31; \ 67 nop; \ 68 .set reorder; \ 69 ENDFN (NAME) 70 71#ifdef L_m16addsf3 72SFOP(__mips16_addsf3, add.s) 73#endif 74#ifdef L_m16subsf3 75SFOP(__mips16_subsf3, sub.s) 76#endif 77#ifdef L_m16mulsf3 78SFOP(__mips16_mulsf3, mul.s) 79#endif 80#ifdef L_m16divsf3 81SFOP(__mips16_divsf3, div.s) 82#endif 83 84#define SFOP2(NAME, OPCODE) \ 85STARTFN (NAME); \ 86 .set noreorder; \ 87 mtc1 $4,$f0; \ 88 nop; \ 89 OPCODE $f0,$f0; \ 90 mfc1 $2,$f0; \ 91 j $31; \ 92 nop; \ 93 .set reorder; \ 94 ENDFN (NAME) 95 96#ifdef L_m16negsf2 97SFOP2(__mips16_negsf2, neg.s) 98#endif 99#ifdef L_m16abssf2 100SFOP2(__mips16_abssf2, abs.s) 101#endif 102 103/* Single precision comparisons. */ 104 105/* This macro defines a function which loads two single precision 106 values, performs a floating point comparison, and returns the 107 specified values according to whether the comparison is true or 108 false. */ 109 110#define SFCMP(NAME, OPCODE, TRUE, FALSE) \ 111STARTFN (NAME); \ 112 mtc1 $4,$f0; \ 113 mtc1 $5,$f2; \ 114 OPCODE $f0,$f2; \ 115 li $2,TRUE; \ 116 bc1t 1f; \ 117 li $2,FALSE; \ 1181:; \ 119 j $31; \ 120 ENDFN (NAME) 121 122/* This macro is like SFCMP, but it reverses the comparison. */ 123 124#define SFREVCMP(NAME, OPCODE, TRUE, FALSE) \ 125STARTFN (NAME); \ 126 mtc1 $4,$f0; \ 127 mtc1 $5,$f2; \ 128 OPCODE $f2,$f0; \ 129 li $2,TRUE; \ 130 bc1t 1f; \ 131 li $2,FALSE; \ 1321:; \ 133 j $31; \ 134 ENDFN (NAME) 135 136#ifdef L_m16eqsf2 137SFCMP(__mips16_eqsf2, c.eq.s, 0, 1) 138#endif 139#ifdef L_m16nesf2 140SFCMP(__mips16_nesf2, c.eq.s, 0, 1) 141#endif 142#ifdef L_m16gtsf2 143SFREVCMP(__mips16_gtsf2, c.lt.s, 1, 0) 144#endif 145#ifdef L_m16gesf2 146SFREVCMP(__mips16_gesf2, c.le.s, 0, -1) 147#endif 148#ifdef L_m16lesf2 149SFCMP(__mips16_lesf2, c.le.s, 0, 1) 150#endif 151#ifdef L_m16ltsf2 152SFCMP(__mips16_ltsf2, c.lt.s, -1, 0) 153#endif 154 155/* Single precision conversions. */ 156 157#ifdef L_m16fltsisf 158STARTFN (__mips16_floatsisf) 159 .set noreorder 160 mtc1 $4,$f0 161 nop 162 cvt.s.w $f0,$f0 163 mfc1 $2,$f0 164 j $31 165 nop 166 .set reorder 167 ENDFN (__mips16_floatsisf) 168#endif 169 170#ifdef L_m16fix_truncsfsi 171STARTFN (__mips16_fix_truncsfsi) 172 .set noreorder 173 mtc1 $4,$f0 174 nop 175 trunc.w.s $f0,$f0,$4 176 mfc1 $2,$f0 177 j $31 178 nop 179 .set reorder 180 ENDFN (__mips16_fix_truncsfsi) 181#endif 182 183#if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT) 184 185/* The double precision operations. We need to use different code 186 based on the preprocessor symbol __mips64, because the way in which 187 double precision values will change. Without __mips64, the value 188 is passed in two 32 bit registers. With __mips64, the value is 189 passed in a single 64 bit register. */ 190 191/* Load the first double precision operand. */ 192 193#if defined(__mips64) 194#define LDDBL1 dmtc1 $4,$f12 195#elif defined(__mipsfp64) 196#define LDDBL1 sw $4,0($29); sw $5,4($29); l.d $f12,0($29) 197#elif defined(__MIPSEB__) 198#define LDDBL1 mtc1 $4,$f13; mtc1 $5,$f12 199#else 200#define LDDBL1 mtc1 $4,$f12; mtc1 $5,$f13 201#endif 202 203/* Load the second double precision operand. */ 204 205#if defined(__mips64) 206/* XXX this should be $6 for Algo arg passing model */ 207#define LDDBL2 dmtc1 $5,$f14 208#elif defined(__mipsfp64) 209#define LDDBL2 sw $6,8($29); sw $7,12($29); l.d $f14,8($29) 210#elif defined(__MIPSEB__) 211#define LDDBL2 mtc1 $6,$f15; mtc1 $7,$f14 212#else 213#define LDDBL2 mtc1 $6,$f14; mtc1 $7,$f15 214#endif 215 216/* Move the double precision return value to the right place. */ 217 218#if defined(__mips64) 219#define RETDBL dmfc1 $2,$f0 220#elif defined(__mipsfp64) 221#define RETDBL s.d $f0,0($29); lw $2,0($29); lw $3,4($29) 222#elif defined(__MIPSEB__) 223#define RETDBL mfc1 $2,$f1; mfc1 $3,$f0 224#else 225#define RETDBL mfc1 $2,$f0; mfc1 $3,$f1 226#endif 227 228/* Double precision math. */ 229 230/* This macro defines a function which loads two double precision 231 values, performs an operation, and returns the double precision 232 result. */ 233 234#define DFOP(NAME, OPCODE) \ 235STARTFN (NAME); \ 236 .set noreorder; \ 237 LDDBL1; \ 238 LDDBL2; \ 239 nop; \ 240 OPCODE $f0,$f12,$f14; \ 241 RETDBL; \ 242 j $31; \ 243 nop; \ 244 .set reorder; \ 245 ENDFN (NAME) 246 247#ifdef L_m16adddf3 248DFOP(__mips16_adddf3, add.d) 249#endif 250#ifdef L_m16subdf3 251DFOP(__mips16_subdf3, sub.d) 252#endif 253#ifdef L_m16muldf3 254DFOP(__mips16_muldf3, mul.d) 255#endif 256#ifdef L_m16divdf3 257DFOP(__mips16_divdf3, div.d) 258#endif 259 260#define DFOP2(NAME, OPCODE) \ 261STARTFN (NAME); \ 262 .set noreorder; \ 263 LDDBL1; \ 264 nop; \ 265 OPCODE $f0,$f12; \ 266 RETDBL; \ 267 j $31; \ 268 nop; \ 269 .set reorder; \ 270 ENDFN (NAME) 271 272#ifdef L_m16negdf2 273DFOP2(__mips16_negdf2, neg.d) 274#endif 275#ifdef L_m16absdf2 276DFOP2(__mips16_absdf2, abs.d) 277#endif 278 279 280/* Conversions between single and double precision. */ 281 282#ifdef L_m16extsfdf2 283STARTFN (__mips16_extendsfdf2) 284 .set noreorder 285 mtc1 $4,$f12 286 nop 287 cvt.d.s $f0,$f12 288 RETDBL 289 j $31 290 nop 291 .set reorder 292 ENDFN (__mips16_extendsfdf2) 293#endif 294 295#ifdef L_m16trdfsf2 296STARTFN (__mips16_truncdfsf2) 297 .set noreorder 298 LDDBL1 299 nop 300 cvt.s.d $f0,$f12 301 mfc1 $2,$f0 302 j $31 303 nop 304 .set reorder 305 ENDFN (__mips16_truncdfsf2) 306#endif 307 308/* Double precision comparisons. */ 309 310/* This macro defines a function which loads two double precision 311 values, performs a floating point comparison, and returns the 312 specified values according to whether the comparison is true or 313 false. */ 314 315#define DFCMP(NAME, OPCODE, TRUE, FALSE) \ 316STARTFN (NAME); \ 317 LDDBL1; \ 318 LDDBL2; \ 319 OPCODE $f12,$f14; \ 320 li $2,TRUE; \ 321 bc1t 1f; \ 322 li $2,FALSE; \ 3231:; \ 324 j $31; \ 325 ENDFN (NAME) 326 327/* This macro is like DFCMP, but it reverses the comparison. */ 328 329#define DFREVCMP(NAME, OPCODE, TRUE, FALSE) \ 330STARTFN (NAME); \ 331 LDDBL1; \ 332 LDDBL2; \ 333 OPCODE $f14,$f12; \ 334 li $2,TRUE; \ 335 bc1t 1f; \ 336 li $2,FALSE; \ 3371:; \ 338 j $31; \ 339 ENDFN (NAME) 340 341#ifdef L_m16eqdf2 342DFCMP(__mips16_eqdf2, c.eq.d, 0, 1) 343#endif 344#ifdef L_m16nedf2 345DFCMP(__mips16_nedf2, c.eq.d, 0, 1) 346#endif 347#ifdef L_m16gtdf2 348DFREVCMP(__mips16_gtdf2, c.lt.d, 1, 0) 349#endif 350#ifdef L_m16gedf2 351DFREVCMP(__mips16_gedf2, c.le.d, 0, -1) 352#endif 353#ifdef L_m16ledf2 354DFCMP(__mips16_ledf2, c.le.d, 0, 1) 355#endif 356#ifdef L_m16ltdf2 357DFCMP(__mips16_ltdf2, c.lt.d, -1, 0) 358#endif 359 360/* Double precision conversions. */ 361 362#ifdef L_m16fltsidf 363STARTFN (__mips16_floatsidf) 364 .set noreorder 365 mtc1 $4,$f12 366 nop 367 cvt.d.w $f0,$f12 368 RETDBL 369 j $31 370 nop 371 .set reorder 372 ENDFN (__mips16_floatsidf) 373#endif 374 375#ifdef L_m16fix_truncdfsi 376STARTFN (__mips16_fix_truncdfsi) 377 .set noreorder 378 LDDBL1 379 nop 380 trunc.w.d $f0,$f12,$4 381 mfc1 $2,$f0 382 j $31 383 nop 384 .set reorder 385 ENDFN (__mips16_fix_truncdfsi) 386#endif 387#endif /* !__mips_single_float */ 388 389/* These functions are used to return floating point values from 390 mips16 functions. In this case we can put mtc1 in a jump delay slot, 391 because we know that the next instruction will not refer to a floating 392 point register. */ 393 394#ifdef L_m16retsf 395STARTFN (__mips16_ret_sf) 396 .set noreorder 397 j $31 398 mtc1 $2,$f0 399 .set reorder 400 ENDFN (__mips16_ret_sf) 401#endif 402 403#if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT) 404#ifdef L_m16retdf 405STARTFN (__mips16_ret_df) 406 .set noreorder 407#if defined(__mips64) 408 j $31 409 dmtc1 $2,$f0 410#elif defined(__mipsfp64) 411 sw $2,0($29) 412 sw $3,4($29) 413 l.d $f0,0($29) 414#elif defined(__MIPSEB__) 415 mtc1 $2,$f1 416 j $31 417 mtc1 $3,$f0 418#else 419 mtc1 $2,$f0 420 j $31 421 mtc1 $3,$f1 422#endif 423 .set reorder 424 ENDFN (__mips16_ret_df) 425#endif 426#endif /* !__mips_single_float */ 427 428/* These functions are used by 16 bit code when calling via a function 429 pointer. They must copy the floating point arguments from the gp 430 regs into the fp regs. The function to call will be in $2. The 431 exact set of floating point arguments to copy is encoded in the 432 function name; the final number is an fp_code, as described in 433 mips.h in the comment about CUMULATIVE_ARGS. */ 434 435#ifdef L_m16stub1 436/* (float) */ 437STARTFN (__mips16_call_stub_1) 438 .set noreorder 439 mtc1 $4,$f12 440 j $2 441 nop 442 .set reorder 443 ENDFN (__mips16_call_stub_1) 444#endif 445 446#ifdef L_m16stub5 447/* (float, float) */ 448STARTFN (__mips16_call_stub_5) 449 .set noreorder 450 mtc1 $4,$f12 451 mtc1 $5,$f14 452 j $2 453 nop 454 .set reorder 455 ENDFN (__mips16_call_stub_5) 456#endif 457 458#if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT) 459 460#ifdef L_m16stub2 461/* (double) */ 462STARTFN (__mips16_call_stub_2) 463 .set noreorder 464 LDDBL1 465 j $2 466 nop 467 .set reorder 468 ENDFN (__mips16_call_stub_2) 469#endif 470 471#ifdef L_m16stub6 472/* (double, float) */ 473STARTFN (__mips16_call_stub_6) 474 .set noreorder 475 LDDBL1 476 mtc1 $6,$f14 477 j $2 478 nop 479 .set reorder 480 ENDFN (__mips16_call_stub_6) 481#endif 482 483#ifdef L_m16stub9 484/* (float, double) */ 485STARTFN (__mips16_call_stub_9) 486 .set noreorder 487 mtc1 $4,$f12 488 LDDBL2 489 j $2 490 nop 491 .set reorder 492 ENDFN (__mips16_call_stub_9) 493#endif 494 495#ifdef L_m16stub10 496/* (double, double) */ 497STARTFN (__mips16_call_stub_10) 498 .set noreorder 499 LDDBL1 500 LDDBL2 501 j $2 502 nop 503 .set reorder 504 ENDFN (__mips16_call_stub_10) 505#endif 506#endif /* !__mips_single_float */ 507 508/* Now we have the same set of functions, except that this time the 509 function being called returns an SFmode value. The calling 510 function will arrange to preserve $18, so these functions are free 511 to use it to hold the return address. 512 513 Note that we do not know whether the function we are calling is 16 514 bit or 32 bit. However, it does not matter, because 16 bit 515 functions always return floating point values in both the gp and 516 the fp regs. It would be possible to check whether the function 517 being called is 16 bits, in which case the copy is unnecessary; 518 however, it's faster to always do the copy. */ 519 520#ifdef L_m16stubsf0 521/* () */ 522STARTFN (__mips16_call_stub_sf_0) 523 .set noreorder 524 move $18,$31 525 jal $2 526 nop 527 mfc1 $2,$f0 528 j $18 529 nop 530 .set reorder 531 ENDFN (__mips16_call_stub_sf_0) 532#endif 533 534#ifdef L_m16stubsf1 535/* (float) */ 536STARTFN (__mips16_call_stub_sf_1) 537 .set noreorder 538 mtc1 $4,$f12 539 move $18,$31 540 jal $2 541 nop 542 mfc1 $2,$f0 543 j $18 544 nop 545 .set reorder 546 ENDFN (__mips16_call_stub_sf_1) 547#endif 548 549#ifdef L_m16stubsf5 550/* (float, float) */ 551STARTFN (__mips16_call_stub_sf_5) 552 .set noreorder 553 mtc1 $4,$f12 554 mtc1 $5,$f14 555 move $18,$31 556 jal $2 557 nop 558 mfc1 $2,$f0 559 j $18 560 nop 561 .set reorder 562 ENDFN (__mips16_call_stub_sf_5) 563#endif 564 565#if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT) 566#ifdef L_m16stubsf2 567/* (double) */ 568STARTFN (__mips16_call_stub_sf_2) 569 .set noreorder 570 LDDBL1 571 move $18,$31 572 jal $2 573 nop 574 mfc1 $2,$f0 575 j $18 576 nop 577 .set reorder 578 ENDFN (__mips16_call_stub_sf_2) 579#endif 580 581#ifdef L_m16stubsf6 582/* (double, float) */ 583STARTFN (__mips16_call_stub_sf_6) 584 .set noreorder 585 LDDBL1 586 mtc1 $6,$f14 587 move $18,$31 588 jal $2 589 nop 590 mfc1 $2,$f0 591 j $18 592 nop 593 .set reorder 594 ENDFN (__mips16_call_stub_sf_6) 595#endif 596 597#ifdef L_m16stubsf9 598/* (float, double) */ 599STARTFN (__mips16_call_stub_sf_9) 600 .set noreorder 601 mtc1 $4,$f12 602 LDDBL2 603 move $18,$31 604 jal $2 605 nop 606 mfc1 $2,$f0 607 j $18 608 nop 609 .set reorder 610 ENDFN (__mips16_call_stub_sf_9) 611#endif 612 613#ifdef L_m16stubsf10 614/* (double, double) */ 615STARTFN (__mips16_call_stub_sf_10) 616 .set noreorder 617 LDDBL1 618 LDDBL2 619 move $18,$31 620 jal $2 621 nop 622 mfc1 $2,$f0 623 j $18 624 nop 625 .set reorder 626 ENDFN (__mips16_call_stub_sf_10) 627#endif 628 629/* Now we have the same set of functions again, except that this time 630 the function being called returns an DFmode value. */ 631 632#ifdef L_m16stubdf0 633/* () */ 634STARTFN (__mips16_call_stub_df_0) 635 .set noreorder 636 move $18,$31 637 jal $2 638 nop 639 RETDBL 640 j $18 641 nop 642 .set reorder 643 ENDFN (__mips16_call_stub_df_0) 644#endif 645 646#ifdef L_m16stubdf1 647/* (float) */ 648STARTFN (__mips16_call_stub_df_1) 649 .set noreorder 650 mtc1 $4,$f12 651 move $18,$31 652 jal $2 653 nop 654 RETDBL 655 j $18 656 nop 657 .set reorder 658 ENDFN (__mips16_call_stub_df_1) 659#endif 660 661#ifdef L_m16stubdf2 662/* (double) */ 663STARTFN (__mips16_call_stub_df_2) 664 .set noreorder 665 LDDBL1 666 move $18,$31 667 jal $2 668 nop 669 RETDBL 670 j $18 671 nop 672 .set reorder 673 ENDFN (__mips16_call_stub_df_2) 674#endif 675 676#ifdef L_m16stubdf5 677/* (float, float) */ 678STARTFN (__mips16_call_stub_df_5) 679 .set noreorder 680 mtc1 $4,$f12 681 mtc1 $5,$f14 682 move $18,$31 683 jal $2 684 nop 685 RETDBL 686 j $18 687 nop 688 .set reorder 689 ENDFN (__mips16_call_stub_df_5) 690#endif 691 692#ifdef L_m16stubdf6 693/* (double, float) */ 694STARTFN (__mips16_call_stub_df_6) 695 .set noreorder 696 LDDBL1 697 mtc1 $6,$f14 698 move $18,$31 699 jal $2 700 nop 701 RETDBL 702 j $18 703 nop 704 .set reorder 705 ENDFN (__mips16_call_stub_df_6) 706#endif 707 708#ifdef L_m16stubdf9 709/* (float, double) */ 710STARTFN (__mips16_call_stub_df_9) 711 .set noreorder 712 mtc1 $4,$f12 713 LDDBL2 714 move $18,$31 715 jal $2 716 nop 717 RETDBL 718 j $18 719 nop 720 .set reorder 721 ENDFN (__mips16_call_stub_df_9) 722#endif 723 724#ifdef L_m16stubdf10 725/* (double, double) */ 726STARTFN (__mips16_call_stub_df_10) 727 .set noreorder 728 LDDBL1 729 LDDBL2 730 move $18,$31 731 jal $2 732 nop 733 RETDBL 734 j $18 735 nop 736 .set reorder 737 ENDFN (__mips16_call_stub_df_10) 738#endif 739#endif /* !__mips_single_float */ 740