|
|
1.1 root 1: /* Subroutines used for code generation on ROMP. 1.1.1.4 ! root 2: Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc. 1.1 root 3: Contributed by Richard Kenner ([email protected]) 4: 5: This file is part of GNU CC. 6: 7: GNU CC is free software; you can redistribute it and/or modify 8: it under the terms of the GNU General Public License as published by 9: the Free Software Foundation; either version 2, or (at your option) 10: any later version. 11: 12: GNU CC is distributed in the hope that it will be useful, 13: but WITHOUT ANY WARRANTY; without even the implied warranty of 14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15: GNU General Public License for more details. 16: 17: You should have received a copy of the GNU General Public License 18: along with GNU CC; see the file COPYING. If not, write to 19: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ 20: 21: 22: #include <stdio.h> 23: #include "config.h" 24: #include "rtl.h" 25: #include "regs.h" 26: #include "hard-reg-set.h" 27: #include "real.h" 28: #include "insn-config.h" 29: #include "conditions.h" 30: #include "insn-flags.h" 31: #include "output.h" 32: #include "insn-attr.h" 33: #include "flags.h" 34: #include "recog.h" 35: #include "expr.h" 36: #include "obstack.h" 37: #include "tree.h" 38: 39: #define min(A,B) ((A) < (B) ? (A) : (B)) 40: #define max(A,B) ((A) > (B) ? (A) : (B)) 41: 42: static int unsigned_comparisons_p (); 43: static void output_loadsave_fpregs (); 44: static void output_fpops (); 45: static void init_fpops (); 46: 47: /* Return 1 if the insn using CC0 set by INSN does not contain 48: any unsigned tests applied to the condition codes. 49: 50: Based on `next_insn_tests_no_inequality' in recog.c. */ 51: 52: int 53: next_insn_tests_no_unsigned (insn) 54: rtx insn; 55: { 56: register rtx next = next_cc0_user (insn); 57: 58: if (next == 0) 59: { 60: if (find_reg_note (insn, REG_UNUSED, cc0_rtx)) 61: return 1; 62: else 63: abort (); 64: } 65: 66: return ((GET_CODE (next) == JUMP_INSN 67: || GET_CODE (next) == INSN 68: || GET_CODE (next) == CALL_INSN) 69: && ! unsigned_comparisons_p (PATTERN (next))); 70: } 71: 72: static int 73: unsigned_comparisons_p (x) 74: rtx x; 75: { 76: register char *fmt; 77: register int len, i; 78: register enum rtx_code code = GET_CODE (x); 79: 80: switch (code) 81: { 82: case REG: 83: case PC: 84: case CC0: 85: case CONST_INT: 86: case CONST_DOUBLE: 87: case CONST: 88: case LABEL_REF: 89: case SYMBOL_REF: 90: return 0; 91: 92: case LTU: 93: case GTU: 94: case LEU: 95: case GEU: 96: return (XEXP (x, 0) == cc0_rtx || XEXP (x, 1) == cc0_rtx); 97: } 98: 99: len = GET_RTX_LENGTH (code); 100: fmt = GET_RTX_FORMAT (code); 101: 102: for (i = 0; i < len; i++) 103: { 104: if (fmt[i] == 'e') 105: { 106: if (unsigned_comparisons_p (XEXP (x, i))) 107: return 1; 108: } 109: else if (fmt[i] == 'E') 110: { 111: register int j; 112: for (j = XVECLEN (x, i) - 1; j >= 0; j--) 113: if (unsigned_comparisons_p (XVECEXP (x, i, j))) 114: return 1; 115: } 116: } 117: 118: return 0; 119: } 120: 121: /* Update the condition code from the insn. Look mostly at the first 122: byte of the machine-specific insn description information. 123: 124: cc_state.value[12] refer to two possible values that might correspond 125: to the CC. We only store register values. */ 126: 127: update_cc (body, insn) 128: rtx body; 129: rtx insn; 130: { 131: switch (get_attr_cc (insn)) 132: { 133: case CC_NONE: 134: /* Insn does not affect the CC at all. */ 135: break; 136: 137: case CC_CHANGE0: 138: /* Insn doesn't affect the CC but does modify operand[0], known to be 139: a register. */ 140: if (cc_status.value1 != 0 141: && reg_overlap_mentioned_p (recog_operand[0], cc_status.value1)) 142: cc_status.value1 = 0; 143: 144: if (cc_status.value2 != 0 145: && reg_overlap_mentioned_p (recog_operand[0], cc_status.value2)) 146: cc_status.value2 = 0; 147: 148: break; 149: 150: case CC_COPY1TO0: 151: /* Insn copies operand[1] to operand[0], both registers, but doesn't 152: affect the CC. */ 153: if (cc_status.value1 != 0 154: && reg_overlap_mentioned_p (recog_operand[0], cc_status.value1)) 155: cc_status.value1 = 0; 156: 157: if (cc_status.value2 != 0 158: && reg_overlap_mentioned_p (recog_operand[0], cc_status.value2)) 159: cc_status.value2 = 0; 160: 161: if (cc_status.value1 != 0 162: && rtx_equal_p (cc_status.value1, recog_operand[1])) 163: cc_status.value2 = recog_operand[0]; 164: 165: if (cc_status.value2 != 0 166: && rtx_equal_p (cc_status.value2, recog_operand[1])) 167: cc_status.value1 = recog_operand[0]; 168: 169: break; 170: 171: case CC_CLOBBER: 172: /* Insn clobbers CC. */ 173: CC_STATUS_INIT; 174: break; 175: 176: case CC_SETS: 177: /* Insn sets CC to recog_operand[0], but overflow is impossible. */ 178: CC_STATUS_INIT; 179: cc_status.flags |= CC_NO_OVERFLOW; 180: cc_status.value1 = recog_operand[0]; 181: break; 182: 183: case CC_COMPARE: 184: /* Insn is a compare which sets the CC fully. Update CC_STATUS for this 185: compare and mark whether the test will be signed or unsigned. */ 186: { 187: register rtx p = PATTERN (insn); 188: 189: CC_STATUS_INIT; 190: 191: if (GET_CODE (p) == PARALLEL) 192: p = XVECEXP (p, 0, 0); 193: cc_status.value1 = SET_SRC (p); 194: 195: if (GET_CODE (SET_SRC (p)) == REG) 196: cc_status.flags |= CC_NO_OVERFLOW; 197: if (! next_insn_tests_no_unsigned (insn)) 198: cc_status.flags |= CC_UNSIGNED; 199: } 200: break; 201: 202: case CC_TBIT: 203: /* Insn sets T bit if result is non-zero. Next insn must be branch. */ 204: CC_STATUS_INIT; 205: cc_status.flags = CC_IN_TB | CC_NOT_NEGATIVE; 206: break; 207: 208: default: 209: abort (); 210: } 211: } 212: 213: /* Return 1 if a previous compare needs to be re-issued. This will happen 214: if two compares tested the same objects, but one was signed and the 215: other unsigned. OP is the comparison operation being performed. */ 216: 217: int 218: restore_compare_p (op) 219: rtx op; 220: { 221: enum rtx_code code = GET_CODE (op); 222: 223: return (((code == GEU || code == LEU || code == GTU || code == LTU) 224: && ! (cc_status.flags & CC_UNSIGNED)) 225: || ((code == GE || code == LE || code == GT || code == LT) 226: && (cc_status.flags & CC_UNSIGNED))); 227: } 228: 229: /* Generate the (long) string corresponding to an inline multiply insn. 230: Note that `r10' does not refer to the register r10, but rather to the 231: SCR used as the MQ. */ 232: char * 233: output_in_line_mul () 234: { 235: static char insns[200]; 236: int i; 237: 238: strcpy (insns, "s %0,%0\n"); 239: strcat (insns, "\tmts r10,%1\n"); 240: for (i = 0; i < 16; i++) 241: strcat (insns, "\tm %0,%2\n"); 242: strcat (insns, "\tmfs r10,%0"); 243: 244: return insns; 245: } 246: 247: /* Returns 1 if OP is a memory reference with an offset from a register within 248: the range specified. The offset must also be a multiple of the size of the 249: mode. */ 250: 251: static int 252: memory_offset_in_range_p (op, mode, low, high) 253: register rtx op; 254: enum machine_mode mode; 255: int low, high; 256: { 257: int offset = 0; 258: 259: if (! memory_operand (op, mode)) 260: return 0; 261: 262: while (GET_CODE (op) == SUBREG) 263: { 264: offset += SUBREG_WORD (op) * UNITS_PER_WORD; 265: #if BYTES_BIG_ENDIAN 266: offset -= (min (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (op))) 267: - min (UNITS_PER_WORD, 268: GET_MODE_SIZE (GET_MODE (SUBREG_REG (op))))); 269: #endif 270: op = SUBREG_REG (op); 271: } 272: 273: /* We must now have either (mem (reg (x)), (mem (plus (reg (x)) (c))), 274: or a constant pool address. */ 275: if (GET_CODE (op) != MEM) 276: abort (); 277: 278: /* Now use the actual mode and get the address. */ 279: mode = GET_MODE (op); 280: op = XEXP (op, 0); 281: if (GET_CODE (op) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (op)) 282: offset = get_pool_offset (op) + 12; 283: else if (GET_CODE (op) == PLUS) 284: { 285: if (GET_CODE (XEXP (op, 1)) != CONST_INT 286: || ! register_operand (XEXP (op, 0), Pmode)) 287: return 0; 288: 289: offset += INTVAL (XEXP (op, 1)); 290: } 291: 292: else if (! register_operand (op, Pmode)) 293: return 0; 294: 295: return (offset >= low && offset <= high 296: && (offset % GET_MODE_SIZE (mode) == 0)); 297: } 298: 299: /* Return 1 if OP is a valid operand for a memory reference insn that can 300: only reference indirect through a register. */ 301: 302: int 303: zero_memory_operand (op, mode) 304: rtx op; 305: enum machine_mode mode; 306: { 307: return memory_offset_in_range_p (op, mode, 0, 0); 308: } 309: 310: /* Return 1 if OP is a valid operand for a `short' memory reference insn. */ 311: 312: int 313: short_memory_operand (op, mode) 314: rtx op; 315: enum machine_mode mode; 316: { 317: if (mode == VOIDmode) 318: mode = GET_MODE (op); 319: 320: return memory_offset_in_range_p (op, mode, 0, 321: 15 * min (UNITS_PER_WORD, 322: GET_MODE_SIZE (mode))); 323: } 324: 325: /* Returns 1 if OP is a memory reference involving a symbolic constant 326: that is not in the constant pool. */ 327: 328: int 329: symbolic_memory_operand (op, mode) 330: register rtx op; 331: enum machine_mode mode; 332: { 333: if (! memory_operand (op, mode)) 334: return 0; 335: 336: while (GET_CODE (op) == SUBREG) 337: op = SUBREG_REG (op); 338: 339: if (GET_CODE (op) != MEM) 340: abort (); 341: 342: op = XEXP (op, 0); 343: if (constant_pool_address_operand (op, VOIDmode)) 344: return 0; 345: else 346: return romp_symbolic_operand (op, Pmode) 347: || (GET_CODE (op) == PLUS && register_operand (XEXP (op, 0), Pmode) 348: && romp_symbolic_operand (XEXP (op, 1), Pmode)); 349: } 350: 351: 352: /* Returns 1 if OP is a constant pool reference to the current function. */ 353: 354: int 355: current_function_operand (op, mode) 356: rtx op; 357: enum machine_mode mode; 358: { 359: if (GET_CODE (op) != MEM || GET_CODE (XEXP (op, 0)) != SYMBOL_REF 360: || ! CONSTANT_POOL_ADDRESS_P (XEXP (op, 0))) 361: return 0; 362: 363: op = get_pool_constant (XEXP (op, 0)); 364: return (GET_CODE (op) == SYMBOL_REF 365: && ! strcmp (current_function_name, XSTR (op, 0))); 366: } 367: 368: /* Return non-zero if this function is known to have a null epilogue. */ 369: 370: int 371: null_epilogue () 372: { 373: return (reload_completed 374: && first_reg_to_save () == 16 375: && ! romp_pushes_stack ()); 376: } 377: 378: /* Returns 1 if OP is the address of a location in the constant pool. */ 379: 380: int 381: constant_pool_address_operand (op, mode) 382: rtx op; 383: enum machine_mode mode; 384: { 385: return ((GET_CODE (op) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (op)) 386: || (GET_CODE (op) == CONST && GET_CODE (XEXP (op, 0)) == PLUS 387: && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT 388: && GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF 389: && CONSTANT_POOL_ADDRESS_P (XEXP (XEXP (op, 0), 0)))); 390: } 391: 392: /* Returns 1 if OP is either a symbol reference or a sum of a symbol 393: reference and a constant. */ 394: 395: int 396: romp_symbolic_operand (op, mode) 397: register rtx op; 398: enum machine_mode mode; 399: { 400: switch (GET_CODE (op)) 401: { 402: case SYMBOL_REF: 403: case LABEL_REF: 404: return ! op->integrated; 405: 406: case CONST: 407: op = XEXP (op, 0); 408: return (GET_CODE (XEXP (op, 0)) == SYMBOL_REF 409: || GET_CODE (XEXP (op, 0)) == LABEL_REF) 410: && GET_CODE (XEXP (op, 1)) == CONST_INT; 411: 412: default: 413: return 0; 414: } 415: } 416: 417: /* Returns 1 if OP is a valid constant for the ROMP. */ 418: 419: int 420: constant_operand (op, mode) 421: register rtx op; 422: enum machine_mode mode; 423: { 424: switch (GET_CODE (op)) 425: { 426: case LABEL_REF: 427: case SYMBOL_REF: 428: case PLUS: 429: case CONST: 430: return romp_symbolic_operand (op,mode); 431: 432: case CONST_INT: 433: return (unsigned int) (INTVAL (op) + 0x8000) < 0x10000 434: || (INTVAL (op) & 0xffff) == 0 || (INTVAL (op) & 0xffff0000) == 0; 435: 436: default: 437: return 0; 438: } 439: } 440: 441: /* Returns 1 if OP is either a constant integer valid for the ROMP or a 442: register. If a register, it must be in the proper mode unless MODE is 443: VOIDmode. */ 444: 445: int 446: reg_or_cint_operand (op, mode) 447: register rtx op; 448: enum machine_mode mode; 449: { 450: if (GET_CODE (op) == CONST_INT) 451: return constant_operand (op, mode); 452: 453: return register_operand (op, mode); 454: } 455: 456: /* Return 1 is the operand is either a register or ANY constant integer. */ 457: 458: int 459: reg_or_any_cint_operand (op, mode) 460: register rtx op; 461: enum machine_mode mode; 462: { 463: return GET_CODE (op) == CONST_INT || register_operand (op, mode); 464: } 465: 466: /* Return 1 if the operand is either a register or a valid D-type operand. */ 467: 468: int 469: reg_or_D_operand (op, mode) 470: register rtx op; 471: enum machine_mode mode; 472: { 473: if (GET_CODE (op) == CONST_INT) 474: return (unsigned) (INTVAL (op) + 0x8000) < 0x10000; 475: 476: return register_operand (op, mode); 477: } 478: 479: /* Return 1 if the operand is either a register or an item that can be 480: used as the operand of an SI add insn. */ 481: 482: int 483: reg_or_add_operand (op, mode) 484: register rtx op; 485: enum machine_mode mode; 486: { 487: return reg_or_D_operand (op, mode) || romp_symbolic_operand (op, mode) 488: || (GET_CODE (op) == CONST_INT && (INTVAL (op) & 0xffff) == 0); 489: } 490: 491: /* Return 1 if the operand is either a register or an item that can be 492: used as the operand of a ROMP logical AND insn. */ 493: 494: int 495: reg_or_and_operand (op, mode) 496: register rtx op; 497: enum machine_mode mode; 498: { 499: if (reg_or_cint_operand (op, mode)) 500: return 1; 501: 502: if (GET_CODE (op) != CONST_INT) 503: return 0; 504: 505: return (INTVAL (op) & 0xffff) == 0xffff 506: || (INTVAL (op) & 0xffff0000) == 0xffff0000; 507: } 508: 509: /* Return 1 if the operand is a register or memory operand. */ 510: 511: int 512: reg_or_mem_operand (op, mode) 513: register rtx op; 514: register enum machine_mode mode; 515: { 516: return register_operand (op, mode) || memory_operand (op, mode); 517: } 518: 519: /* Return 1 if the operand is either a register or a memory operand that is 520: not symbolic. */ 521: 522: int 523: reg_or_nonsymb_mem_operand (op, mode) 524: register rtx op; 525: enum machine_mode mode; 526: { 527: if (register_operand (op, mode)) 528: return 1; 529: 530: if (memory_operand (op, mode) && ! symbolic_memory_operand (op, mode)) 531: return 1; 532: 533: return 0; 534: } 535: 536: /* Return 1 if this operand is valid for the ROMP. This is any operand except 537: certain constant integers. */ 538: 539: int 540: romp_operand (op, mode) 541: register rtx op; 542: enum machine_mode mode; 543: { 544: if (GET_CODE (op) == CONST_INT) 545: return constant_operand (op, mode); 546: 547: return general_operand (op, mode); 548: } 549: 550: /* Return 1 if the operand is (reg:mode 0). */ 551: 552: int 553: reg_0_operand (op, mode) 554: rtx op; 555: enum machine_mode mode; 556: { 557: return ((mode == VOIDmode || mode == GET_MODE (op)) 558: && GET_CODE (op) == REG && REGNO (op) == 0); 559: } 560: 561: /* Return 1 if the operand is (reg:mode 15). */ 562: 563: int 564: reg_15_operand (op, mode) 565: rtx op; 566: enum machine_mode mode; 567: { 568: return ((mode == VOIDmode || mode == GET_MODE (op)) 569: && GET_CODE (op) == REG && REGNO (op) == 15); 570: } 571: 572: /* Return 1 if this is a binary floating-point operation. */ 573: 574: int 575: float_binary (op, mode) 576: register rtx op; 577: enum machine_mode mode; 578: { 579: if (mode != VOIDmode && mode != GET_MODE (op)) 580: return 0; 581: 582: if (GET_MODE (op) != SFmode && GET_MODE (op) != DFmode) 583: return 0; 584: 585: switch (GET_CODE (op)) 586: { 587: case PLUS: 588: case MINUS: 589: case MULT: 590: case DIV: 591: return GET_MODE (XEXP (op, 0)) == GET_MODE (op) 592: && GET_MODE (XEXP (op, 1)) == GET_MODE (op); 593: 594: default: 595: return 0; 596: } 597: } 598: 599: /* Return 1 if this is a unary floating-point operation. */ 600: 601: int 602: float_unary (op, mode) 603: register rtx op; 604: enum machine_mode mode; 605: { 606: if (mode != VOIDmode && mode != GET_MODE (op)) 607: return 0; 608: 609: if (GET_MODE (op) != SFmode && GET_MODE (op) != DFmode) 610: return 0; 611: 612: return (GET_CODE (op) == NEG || GET_CODE (op) == ABS) 613: && GET_MODE (XEXP (op, 0)) == GET_MODE (op); 614: } 615: 1.1.1.2 root 616: /* Return 1 if this is a valid floating-point conversion that can be done 1.1 root 617: as part of an operation by the RT floating-point routines. */ 618: 619: int 620: float_conversion (op, mode) 621: register rtx op; 622: enum machine_mode mode; 623: { 624: if (mode != VOIDmode && mode != GET_MODE (op)) 625: return 0; 626: 627: switch (GET_CODE (op)) 628: { 629: case FLOAT_TRUNCATE: 630: return GET_MODE (op) == SFmode && GET_MODE (XEXP (op, 0)) == DFmode; 631: 632: case FLOAT_EXTEND: 633: return GET_MODE (op) == DFmode && GET_MODE (XEXP (op, 0)) == SFmode; 634: 635: case FLOAT: 636: return ((GET_MODE (XEXP (op, 0)) == SImode 637: || GET_CODE (XEXP (op, 0)) == CONST_INT) 638: && (GET_MODE (op) == SFmode || GET_MODE (op) == DFmode)); 639: 640: case FIX: 641: return ((GET_MODE (op) == SImode 642: || GET_CODE (XEXP (op, 0)) == CONST_INT) 643: && (GET_MODE (XEXP (op, 0)) == SFmode 644: || GET_MODE (XEXP (op, 0)) == DFmode)); 645: 646: default: 647: return 0; 648: } 649: } 650: 651: /* Print an operand. Recognize special options, documented below. */ 652: 653: void 654: print_operand (file, x, code) 655: FILE *file; 656: rtx x; 657: char code; 658: { 659: int i; 660: 661: switch (code) 662: { 663: case 'B': 664: /* Byte number (const/8) */ 665: if (GET_CODE (x) != CONST_INT) 666: output_operand_lossage ("invalid %%B value"); 667: 668: fprintf (file, "%d", INTVAL (x) / 8); 669: break; 670: 671: case 'L': 672: /* Low order 16 bits of constant. */ 673: if (GET_CODE (x) != CONST_INT) 674: output_operand_lossage ("invalid %%L value"); 675: 676: fprintf (file, "%d", INTVAL (x) & 0xffff); 677: break; 678: 679: case 's': 680: /* Null or "16" depending on whether the constant is greater than 16. */ 681: if (GET_CODE (x) != CONST_INT) 682: output_operand_lossage ("invalid %%s value"); 683: 684: if (INTVAL (x) >= 16) 685: fprintf (file, "16"); 686: 687: break; 688: 689: case 'S': 690: /* For shifts: 's' will have given the half. Just give the amount 691: within 16. */ 692: if (GET_CODE (x) != CONST_INT) 693: output_operand_lossage ("invalid %%S value"); 694: 695: fprintf (file, "%d", INTVAL (x) & 15); 696: break; 697: 698: case 'b': 699: /* The number of a single bit set or cleared, mod 16. Note that the ROMP 700: numbers bits with the high-order bit 31. */ 701: if (GET_CODE (x) != CONST_INT) 702: output_operand_lossage ("invalid %%b value"); 703: 704: if ((i = exact_log2 (INTVAL (x))) >= 0) 705: fprintf (file, "%d", (31 - i) % 16); 706: else if ((i = exact_log2 (~ INTVAL (x))) >= 0) 707: fprintf (file, "%d", (31 - i) % 16); 708: else 709: output_operand_lossage ("invalid %%b value"); 710: 711: break; 712: 713: case 'h': 714: /* "l" or "u" depending on which half of the constant is zero. */ 715: if (GET_CODE (x) != CONST_INT) 716: output_operand_lossage ("invalid %%h value"); 717: 718: if ((INTVAL (x) & 0xffff0000) == 0) 719: fprintf (file, "l"); 720: else if ((INTVAL (x) & 0xffff) == 0) 721: fprintf (file, "u"); 722: else 723: output_operand_lossage ("invalid %%h value"); 724: 725: break; 726: 727: case 'H': 728: /* Upper or lower half, depending on which half is zero. */ 729: if (GET_CODE (x) != CONST_INT) 730: output_operand_lossage ("invalid %%H value"); 731: 732: if ((INTVAL (x) & 0xffff0000) == 0) 733: fprintf (file, "%d", INTVAL (x) & 0xffff); 734: else if ((INTVAL (x) & 0xffff) == 0) 735: fprintf (file, "%d", (INTVAL (x) >> 16) & 0xffff); 736: else 737: output_operand_lossage ("invalid %%H value"); 738: 739: break; 740: 741: case 'z': 742: /* Write two characters: 743: 'lo' if the high order part is all ones 744: 'lz' if the high order part is all zeros 745: 'uo' if the low order part is all ones 746: 'uz' if the low order part is all zeros 747: */ 748: if (GET_CODE (x) != CONST_INT) 749: output_operand_lossage ("invalid %%z value"); 750: 751: if ((INTVAL (x) & 0xffff0000) == 0) 752: fprintf (file, "lz"); 753: else if ((INTVAL (x) & 0xffff0000) == 0xffff0000) 754: fprintf (file, "lo"); 755: else if ((INTVAL (x) & 0xffff) == 0) 756: fprintf (file, "uz"); 757: else if ((INTVAL (x) & 0xffff) == 0xffff) 758: fprintf (file, "uo"); 759: else 760: output_operand_lossage ("invalid %%z value"); 761: 762: break; 763: 764: case 'Z': 765: /* Upper or lower half, depending on which is non-zero or not 766: all ones. Must be consistent with 'z' above. */ 767: if (GET_CODE (x) != CONST_INT) 768: output_operand_lossage ("invalid %%Z value"); 769: 770: if ((INTVAL (x) & 0xffff0000) == 0 771: || (INTVAL (x) & 0xffff0000) == 0xffff0000) 772: fprintf (file, "%d", INTVAL (x) & 0xffff); 773: else if ((INTVAL (x) & 0xffff) == 0 || (INTVAL (x) & 0xffff) == 0xffff) 774: fprintf (file, "%d", (INTVAL (x) >> 16) & 0xffff); 775: else 776: output_operand_lossage ("invalid %%Z value"); 777: 778: break; 779: 780: case 'k': 781: /* Same as 'z', except the trailing 'o' or 'z' is not written. */ 782: if (GET_CODE (x) != CONST_INT) 783: output_operand_lossage ("invalid %%k value"); 784: 785: if ((INTVAL (x) & 0xffff0000) == 0 786: || (INTVAL (x) & 0xffff0000) == 0xffff0000) 787: fprintf (file, "l"); 788: else if ((INTVAL (x) & 0xffff) == 0 789: || (INTVAL (x) & 0xffff) == 0xffff) 790: fprintf (file, "u"); 791: else 792: output_operand_lossage ("invalid %%k value"); 793: 794: break; 795: 796: case 't': 797: /* Similar to 's', except that we write 'h' or 'u'. */ 798: if (GET_CODE (x) != CONST_INT) 799: output_operand_lossage ("invalid %%k value"); 800: 801: if (INTVAL (x) < 16) 802: fprintf (file, "u"); 803: else 804: fprintf (file, "l"); 805: break; 806: 807: case 'M': 808: /* For memory operations, write 's' if the operand is a short 809: memory operand. */ 810: if (short_memory_operand (x, VOIDmode)) 811: fprintf (file, "s"); 812: break; 813: 814: case 'N': 815: /* Like 'M', but check for zero memory offset. */ 816: if (zero_memory_operand (x, VOIDmode)) 817: fprintf (file, "s"); 818: break; 819: 820: case 'O': 821: /* Write low-order part of DImode or DFmode. Supported for MEM 822: and REG only. */ 823: if (GET_CODE (x) == REG) 824: fprintf (file, "%s", reg_names[REGNO (x) + 1]); 825: else if (GET_CODE (x) == MEM) 826: print_operand (file, gen_rtx (MEM, GET_MODE (x), 827: plus_constant (XEXP (x, 0), 4)), 0); 828: else 829: abort (); 830: break; 831: 832: case 'C': 833: /* Offset in constant pool for constant pool address. */ 834: if (! constant_pool_address_operand (x, VOIDmode)) 835: abort (); 836: if (GET_CODE (x) == SYMBOL_REF) 837: fprintf (file, "%d", get_pool_offset (x) + 12); 838: else 839: /* Must be (const (plus (symbol_ref) (const_int))) */ 840: fprintf (file, "%d", 841: (get_pool_offset (XEXP (XEXP (x, 0), 0)) + 12 842: + INTVAL (XEXP (XEXP (x, 0), 1)))); 843: break; 844: 845: case 'j': 846: /* Branch opcode. Check for condition in test bit for eq/ne. */ 847: switch (GET_CODE (x)) 848: { 849: case EQ: 850: if (cc_status.flags & CC_IN_TB) 851: fprintf (file, "ntb"); 852: else 853: fprintf (file, "eq"); 854: break; 855: 856: case NE: 857: if (cc_status.flags & CC_IN_TB) 858: fprintf (file, "tb"); 859: else 860: fprintf (file, "ne"); 861: break; 862: 863: case GT: 864: case GTU: 865: fprintf (file, "h"); 866: break; 867: 868: case LT: 869: case LTU: 870: fprintf (file, "l"); 871: break; 872: 873: case GE: 874: case GEU: 875: fprintf (file, "he"); 876: break; 877: 878: case LE: 879: case LEU: 880: fprintf (file, "le"); 881: break; 882: 883: default: 884: output_operand_lossage ("invalid %%j value"); 885: } 886: break; 887: 888: case 'J': 889: /* Reversed branch opcode. */ 890: switch (GET_CODE (x)) 891: { 892: case EQ: 893: if (cc_status.flags & CC_IN_TB) 894: fprintf (file, "tb"); 895: else 896: fprintf (file, "ne"); 897: break; 898: 899: case NE: 900: if (cc_status.flags & CC_IN_TB) 901: fprintf (file, "ntb"); 902: else 903: fprintf (file, "eq"); 904: break; 905: 906: case GT: 907: case GTU: 908: fprintf (file, "le"); 909: break; 910: 911: case LT: 912: case LTU: 913: fprintf (file, "he"); 914: break; 915: 916: case GE: 917: case GEU: 918: fprintf (file, "l"); 919: break; 920: 921: case LE: 922: case LEU: 923: fprintf (file, "h"); 924: break; 925: 926: default: 927: output_operand_lossage ("invalid %%j value"); 928: } 929: break; 930: 931: case '.': 1.1.1.2 root 932: /* Output nothing. Used as delimiter in, e.g., "mc%B1%.3 " */ 1.1 root 933: break; 934: 935: case '#': 936: /* Output 'x' if this insn has a delay slot, else nothing. */ 937: if (dbr_sequence_length ()) 938: fprintf (file, "x"); 939: break; 940: 941: case 0: 942: if (GET_CODE (x) == REG) 943: fprintf (file, "%s", reg_names[REGNO (x)]); 944: else if (GET_CODE (x) == MEM) 945: { 946: if (GET_CODE (XEXP (x, 0)) == SYMBOL_REF 947: && current_function_operand (x, Pmode)) 948: fprintf (file, "r14"); 949: else 950: output_address (XEXP (x, 0)); 951: } 952: else 953: output_addr_const (file, x); 954: break; 955: 956: default: 957: output_operand_lossage ("invalid %%xn code"); 958: } 959: } 960: 961: /* This page contains routines that are used to determine what the function 962: prologue and epilogue code will do and write them out. */ 963: 964: /* Return the first register that is required to be saved. 16 if none. */ 965: 966: int 967: first_reg_to_save() 968: { 969: int first_reg; 970: 971: /* Find lowest numbered live register. */ 972: for (first_reg = 6; first_reg <= 15; first_reg++) 973: if (regs_ever_live[first_reg]) 974: break; 975: 976: /* If we think that we do not have to save r14, see if it will be used 977: to be sure. */ 978: if (first_reg > 14 && romp_using_r14 ()) 979: first_reg = 14; 980: 981: return first_reg; 982: } 983: 984: /* Compute the size of the save area in the stack, including the space for 985: the first four incoming arguments. */ 986: 987: int 988: romp_sa_size () 989: { 990: int size; 991: int i; 992: 993: /* We have the 4 words corresponding to the arguments passed in registers, 994: 4 reserved words, space for static chain, general register save area, 995: and floating-point save area. */ 996: size = 4 + 4 + 1 + (16 - first_reg_to_save ()); 997: 998: /* The documentation says we have to leave 18 words in the save area if 999: any floating-point registers at all are saved, not the three words 1000: per register you might otherwise expect. */ 1001: for (i = 2 + (TARGET_FP_REGS != 0); i <= 7; i++) 1002: if (regs_ever_live[i + 17]) 1003: { 1004: size += 18; 1005: break; 1006: } 1007: 1008: return size * 4; 1009: } 1010: 1011: /* Return non-zero if this function makes calls or has fp operations 1012: (which are really calls). */ 1013: 1014: int 1015: romp_makes_calls () 1016: { 1017: rtx insn; 1018: 1019: for (insn = get_insns (); insn; insn = next_insn (insn)) 1020: { 1021: if (GET_CODE (insn) == CALL_INSN) 1022: return 1; 1023: else if (GET_CODE (insn) == INSN) 1024: { 1025: rtx body = PATTERN (insn); 1026: 1027: if (GET_CODE (body) != USE && GET_CODE (body) != CLOBBER 1028: && GET_CODE (body) != ADDR_VEC 1029: && GET_CODE (body) != ADDR_DIFF_VEC 1030: && get_attr_type (insn) == TYPE_FP) 1031: return 1; 1032: } 1033: } 1034: 1035: return 0; 1036: } 1037: 1038: /* Return non-zero if this function will use r14 as a pointer to its 1039: constant pool. */ 1040: 1041: int 1042: romp_using_r14 () 1043: { 1044: /* If we are debugging, profiling, have a non-empty constant pool, or 1045: call a function, we need r14. */ 1046: return (write_symbols != NO_DEBUG || profile_flag || get_pool_size () != 0 1047: || romp_makes_calls ()); 1048: } 1049: 1050: /* Return non-zero if this function needs to push space on the stack. */ 1051: 1052: int 1053: romp_pushes_stack () 1054: { 1055: /* We need to push the stack if a frame pointer is needed (because the 1056: stack might be dynamically adjusted), if we are debugging, if the 1057: total required size is more than 100 bytes, or if we make calls. */ 1058: 1059: return (frame_pointer_needed || write_symbols != NO_DEBUG 1060: || (romp_sa_size () + get_frame_size ()) > 100 1061: || romp_makes_calls ()); 1062: } 1063: 1064: /* Write function prologue. 1065: 1066: We compute the size of the fixed area required as follows: 1067: 1068: We always allocate 4 words for incoming arguments, 4 word reserved, 1 1069: word for static link, as many words as required for general register 1070: save area, plus 2 words for each FP reg 2-7 that must be saved. */ 1071: 1072: void 1073: output_prolog (file, size) 1074: FILE *file; 1075: int size; 1076: { 1077: int first_reg; 1078: int reg_save_offset; 1079: rtx insn; 1080: int fp_save = size + current_function_outgoing_args_size; 1081: 1082: init_fpops (); 1083: 1084: /* Add in fixed size plus output argument area. */ 1085: size += romp_sa_size () + current_function_outgoing_args_size; 1086: 1087: /* Compute first register to save and perform the save operation if anything 1088: needs to be saved. */ 1089: first_reg = first_reg_to_save(); 1090: reg_save_offset = - (4 + 4 + 1 + (16 - first_reg)) * 4; 1091: if (first_reg == 15) 1092: fprintf (file, "\tst r15,%d(r1)\n", reg_save_offset); 1093: else if (first_reg < 16) 1094: fprintf (file, "\tstm r%d,%d(r1)\n", first_reg, reg_save_offset); 1095: 1096: /* Set up pointer to data area if it is needed. */ 1097: if (romp_using_r14 ()) 1098: fprintf (file, "\tcas r14,r0,r0\n"); 1099: 1100: /* Set up frame pointer if needed. */ 1101: if (frame_pointer_needed) 1102: fprintf (file, "\tcal r13,-%d(r1)\n", romp_sa_size () + 64); 1103: 1104: /* Push stack if neeeded. There are a couple of ways of doing this. */ 1105: if (romp_pushes_stack ()) 1106: { 1107: if (size >= 32768) 1108: { 1109: if (size >= 65536) 1110: { 1111: fprintf (file, "\tcau r0,%d(r0)\n", size >> 16); 1112: fprintf (file, "\toil r0,r0,%d\n", size & 0xffff); 1113: } 1114: else 1115: fprintf (file, "\tcal16 r0,%d(r0)\n", size); 1116: fprintf (file, "\ts r1,r0\n"); 1117: } 1118: else 1119: fprintf (file, "\tcal r1,-%d(r1)\n", size); 1120: } 1121: 1122: /* Save floating-point registers. */ 1123: output_loadsave_fpregs (file, USE, 1124: plus_constant (stack_pointer_rtx, fp_save)); 1125: } 1126: 1127: /* Write function epilogue. */ 1128: 1129: void 1130: output_epilog (file, size) 1131: FILE *file; 1132: int size; 1133: { 1134: int first_reg = first_reg_to_save(); 1135: int pushes_stack = romp_pushes_stack (); 1136: int reg_save_offset = - ((16 - first_reg) + 1 + 4 + 4) * 4; 1137: int total_size = (size + romp_sa_size () 1138: + current_function_outgoing_args_size); 1139: int fp_save = size + current_function_outgoing_args_size; 1140: int long_frame = total_size >= 32768; 1141: rtx insn = get_last_insn (); 1142: int write_code = 1; 1143: 1144: int nargs = 0; /* words of arguments */ 1145: tree argptr; 1146: 1147: for (argptr = DECL_ARGUMENTS (current_function_decl); 1148: argptr; argptr = TREE_CHAIN (argptr)) 1149: nargs += ((TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (argptr))) 1150: + BITS_PER_WORD - 1) / BITS_PER_WORD); 1151: 1152: /* If the last insn was a BARRIER, we don't have to write anything except 1153: the trace table. */ 1154: if (GET_CODE (insn) == NOTE) 1155: insn = prev_nonnote_insn (insn); 1156: if (insn && GET_CODE (insn) == BARRIER) 1157: write_code = 0; 1158: 1159: /* Restore floating-point registers. */ 1160: if (write_code) 1161: output_loadsave_fpregs (file, CLOBBER, 1162: gen_rtx (PLUS, Pmode, gen_rtx (REG, Pmode, 1), 1163: gen_rtx (CONST_INT, VOIDmode, fp_save))); 1164: 1165: /* If we push the stack and do not have size > 32K, adjust the register 1166: save location to the current position of sp. Otherwise, if long frame, 1167: restore sp from fp. */ 1168: if (pushes_stack && ! long_frame) 1169: reg_save_offset += total_size; 1170: else if (long_frame && write_code) 1171: fprintf (file, "\tcal r1,%d(r13)\n", romp_sa_size () + 64); 1172: 1173: /* Restore registers. */ 1174: if (first_reg == 15 && write_code) 1175: fprintf (file, "\tl r15,%d(r1)\n", reg_save_offset); 1176: else if (first_reg < 16 && write_code) 1177: fprintf (file, "\tlm r%d,%d(r1)\n", first_reg, reg_save_offset); 1178: if (first_reg == 16) first_reg = 0; 1179: 1180: /* Handle popping stack, if needed and write debug table entry. */ 1181: if (pushes_stack) 1182: { 1183: if (write_code) 1184: { 1185: if (long_frame) 1186: fprintf (file, "\tbr r15\n"); 1187: else 1188: fprintf (file, "\tbrx r15\n\tcal r1,%d(r1)\n", total_size); 1189: } 1190: fprintf (file, "\t.long 0x%x\n", 0xdf07df08 + first_reg * 0x10); 1191: 1192: if (nargs > 15) nargs = 15; 1193: if (frame_pointer_needed) 1194: fprintf (file, "\t.byte 0x%xd, 53\n", nargs); 1195: else 1196: fprintf (file, "\t.short 0x%x100\n", nargs); 1197: } 1198: else 1199: { 1200: if (write_code) 1201: fprintf (file, "\tbr r15\n"); 1202: fprintf (file, "\t.long 0xdf02df00\n"); 1203: } 1204: 1205: /* Output any pending floating-point operations. */ 1.1.1.4 ! root 1206: output_fpops (file); 1.1 root 1207: } 1208: 1209: /* For the ROMP we need to make new SYMBOL_REFs for the actual name of a 1210: called routine. To keep them unique we maintain a hash table of all 1211: that have been created so far. */ 1212: 1213: struct symref_hashent { 1214: rtx symref; /* Created SYMBOL_REF rtx. */ 1215: struct symref_hashent *next; /* Next with same hash code. */ 1216: }; 1217: 1218: #define SYMHASHSIZE 151 1219: #define HASHBITS 65535 1220: 1221: /* Define the hash table itself. */ 1222: 1223: static struct symref_hashent *symref_hash_table[SYMHASHSIZE]; 1224: 1225: /* Given a name (allocatable in temporary storage), return a SYMBOL_REF 1226: for the name. The rtx is allocated from the current rtl_obstack, while 1227: the name string is allocated from the permanent obstack. */ 1228: rtx 1229: get_symref (name) 1230: register char *name; 1231: { 1232: extern struct obstack permanent_obstack; 1233: register char *sp = name; 1234: unsigned int hash = 0; 1235: struct symref_hashent *p, **last_p; 1236: 1237: /* Compute the hash code for the string. */ 1238: while (*sp) 1239: hash = (hash << 4) + *sp++; 1240: 1241: /* Search for a matching entry in the hash table, keeping track of the 1242: insertion location as we do so. */ 1243: hash = (hash & HASHBITS) % SYMHASHSIZE; 1244: for (last_p = &symref_hash_table[hash], p = *last_p; 1245: p; last_p = &p->next, p = *last_p) 1246: if (strcmp (name, XSTR (p->symref, 0)) == 0) 1247: break; 1248: 1249: /* If couldn't find matching SYMBOL_REF, make a new one. */ 1250: if (p == 0) 1251: { 1252: /* Ensure SYMBOL_REF will stay around. */ 1253: end_temporary_allocation (); 1254: p = *last_p = (struct symref_hashent *) 1255: permalloc (sizeof (struct symref_hashent)); 1256: p->symref = gen_rtx (SYMBOL_REF, Pmode, 1257: obstack_copy0 (&permanent_obstack, 1258: name, strlen (name))); 1259: p->next = 0; 1260: resume_temporary_allocation (); 1261: } 1262: 1263: return p->symref; 1264: } 1265: 1266: /* Validate the precision of a floating-point operation. 1267: 1268: We merge conversions from integers and between floating-point modes into 1269: the insn. However, this must not effect the desired precision of the 1270: insn. The RT floating-point system uses the widest of the operand modes. 1271: If this should be a double-precision insn, ensure that one operand 1272: passed to the floating-point processor has double mode. 1273: 1274: Note that since we don't check anything if the mode is single precision, 1275: it, strictly speaking, isn't necessary to call this for those insns. 1276: However, we do so in case something else needs to be checked in the 1277: future. 1278: 1279: This routine returns 1 if the operation is OK. */ 1280: 1281: int 1282: check_precision (opmode, op1, op2) 1283: enum machine_mode opmode; 1284: rtx op1, op2; 1285: { 1286: if (opmode == SFmode) 1287: return 1; 1288: 1289: /* If operand is not a conversion from an integer mode or an extension from 1290: single-precision, it must be a double-precision value. */ 1291: if (GET_CODE (op1) != FLOAT && GET_CODE (op1) != FLOAT_EXTEND) 1292: return 1; 1293: 1294: if (op2 && GET_CODE (op2) != FLOAT && GET_CODE (op2) != FLOAT_EXTEND) 1295: return 1; 1296: 1297: return 0; 1298: } 1299: 1300: /* Floating-point on the RT is done by creating an operation block in the data 1301: area that describes the operation. If two floating-point operations are the 1302: same in a single function, they can use the same block. 1303: 1304: These routines are responsible for managing these blocks. */ 1305: 1306: /* Structure to describe a floating-point operation. */ 1307: 1308: struct fp_op { 1309: struct fp_op *next_same_hash; /* Next op with same hash code. */ 1310: struct fp_op *next_in_mem; /* Next op in memory. */ 1311: int mem_offset; /* Offset from data area. */ 1312: short size; /* Size of block in bytes. */ 1313: short noperands; /* Number of operands in block. */ 1314: rtx ops[3]; /* RTL for operands. */ 1315: enum rtx_code opcode; /* Operation being performed. */ 1316: }; 1317: 1318: /* Size of hash table. */ 1319: #define FP_HASH_SIZE 101 1320: 1321: /* Hash table of floating-point operation blocks. */ 1322: static struct fp_op *fp_hash_table[FP_HASH_SIZE]; 1323: 1324: /* First floating-point block in data area. */ 1325: static struct fp_op *first_fpop; 1326: 1327: /* Last block in data area so far. */ 1328: static struct fp_op *last_fpop_in_mem; 1329: 1330: /* Subroutine number in file, to get unique "LF" labels. */ 1331: static int subr_number = 0; 1332: 1333: /* Current word offset in data area (includes header and any constant pool). */ 1334: int data_offset; 1335: 1336: /* Compute hash code for an RTX used in floating-point. */ 1337: 1338: static unsigned int 1339: hash_rtx (x) 1340: register rtx x; 1341: { 1342: register unsigned int hash = (((int) GET_CODE (x) << 10) 1343: + ((int) GET_MODE (x) << 20)); 1344: register int i; 1345: register char *fmt = GET_RTX_FORMAT (GET_CODE (x)); 1346: 1347: for (i = 0; i < GET_RTX_LENGTH (GET_CODE (x)); i++) 1348: if (fmt[i] == 'e') 1349: hash += hash_rtx (XEXP (x, i)); 1350: else if (fmt[i] == 'u') 1351: hash += (int) XEXP (x, i); 1352: else if (fmt[i] == 'i') 1353: hash += XINT (x, i); 1354: else if (fmt[i] == 's') 1355: hash += (int) XSTR (x, i); 1356: 1357: return hash; 1358: } 1359: 1360: /* Given an operation code and up to three operands, return a character string 1361: corresponding to the code to emit to branch to a floating-point operation 1362: block. INSN is provided to see if the delay slot has been filled or not. 1363: 1364: A new floating-point operation block is created if this operation has not 1365: been seen before. */ 1366: 1367: char * 1368: output_fpop (code, op0, op1, op2, insn) 1369: enum rtx_code code; 1370: rtx op0, op1, op2; 1371: rtx insn; 1372: { 1373: static char outbuf[40]; 1374: unsigned int hash, hash0, hash1, hash2; 1375: int size, i; 1376: register struct fp_op *fpop, *last_fpop; 1377: int dyadic = (op2 != 0); 1378: enum machine_mode opmode; 1379: int noperands; 1380: rtx tem; 1381: unsigned int tem_hash; 1382: int fr0_avail = 0; 1383: 1384: /* Compute hash code for each operand. If the operation is commutative, 1385: put the one with the smaller hash code first. This will make us see 1386: more operations as identical. */ 1387: hash0 = op0 ? hash_rtx (op0) : 0; 1388: hash1 = op1 ? hash_rtx (op1) : 0; 1389: hash2 = op2 ? hash_rtx (op2) : 0; 1390: 1391: if (hash0 > hash1 && code == EQ) 1392: { 1393: tem = op0; op0 = op1; op1 = tem; 1394: tem_hash = hash0; hash0 = hash1; hash1 = tem_hash; 1395: } 1396: else if (hash1 > hash2 && (code == PLUS || code == MULT)) 1397: { 1398: tem = op1; op1 = op2; op2 = tem; 1399: tem_hash = hash1; hash1 = hash2; hash2 = tem_hash; 1400: } 1401: 1402: /* If operation is commutative and the first and third operands are equal, 1403: swap the second and third operands. Note that we must consider two 1404: operands equal if they are the same register even if different modes. */ 1405: if (op2 && (code == PLUS || code == MULT) 1406: && (rtx_equal_p (op0, op2) 1407: || (GET_CODE (op0) == REG && GET_CODE (op2) == REG 1408: && REGNO (op0) == REGNO (op2)))) 1409: { 1410: tem = op1; op1 = op2; op2 = tem; 1411: tem_hash = hash1; hash1 = hash2; hash2 = tem_hash; 1412: } 1413: 1414: /* If the first and second operands are the same, merge them. Don't do this 1.1.1.3 root 1415: for SFmode or SImode in general registers because this triggers a bug in 1416: the RT fp code. */ 1.1 root 1417: if (op1 && rtx_equal_p (op0, op1) 1418: && code != EQ && code != GE && code != SET 1.1.1.3 root 1419: && ((GET_MODE (op1) != SFmode && GET_MODE (op1) != SImode) 1420: || GET_CODE (op0) != REG || FP_REGNO_P (REGNO (op0)))) 1.1 root 1421: { 1422: op1 = op2; 1423: op2 = 0; 1424: } 1425: 1426: noperands = 1 + (op1 != 0) + (op2 != 0); 1427: 1428: /* Compute hash code for entire expression and see if operation block 1429: already exists. */ 1430: hash = ((int) code << 13) + (hash0 << 2) + (hash1 << 1) + hash2; 1431: 1432: hash %= FP_HASH_SIZE; 1433: for (fpop = fp_hash_table[hash], last_fpop = 0; 1434: fpop; 1435: last_fpop = fpop, fpop = fpop->next_same_hash) 1436: if (fpop->opcode == code && noperands == fpop->noperands 1437: && (op0 == 0 || rtx_equal_p (op0, fpop->ops[0])) 1438: && (op1 == 0 || rtx_equal_p (op1, fpop->ops[1])) 1439: && (op2 == 0 || rtx_equal_p (op2, fpop->ops[2]))) 1440: goto win; 1441: 1442: /* We have never seen this operation before. */ 1443: fpop = (struct fp_op *) oballoc (sizeof (struct fp_op)); 1444: fpop->mem_offset = data_offset; 1445: fpop->opcode = code; 1446: fpop->noperands = noperands; 1447: fpop->ops[0] = op0; 1448: fpop->ops[1] = op1; 1449: fpop->ops[2] = op2; 1450: 1451: /* Compute the size using the rules in Appendix A of the RT Linkage 1452: Convention (4.3/RT-PSD:5) manual. These rules are a bit ambiguous, 1453: but if we guess wrong, it will effect only efficiency, not correctness. */ 1454: 1455: /* Size = 24 + 32 for each non-fp (or fr7) */ 1456: size = 24; 1457: if (op0 && (GET_CODE (op0) != REG 1458: || ! FP_REGNO_P (REGNO (op0)) || REGNO (op0) == 23)) 1459: size += 32; 1460: 1461: if (op1 && (GET_CODE (op1) != REG 1462: || ! FP_REGNO_P (REGNO (op1)) || REGNO (op1) == 23)) 1463: size += 32; 1464: 1465: if (op2 && (GET_CODE (op2) != REG 1466: || ! FP_REGNO_P (REGNO (op2)) || REGNO (op2) == 23)) 1467: size += 32; 1468: 1469: /* Size + 12 for each conversion. First get operation mode. */ 1470: if ((op0 && GET_MODE (op0) == DFmode) 1471: || (op1 && GET_MODE (op1) == DFmode) 1472: || (op2 && GET_MODE (op2) == DFmode)) 1473: opmode = DFmode; 1474: else 1475: opmode = SFmode; 1476: 1477: if (op0 && GET_MODE (op0) != opmode) 1478: size += 12; 1479: if (op1 && GET_MODE (op1) != opmode) 1480: size += 12; 1481: if (op2 && GET_MODE (op2) != opmode) 1482: size += 12; 1483: 1484: /* 12 more if first and third operand types not the same. */ 1485: if (op2 && GET_MODE (op0) != GET_MODE (op2)) 1486: size += 12; 1487: 1488: /* CMP and CMPT need additional. Also, compute size of save/restore here. */ 1489: if (code == EQ) 1490: size += 32; 1491: else if (code == GE) 1492: size += 64; 1493: else if (code == USE || code == CLOBBER) 1494: { 1495: /* 34 + 24 for each additional register plus 8 if fr7 saved. (We 1496: call it 36 because we need to keep the block length a multiple 1497: of four. */ 1498: size = 36 - 24; 1499: for (i = 0; i <= 7; i++) 1500: if (INTVAL (op0) & (1 << (7-i))) 1501: size += 24 + 8 * (i == 7); 1502: } 1503: 1504: /* We provide no general-purpose scratch registers. */ 1505: size +=16; 1506: 1507: /* No floating-point scratch registers are provided. Compute extra 1508: length due to this. This logic is that shown in the referenced 1509: appendix. */ 1510: 1511: i = 0; 1512: if (op0 && GET_CODE (op0) == REG && FP_REGNO_P (REGNO (op0))) 1513: i++; 1514: if (op1 && GET_CODE (op1) == REG && FP_REGNO_P (REGNO (op1))) 1515: i++; 1516: if (op2 && GET_CODE (op2) == REG && FP_REGNO_P (REGNO (op2))) 1517: i++; 1518: 1519: if ((op0 == 0 || GET_CODE (op0) != REG || REGNO(op0) != 17) 1520: && (op1 == 0 || GET_CODE (op1) != REG || REGNO(op1) != 17) 1521: && (op2 == 0 || GET_CODE (op2) != REG || REGNO(op2) != 17)) 1522: fr0_avail = 1; 1523: 1524: if (dyadic) 1525: { 1526: if (i == 0) 1527: size += fr0_avail ? 64 : 112; 1528: else if (fpop->noperands == 2 && i == 1) 1529: size += fr0_avail ? 0 : 64; 1530: else if (fpop->noperands == 3) 1531: { 1532: if (GET_CODE (op0) == REG && FP_REGNO_P (REGNO (op0)) 1533: && GET_CODE (op2) == REG && FP_REGNO_P (REGNO (op2))) 1534: { 1535: if (REGNO (op0) == REGNO (op2)) 1536: #if 1 1537: /* This triggers a bug on the RT. */ 1538: abort (); 1539: #else 1540: size += fr0_avail ? 0 : 64; 1541: #endif 1542: } 1543: else 1544: { 1545: i = 0; 1546: if (GET_CODE (op0) == REG && FP_REGNO_P (REGNO (op0))) 1547: i++; 1548: if (GET_CODE (op2) == REG && FP_REGNO_P (REGNO (op2))) 1549: i++; 1550: if (i == 0) 1551: size += fr0_avail ? 64 : 112; 1552: else if (i == 1) 1553: size += fr0_avail ? 0 : 64; 1554: } 1555: } 1556: } 1557: else if (code != USE && code != CLOBBER 1558: && (GET_CODE (op0) != REG || ! FP_REGNO_P (REGNO (op0)))) 1559: size += 64; 1560: 1561: if (! TARGET_FULL_FP_BLOCKS) 1562: { 1563: /* If we are not to pad the blocks, just compute its actual length. */ 1564: size = 12; /* Header + opcode */ 1565: if (code == USE || code == CLOBBER) 1566: size += 2; 1567: else 1568: { 1569: if (op0) size += 2; 1570: if (op1) size += 2; 1571: if (op2) size += 2; 1572: } 1573: 1574: /* If in the middle of a word, round. */ 1575: if (size % UNITS_PER_WORD) 1576: size += 2; 1577: 1578: /* Handle any immediates. */ 1579: if (code != USE && code != CLOBBER && op0 && GET_CODE (op0) != REG) 1580: size += 4; 1581: if (op1 && GET_CODE (op1) != REG) 1582: size += 4; 1583: if (op2 && GET_CODE (op2) != REG) 1584: size += 4; 1585: 1586: if (code != USE && code != CLOBBER && 1587: op0 && GET_CODE (op0) == CONST_DOUBLE && GET_MODE (op0) == DFmode) 1588: size += 4; 1589: if (op1 && GET_CODE (op1) == CONST_DOUBLE && GET_MODE (op1) == DFmode) 1590: size += 4; 1591: if (op2 && GET_CODE (op2) == CONST_DOUBLE && GET_MODE (op2) == DFmode) 1592: size += 4; 1593: } 1594: 1595: /* Done with size computation! Chain this in. */ 1596: fpop->size = size; 1597: data_offset += size / UNITS_PER_WORD; 1598: fpop->next_in_mem = 0; 1599: fpop->next_same_hash = 0; 1600: 1601: if (last_fpop_in_mem) 1602: last_fpop_in_mem->next_in_mem = fpop; 1603: else 1604: first_fpop = fpop; 1605: last_fpop_in_mem = fpop; 1606: 1607: if (last_fpop) 1608: last_fpop->next_same_hash = fpop; 1609: else 1610: fp_hash_table[hash] = fpop; 1611: 1612: win: 1613: /* FPOP describes the operation to be performed. Return a string to branch 1614: to it. */ 1615: if (fpop->mem_offset < 32768 / UNITS_PER_WORD) 1616: sprintf (outbuf, "cal r15,%d(r14)\n\tbalr%s r15,r15", 1617: fpop->mem_offset * UNITS_PER_WORD, 1618: dbr_sequence_length () ? "x" : ""); 1619: else 1620: sprintf (outbuf, "get r15,$L%dF%d\n\tbalr%s r15,r15", 1621: subr_number, fpop->mem_offset * UNITS_PER_WORD, 1622: dbr_sequence_length () ? "x" : ""); 1623: return outbuf; 1624: } 1625: 1626: /* If necessary, output a floating-point operation to save or restore all 1627: floating-point registers. 1628: 1629: file is the file to write the operation to, CODE is USE for save, CLOBBER 1630: for restore, and ADDR is the address of the same area, as RTL. */ 1631: 1632: static void 1633: output_loadsave_fpregs (file, code, addr) 1634: FILE *file; 1635: enum rtx_code code; 1636: rtx addr; 1637: { 1638: register int i; 1639: register int mask = 0; 1640: 1641: for (i = 2 + (TARGET_FP_REGS != 0); i <= 7; i++) 1642: if (regs_ever_live[i + 17]) 1643: mask |= 1 << (7 - i); 1644: 1645: if (mask) 1646: fprintf (file, "\t%s\n", 1647: output_fpop (code, gen_rtx (CONST_INT, VOIDmode, mask), 1648: gen_rtx (MEM, Pmode, addr), 1649: 0, const0_rtx)); 1650: 1651: } 1652: 1653: /* Output any floating-point operations at the end of the routine. */ 1654: 1655: static void 1656: output_fpops (file) 1657: FILE *file; 1658: { 1659: register struct fp_op *fpop; 1660: register int size_so_far; 1661: register int i; 1662: rtx immed[3]; 1663: 1664: if (first_fpop == 0) 1665: return; 1666: 1667: data_section (); 1668: 1669: ASM_OUTPUT_ALIGN (file, 2); 1670: 1671: for (fpop = first_fpop; fpop; fpop = fpop->next_in_mem) 1672: { 1673: if (fpop->mem_offset < 32768 / UNITS_PER_WORD) 1674: fprintf (file, "# data area offset = %d\n", 1675: fpop->mem_offset * UNITS_PER_WORD); 1676: else 1677: fprintf (file, "L%dF%d:\n", 1678: subr_number, fpop->mem_offset * UNITS_PER_WORD); 1679: 1680: fprintf (file, "\tcas r0,r15,r0\n"); 1681: fprintf (file, "\t.long FPGLUE\n"); 1682: switch (fpop->opcode) 1683: { 1684: case USE: 1685: fprintf (file, "\t.byte 0x1d\t# STOREM\n"); 1686: break; 1687: case CLOBBER: 1688: fprintf (file, "\t.byte 0x0f\t# LOADM\n"); 1689: break; 1690: case ABS: 1691: fprintf (file, "\t.byte 0x00\t# ABS\n"); 1692: break; 1693: case PLUS: 1694: fprintf (file, "\t.byte 0x02\t# ADD\n"); 1695: break; 1696: case EQ: 1697: fprintf (file, "\t.byte 0x07\t# CMP\n"); 1698: break; 1699: case GE: 1700: fprintf (file, "\t.byte 0x08\t# CMPT\n"); 1701: break; 1702: case DIV: 1703: fprintf (file, "\t.byte 0x0c\t# DIV\n"); 1704: break; 1705: case SET: 1706: fprintf (file, "\t.byte 0x14\t# MOVE\n"); 1707: break; 1708: case MULT: 1709: fprintf (file, "\t.byte 0x15\t# MUL\n"); 1710: break; 1711: case NEG: 1712: fprintf (file, "\t.byte 0x16\t# NEG\n"); 1713: break; 1714: case SQRT: 1715: fprintf (file, "\t.byte 0x1c\t# SQRT\n"); 1716: break; 1717: case MINUS: 1718: fprintf (file, "\t.byte 0x1e\t# SUB\n"); 1719: break; 1720: default: 1721: abort (); 1722: } 1723: 1724: fprintf (file, "\t.byte %d\n", fpop->noperands); 1725: fprintf (file, "\t.short 0x8001\n"); 1726: 1727: if ((fpop->ops[0] == 0 1728: || GET_CODE (fpop->ops[0]) != REG || REGNO(fpop->ops[0]) != 17) 1729: && (fpop->ops[1] == 0 || GET_CODE (fpop->ops[1]) != REG 1730: || REGNO(fpop->ops[1]) != 17) 1731: && (fpop->ops[2] == 0 || GET_CODE (fpop->ops[2]) != REG 1732: || REGNO(fpop->ops[2]) != 17)) 1733: fprintf (file, "\t.byte %d, 0x80\n", fpop->size); 1734: else 1735: fprintf (file, "\t.byte %d, 0\n", fpop->size); 1736: size_so_far = 12; 1737: for (i = 0; i < fpop->noperands; i++) 1738: { 1739: register int type; 1740: register int opbyte; 1741: register char *desc0; 1742: char desc1[50]; 1743: 1744: immed[i] = 0; 1745: switch (GET_MODE (fpop->ops[i])) 1746: { 1747: case SImode: 1748: case VOIDmode: 1749: desc0 = "int"; 1750: type = 0; 1751: break; 1752: case SFmode: 1753: desc0 = "float"; 1754: type = 2; 1755: break; 1756: case DFmode: 1757: desc0 = "double"; 1758: type = 3; 1759: break; 1760: default: 1761: abort (); 1762: } 1763: 1764: switch (GET_CODE (fpop->ops[i])) 1765: { 1766: case REG: 1767: strcpy(desc1, reg_names[REGNO (fpop->ops[i])]); 1768: if (FP_REGNO_P (REGNO (fpop->ops[i]))) 1769: { 1770: type += 0x10; 1771: opbyte = REGNO (fpop->ops[i]) - 17; 1772: } 1773: else 1774: { 1775: type += 0x00; 1776: opbyte = REGNO (fpop->ops[i]); 1777: if (type == 3) 1778: opbyte = (opbyte << 4) + opbyte + 1; 1779: } 1780: break; 1781: 1782: case MEM: 1783: type += 0x30; 1784: if (GET_CODE (XEXP (fpop->ops[i], 0)) == PLUS) 1785: { 1786: immed[i] = XEXP (XEXP (fpop->ops[i], 0), 1); 1787: opbyte = REGNO (XEXP (XEXP (fpop->ops[i], 0), 0)); 1788: if (GET_CODE (immed[i]) == CONST_INT) 1789: sprintf (desc1, "%d(%s)", INTVAL (immed[i]), 1790: reg_names[opbyte]); 1791: else 1792: sprintf (desc1, "<memory> (%s)", reg_names[opbyte]); 1793: } 1794: else if (GET_CODE (XEXP (fpop->ops[i], 0)) == REG) 1795: { 1796: opbyte = REGNO (XEXP (fpop->ops[i], 0)); 1797: immed[i] = const0_rtx; 1798: sprintf (desc1, "(%s)", reg_names[opbyte]); 1799: } 1800: else 1801: { 1802: immed[i] = XEXP (fpop->ops[i], 0); 1803: opbyte = 0; 1804: sprintf(desc1, "<memory>"); 1805: } 1806: break; 1807: 1808: case CONST_INT: 1809: case CONST_DOUBLE: 1810: case CONST: 1.1.1.4 ! root 1811: case SYMBOL_REF: ! 1812: case LABEL_REF: 1.1 root 1813: type += 0x20; 1814: opbyte = 0; 1815: immed[i] = fpop->ops[i]; 1816: desc1[0] = '$'; 1817: desc1[1] = '\0'; 1818: break; 1819: 1820: default: 1821: abort (); 1822: } 1823: 1824: /* Save/restore is special. */ 1825: if (i == 0 && (fpop->opcode == USE || fpop->opcode == CLOBBER)) 1826: type = 0xff, opbyte = INTVAL (fpop->ops[0]), immed[i] = 0; 1827: 1828: fprintf (file, "\t.byte 0x%x,0x%x # (%s) %s\n", 1829: type, opbyte, desc0, desc1); 1830: 1831: size_so_far += 2; 1832: } 1833: 1834: /* If in the middle of a word, round. */ 1835: if (size_so_far % UNITS_PER_WORD) 1836: { 1837: fprintf (file, "\t.space 2\n"); 1838: size_so_far += 2; 1839: } 1840: 1841: for (i = 0; i < fpop->noperands; i++) 1842: if (immed[i]) 1843: switch (GET_MODE (immed[i])) 1844: { 1845: case SImode: 1846: case VOIDmode: 1847: size_so_far += 4; 1848: fprintf (file, "\t.long "); 1849: output_addr_const (file, immed[i]); 1850: fprintf (file, "\n"); 1851: break; 1852: 1853: case DFmode: 1854: size_so_far += 4; 1855: case SFmode: 1856: size_so_far += 4; 1857: if (GET_CODE (immed[i]) == CONST_DOUBLE) 1858: { 1859: union real_extract u; 1860: 1861: bcopy (&CONST_DOUBLE_LOW (immed[i]), &u, sizeof u); 1862: if (GET_MODE (immed[i]) == DFmode) 1863: ASM_OUTPUT_DOUBLE (file, u.d); 1864: else 1865: ASM_OUTPUT_FLOAT (file, u.d); 1866: } 1867: else 1868: abort (); 1869: break; 1870: 1871: default: 1872: abort (); 1873: } 1874: 1875: if (size_so_far != fpop->size) 1876: { 1877: if (TARGET_FULL_FP_BLOCKS) 1878: fprintf (file, "\t.space %d\n", fpop->size - size_so_far); 1879: else 1880: abort (); 1881: } 1882: } 1883: 1884: /* Update for next subroutine. */ 1885: subr_number++; 1886: text_section (); 1887: } 1888: 1889: /* Initialize floating-point operation table. */ 1890: 1891: static void 1892: init_fpops() 1893: { 1894: register int i; 1895: 1896: first_fpop = last_fpop_in_mem = 0; 1897: for (i = 0; i < FP_HASH_SIZE; i++) 1898: fp_hash_table[i] = 0; 1899: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.