|
|
1.1 ! root 1: /* Subroutines used for code generation on ROMP. ! 2: Copyright (C) 1990, 1991, 1992, 1993 Free Software Foundation, Inc. ! 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: ! 616: /* Return 1 if this is a valid floating-point conversion that can be done ! 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 '.': ! 932: /* Output nothing. Used as delimiter in, e.g., "mc%B1%.3 " */ ! 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: int fp_save = size + current_function_outgoing_args_size; ! 1080: ! 1081: init_fpops (); ! 1082: ! 1083: /* Add in fixed size plus output argument area. */ ! 1084: size += romp_sa_size () + current_function_outgoing_args_size; ! 1085: ! 1086: /* Compute first register to save and perform the save operation if anything ! 1087: needs to be saved. */ ! 1088: first_reg = first_reg_to_save(); ! 1089: reg_save_offset = - (4 + 4 + 1 + (16 - first_reg)) * 4; ! 1090: if (first_reg == 15) ! 1091: fprintf (file, "\tst r15,%d(r1)\n", reg_save_offset); ! 1092: else if (first_reg < 16) ! 1093: fprintf (file, "\tstm r%d,%d(r1)\n", first_reg, reg_save_offset); ! 1094: ! 1095: /* Set up pointer to data area if it is needed. */ ! 1096: if (romp_using_r14 ()) ! 1097: fprintf (file, "\tcas r14,r0,r0\n"); ! 1098: ! 1099: /* Set up frame pointer if needed. */ ! 1100: if (frame_pointer_needed) ! 1101: fprintf (file, "\tcal r13,-%d(r1)\n", romp_sa_size () + 64); ! 1102: ! 1103: /* Push stack if neeeded. There are a couple of ways of doing this. */ ! 1104: if (romp_pushes_stack ()) ! 1105: { ! 1106: if (size >= 32768) ! 1107: { ! 1108: if (size >= 65536) ! 1109: { ! 1110: fprintf (file, "\tcau r0,%d(r0)\n", size >> 16); ! 1111: fprintf (file, "\toil r0,r0,%d\n", size & 0xffff); ! 1112: } ! 1113: else ! 1114: fprintf (file, "\tcal16 r0,%d(r0)\n", size); ! 1115: fprintf (file, "\ts r1,r0\n"); ! 1116: } ! 1117: else ! 1118: fprintf (file, "\tcal r1,-%d(r1)\n", size); ! 1119: } ! 1120: ! 1121: /* Save floating-point registers. */ ! 1122: output_loadsave_fpregs (file, USE, ! 1123: plus_constant (stack_pointer_rtx, fp_save)); ! 1124: } ! 1125: ! 1126: /* Output the offset information used by debuggers. ! 1127: This is the exactly the total_size value of output_epilog ! 1128: which is added to the frame pointer. However the value in the debug ! 1129: table is encoded in a space-saving way as follows: ! 1130: ! 1131: The first byte contains two fields: a 2-bit size field and the first ! 1132: 6 bits of an offset value. The 2-bit size field is in the high-order ! 1133: position and specifies how many subsequent bytes follow after ! 1134: this one. An offset value is at most 4-bytes long. ! 1135: ! 1136: The last 6 bits of the first byte initialize the offset value. In many ! 1137: cases where procedures have small local storage, this is enough and, in ! 1138: this case, the high-order size field is zero so the byte can (almost) be ! 1139: used as is (see below). Thus, the byte value of 0x0d is encodes a offset ! 1140: size of 13 words, or 52 bytes. ! 1141: ! 1142: For procedures with a local space larger than 60 bytes, the 6 bits ! 1143: are the high-order 6 bits. The remaining bytes follow as necessary, ! 1144: in Big Endian order. Thus, the short value of 16907 (= 16384+523) ! 1145: encodes an offset of 2092 bytes (523 words). ! 1146: ! 1147: The total offset value is in words (not bytes), so the final value has to ! 1148: be multiplied by 4 before it can be used in address computations by a ! 1149: debugger. */ ! 1150: ! 1151: void ! 1152: output_encoded_offset (file, reg_offset) ! 1153: FILE *file; ! 1154: unsigned reg_offset; ! 1155: { ! 1156: /* Convert the offset value to 4-byte words rather than bytes. */ ! 1157: reg_offset = (reg_offset + 3) / 4; ! 1158: ! 1159: /* Now output 1-4 bytes in encoded form. */ ! 1160: if (reg_offset < (1 << 6)) ! 1161: /* Fits into one byte */ ! 1162: fprintf (file, "\t.byte %d\n", reg_offset); ! 1163: else if (reg_offset < (1 << (6 + 8))) ! 1164: /* Fits into two bytes */ ! 1165: fprintf (file, "\t.short %d\n", (1 << (6 + 8)) + reg_offset); ! 1166: else if (reg_offset < (1 << (6 + 8 + 8))) ! 1167: { ! 1168: /* Fits in three bytes */ ! 1169: fprintf (file, "\t.byte %d\n", (2 << 6) + (reg_offset >> ( 6+ 8))); ! 1170: fprintf (file, "\t.short %d\n", reg_offset % (1 << (6 + 8))); ! 1171: } ! 1172: else ! 1173: { ! 1174: /* Use 4 bytes. */ ! 1175: fprintf (file, "\t.short %d", (3 << (6 + 8)) + (reg_offset >> (6 + 8))); ! 1176: fprintf (file, "\t.short %d\n", reg_offset % (1 << (6 + 8))); ! 1177: } ! 1178: } ! 1179: ! 1180: /* Write function epilogue. */ ! 1181: ! 1182: void ! 1183: output_epilog (file, size) ! 1184: FILE *file; ! 1185: int size; ! 1186: { ! 1187: int first_reg = first_reg_to_save(); ! 1188: int pushes_stack = romp_pushes_stack (); ! 1189: int reg_save_offset = - ((16 - first_reg) + 1 + 4 + 4) * 4; ! 1190: int total_size = (size + romp_sa_size () ! 1191: + current_function_outgoing_args_size); ! 1192: int fp_save = size + current_function_outgoing_args_size; ! 1193: int long_frame = total_size >= 32768; ! 1194: rtx insn = get_last_insn (); ! 1195: int write_code = 1; ! 1196: ! 1197: int nargs = 0; /* words of arguments */ ! 1198: tree argptr; ! 1199: ! 1200: /* Compute the number of words of arguments. Since this is just for ! 1201: the traceback table, we ignore arguments that don't have a size or ! 1202: don't have a fixed size. */ ! 1203: ! 1204: for (argptr = DECL_ARGUMENTS (current_function_decl); ! 1205: argptr; argptr = TREE_CHAIN (argptr)) ! 1206: { ! 1207: int this_size = int_size_in_bytes (TREE_TYPE (argptr)); ! 1208: ! 1209: if (this_size > 0) ! 1210: nargs += (this_size + UNITS_PER_WORD - 1) / UNITS_PER_WORD; ! 1211: } ! 1212: ! 1213: /* If the last insn was a BARRIER, we don't have to write anything except ! 1214: the trace table. */ ! 1215: if (GET_CODE (insn) == NOTE) ! 1216: insn = prev_nonnote_insn (insn); ! 1217: if (insn && GET_CODE (insn) == BARRIER) ! 1218: write_code = 0; ! 1219: ! 1220: /* Restore floating-point registers. */ ! 1221: if (write_code) ! 1222: output_loadsave_fpregs (file, CLOBBER, ! 1223: gen_rtx (PLUS, Pmode, gen_rtx (REG, Pmode, 1), ! 1224: gen_rtx (CONST_INT, VOIDmode, fp_save))); ! 1225: ! 1226: /* If we push the stack and do not have size > 32K, adjust the register ! 1227: save location to the current position of sp. Otherwise, if long frame, ! 1228: restore sp from fp. */ ! 1229: if (pushes_stack && ! long_frame) ! 1230: reg_save_offset += total_size; ! 1231: else if (long_frame && write_code) ! 1232: fprintf (file, "\tcal r1,%d(r13)\n", romp_sa_size () + 64); ! 1233: ! 1234: /* Restore registers. */ ! 1235: if (first_reg == 15 && write_code) ! 1236: fprintf (file, "\tl r15,%d(r1)\n", reg_save_offset); ! 1237: else if (first_reg < 16 && write_code) ! 1238: fprintf (file, "\tlm r%d,%d(r1)\n", first_reg, reg_save_offset); ! 1239: if (first_reg == 16) first_reg = 0; ! 1240: ! 1241: /* Handle popping stack, if needed and write debug table entry. */ ! 1242: if (pushes_stack) ! 1243: { ! 1244: if (write_code) ! 1245: { ! 1246: if (long_frame) ! 1247: fprintf (file, "\tbr r15\n"); ! 1248: else ! 1249: fprintf (file, "\tbrx r15\n\tcal r1,%d(r1)\n", total_size); ! 1250: } ! 1251: ! 1252: /* Table header (0xdf), usual-type stack frame (0x07), ! 1253: table header (0xdf), and first register saved. ! 1254: ! 1255: The final 0x08 means that there is a byte following this one ! 1256: describing the number of parameter words and the register used as ! 1257: stack pointer. ! 1258: ! 1259: If GCC passed floating-point parameters in floating-point registers, ! 1260: it would be necessary to change the final byte from 0x08 to 0x0c. ! 1261: Also an additional entry byte would be need to be emitted to specify ! 1262: the first floating-point register. ! 1263: ! 1264: (See also Section 11 (Trace Tables) in ``IBM/4.3 Linkage Convention,'' ! 1265: pages IBM/4.3-PSD:5-7 of Volume III of the IBM Academic Operating ! 1266: System Manual dated July 1987.) */ ! 1267: ! 1268: fprintf (file, "\t.long 0x%x\n", 0xdf07df08 + first_reg * 0x10); ! 1269: ! 1270: if (nargs > 15) nargs = 15; ! 1271: ! 1272: /* The number of parameter words and the register used as the stack ! 1273: pointer (encoded here as r1). ! 1274: ! 1275: Note: The MetWare Hich C Compiler R2.1y actually gets this wrong; ! 1276: it erroneously lists r13 but uses r1 as the stack too. But a bug in ! 1277: dbx 1.5 nullifies this mistake---most of the time. ! 1278: (Dbx retrieves the value of r13 saved on the stack which is often ! 1279: the value of r1 before the call.) */ ! 1280: ! 1281: fprintf (file, "\t.byte 0x%x1\n", nargs); ! 1282: output_encoded_offset (file, total_size); ! 1283: } ! 1284: else ! 1285: { ! 1286: if (write_code) ! 1287: fprintf (file, "\tbr r15\n"); ! 1288: ! 1289: /* Table header (0xdf), no stack frame (0x02), ! 1290: table header (0xdf) and no parameters saved (0x00). ! 1291: ! 1292: If GCC passed floating-point parameters in floating-point registers, ! 1293: it might be necessary to change the final byte from 0x00 to 0x04. ! 1294: Also a byte would be needed to specify the first floating-point ! 1295: register. */ ! 1296: fprintf (file, "\t.long 0xdf02df00\n"); ! 1297: } ! 1298: ! 1299: /* Output any pending floating-point operations. */ ! 1300: output_fpops (file); ! 1301: } ! 1302: ! 1303: /* For the ROMP we need to make new SYMBOL_REFs for the actual name of a ! 1304: called routine. To keep them unique we maintain a hash table of all ! 1305: that have been created so far. */ ! 1306: ! 1307: struct symref_hashent { ! 1308: rtx symref; /* Created SYMBOL_REF rtx. */ ! 1309: struct symref_hashent *next; /* Next with same hash code. */ ! 1310: }; ! 1311: ! 1312: #define SYMHASHSIZE 151 ! 1313: #define HASHBITS 65535 ! 1314: ! 1315: /* Define the hash table itself. */ ! 1316: ! 1317: static struct symref_hashent *symref_hash_table[SYMHASHSIZE]; ! 1318: ! 1319: /* Given a name (allocatable in temporary storage), return a SYMBOL_REF ! 1320: for the name. The rtx is allocated from the current rtl_obstack, while ! 1321: the name string is allocated from the permanent obstack. */ ! 1322: rtx ! 1323: get_symref (name) ! 1324: register char *name; ! 1325: { ! 1326: extern struct obstack permanent_obstack; ! 1327: register char *sp = name; ! 1328: unsigned int hash = 0; ! 1329: struct symref_hashent *p, **last_p; ! 1330: ! 1331: /* Compute the hash code for the string. */ ! 1332: while (*sp) ! 1333: hash = (hash << 4) + *sp++; ! 1334: ! 1335: /* Search for a matching entry in the hash table, keeping track of the ! 1336: insertion location as we do so. */ ! 1337: hash = (hash & HASHBITS) % SYMHASHSIZE; ! 1338: for (last_p = &symref_hash_table[hash], p = *last_p; ! 1339: p; last_p = &p->next, p = *last_p) ! 1340: if (strcmp (name, XSTR (p->symref, 0)) == 0) ! 1341: break; ! 1342: ! 1343: /* If couldn't find matching SYMBOL_REF, make a new one. */ ! 1344: if (p == 0) ! 1345: { ! 1346: /* Ensure SYMBOL_REF will stay around. */ ! 1347: end_temporary_allocation (); ! 1348: p = *last_p = (struct symref_hashent *) ! 1349: permalloc (sizeof (struct symref_hashent)); ! 1350: p->symref = gen_rtx (SYMBOL_REF, Pmode, ! 1351: obstack_copy0 (&permanent_obstack, ! 1352: name, strlen (name))); ! 1353: p->next = 0; ! 1354: resume_temporary_allocation (); ! 1355: } ! 1356: ! 1357: return p->symref; ! 1358: } ! 1359: ! 1360: /* Validate the precision of a floating-point operation. ! 1361: ! 1362: We merge conversions from integers and between floating-point modes into ! 1363: the insn. However, this must not effect the desired precision of the ! 1364: insn. The RT floating-point system uses the widest of the operand modes. ! 1365: If this should be a double-precision insn, ensure that one operand ! 1366: passed to the floating-point processor has double mode. ! 1367: ! 1368: Note that since we don't check anything if the mode is single precision, ! 1369: it, strictly speaking, isn't necessary to call this for those insns. ! 1370: However, we do so in case something else needs to be checked in the ! 1371: future. ! 1372: ! 1373: This routine returns 1 if the operation is OK. */ ! 1374: ! 1375: int ! 1376: check_precision (opmode, op1, op2) ! 1377: enum machine_mode opmode; ! 1378: rtx op1, op2; ! 1379: { ! 1380: if (opmode == SFmode) ! 1381: return 1; ! 1382: ! 1383: /* If operand is not a conversion from an integer mode or an extension from ! 1384: single-precision, it must be a double-precision value. */ ! 1385: if (GET_CODE (op1) != FLOAT && GET_CODE (op1) != FLOAT_EXTEND) ! 1386: return 1; ! 1387: ! 1388: if (op2 && GET_CODE (op2) != FLOAT && GET_CODE (op2) != FLOAT_EXTEND) ! 1389: return 1; ! 1390: ! 1391: return 0; ! 1392: } ! 1393: ! 1394: /* Floating-point on the RT is done by creating an operation block in the data ! 1395: area that describes the operation. If two floating-point operations are the ! 1396: same in a single function, they can use the same block. ! 1397: ! 1398: These routines are responsible for managing these blocks. */ ! 1399: ! 1400: /* Structure to describe a floating-point operation. */ ! 1401: ! 1402: struct fp_op { ! 1403: struct fp_op *next_same_hash; /* Next op with same hash code. */ ! 1404: struct fp_op *next_in_mem; /* Next op in memory. */ ! 1405: int mem_offset; /* Offset from data area. */ ! 1406: short size; /* Size of block in bytes. */ ! 1407: short noperands; /* Number of operands in block. */ ! 1408: rtx ops[3]; /* RTL for operands. */ ! 1409: enum rtx_code opcode; /* Operation being performed. */ ! 1410: }; ! 1411: ! 1412: /* Size of hash table. */ ! 1413: #define FP_HASH_SIZE 101 ! 1414: ! 1415: /* Hash table of floating-point operation blocks. */ ! 1416: static struct fp_op *fp_hash_table[FP_HASH_SIZE]; ! 1417: ! 1418: /* First floating-point block in data area. */ ! 1419: static struct fp_op *first_fpop; ! 1420: ! 1421: /* Last block in data area so far. */ ! 1422: static struct fp_op *last_fpop_in_mem; ! 1423: ! 1424: /* Subroutine number in file, to get unique "LF" labels. */ ! 1425: static int subr_number = 0; ! 1426: ! 1427: /* Current word offset in data area (includes header and any constant pool). */ ! 1428: int data_offset; ! 1429: ! 1430: /* Compute hash code for an RTX used in floating-point. */ ! 1431: ! 1432: static unsigned int ! 1433: hash_rtx (x) ! 1434: register rtx x; ! 1435: { ! 1436: register unsigned int hash = (((int) GET_CODE (x) << 10) ! 1437: + ((int) GET_MODE (x) << 20)); ! 1438: register int i; ! 1439: register char *fmt = GET_RTX_FORMAT (GET_CODE (x)); ! 1440: ! 1441: for (i = 0; i < GET_RTX_LENGTH (GET_CODE (x)); i++) ! 1442: if (fmt[i] == 'e') ! 1443: hash += hash_rtx (XEXP (x, i)); ! 1444: else if (fmt[i] == 'u') ! 1445: hash += (int) XEXP (x, i); ! 1446: else if (fmt[i] == 'i') ! 1447: hash += XINT (x, i); ! 1448: else if (fmt[i] == 's') ! 1449: hash += (int) XSTR (x, i); ! 1450: ! 1451: return hash; ! 1452: } ! 1453: ! 1454: /* Given an operation code and up to three operands, return a character string ! 1455: corresponding to the code to emit to branch to a floating-point operation ! 1456: block. INSN is provided to see if the delay slot has been filled or not. ! 1457: ! 1458: A new floating-point operation block is created if this operation has not ! 1459: been seen before. */ ! 1460: ! 1461: char * ! 1462: output_fpop (code, op0, op1, op2, insn) ! 1463: enum rtx_code code; ! 1464: rtx op0, op1, op2; ! 1465: rtx insn; ! 1466: { ! 1467: static char outbuf[40]; ! 1468: unsigned int hash, hash0, hash1, hash2; ! 1469: int size, i; ! 1470: register struct fp_op *fpop, *last_fpop; ! 1471: int dyadic = (op2 != 0); ! 1472: enum machine_mode opmode; ! 1473: int noperands; ! 1474: rtx tem; ! 1475: unsigned int tem_hash; ! 1476: int fr0_avail = 0; ! 1477: ! 1478: /* Compute hash code for each operand. If the operation is commutative, ! 1479: put the one with the smaller hash code first. This will make us see ! 1480: more operations as identical. */ ! 1481: hash0 = op0 ? hash_rtx (op0) : 0; ! 1482: hash1 = op1 ? hash_rtx (op1) : 0; ! 1483: hash2 = op2 ? hash_rtx (op2) : 0; ! 1484: ! 1485: if (hash0 > hash1 && code == EQ) ! 1486: { ! 1487: tem = op0; op0 = op1; op1 = tem; ! 1488: tem_hash = hash0; hash0 = hash1; hash1 = tem_hash; ! 1489: } ! 1490: else if (hash1 > hash2 && (code == PLUS || code == MULT)) ! 1491: { ! 1492: tem = op1; op1 = op2; op2 = tem; ! 1493: tem_hash = hash1; hash1 = hash2; hash2 = tem_hash; ! 1494: } ! 1495: ! 1496: /* If operation is commutative and the first and third operands are equal, ! 1497: swap the second and third operands. Note that we must consider two ! 1498: operands equal if they are the same register even if different modes. */ ! 1499: if (op2 && (code == PLUS || code == MULT) ! 1500: && (rtx_equal_p (op0, op2) ! 1501: || (GET_CODE (op0) == REG && GET_CODE (op2) == REG ! 1502: && REGNO (op0) == REGNO (op2)))) ! 1503: { ! 1504: tem = op1; op1 = op2; op2 = tem; ! 1505: tem_hash = hash1; hash1 = hash2; hash2 = tem_hash; ! 1506: } ! 1507: ! 1508: /* If the first and second operands are the same, merge them. Don't do this ! 1509: for SFmode or SImode in general registers because this triggers a bug in ! 1510: the RT fp code. */ ! 1511: if (op1 && rtx_equal_p (op0, op1) ! 1512: && code != EQ && code != GE && code != SET ! 1513: && ((GET_MODE (op1) != SFmode && GET_MODE (op1) != SImode) ! 1514: || GET_CODE (op0) != REG || FP_REGNO_P (REGNO (op0)))) ! 1515: { ! 1516: op1 = op2; ! 1517: op2 = 0; ! 1518: } ! 1519: ! 1520: noperands = 1 + (op1 != 0) + (op2 != 0); ! 1521: ! 1522: /* Compute hash code for entire expression and see if operation block ! 1523: already exists. */ ! 1524: hash = ((int) code << 13) + (hash0 << 2) + (hash1 << 1) + hash2; ! 1525: ! 1526: hash %= FP_HASH_SIZE; ! 1527: for (fpop = fp_hash_table[hash], last_fpop = 0; ! 1528: fpop; ! 1529: last_fpop = fpop, fpop = fpop->next_same_hash) ! 1530: if (fpop->opcode == code && noperands == fpop->noperands ! 1531: && (op0 == 0 || rtx_equal_p (op0, fpop->ops[0])) ! 1532: && (op1 == 0 || rtx_equal_p (op1, fpop->ops[1])) ! 1533: && (op2 == 0 || rtx_equal_p (op2, fpop->ops[2]))) ! 1534: goto win; ! 1535: ! 1536: /* We have never seen this operation before. */ ! 1537: fpop = (struct fp_op *) oballoc (sizeof (struct fp_op)); ! 1538: fpop->mem_offset = data_offset; ! 1539: fpop->opcode = code; ! 1540: fpop->noperands = noperands; ! 1541: fpop->ops[0] = op0; ! 1542: fpop->ops[1] = op1; ! 1543: fpop->ops[2] = op2; ! 1544: ! 1545: /* Compute the size using the rules in Appendix A of the RT Linkage ! 1546: Convention (4.3/RT-PSD:5) manual. These rules are a bit ambiguous, ! 1547: but if we guess wrong, it will effect only efficiency, not correctness. */ ! 1548: ! 1549: /* Size = 24 + 32 for each non-fp (or fr7) */ ! 1550: size = 24; ! 1551: if (op0 && (GET_CODE (op0) != REG ! 1552: || ! FP_REGNO_P (REGNO (op0)) || REGNO (op0) == 23)) ! 1553: size += 32; ! 1554: ! 1555: if (op1 && (GET_CODE (op1) != REG ! 1556: || ! FP_REGNO_P (REGNO (op1)) || REGNO (op1) == 23)) ! 1557: size += 32; ! 1558: ! 1559: if (op2 && (GET_CODE (op2) != REG ! 1560: || ! FP_REGNO_P (REGNO (op2)) || REGNO (op2) == 23)) ! 1561: size += 32; ! 1562: ! 1563: /* Size + 12 for each conversion. First get operation mode. */ ! 1564: if ((op0 && GET_MODE (op0) == DFmode) ! 1565: || (op1 && GET_MODE (op1) == DFmode) ! 1566: || (op2 && GET_MODE (op2) == DFmode)) ! 1567: opmode = DFmode; ! 1568: else ! 1569: opmode = SFmode; ! 1570: ! 1571: if (op0 && GET_MODE (op0) != opmode) ! 1572: size += 12; ! 1573: if (op1 && GET_MODE (op1) != opmode) ! 1574: size += 12; ! 1575: if (op2 && GET_MODE (op2) != opmode) ! 1576: size += 12; ! 1577: ! 1578: /* 12 more if first and third operand types not the same. */ ! 1579: if (op2 && GET_MODE (op0) != GET_MODE (op2)) ! 1580: size += 12; ! 1581: ! 1582: /* CMP and CMPT need additional. Also, compute size of save/restore here. */ ! 1583: if (code == EQ) ! 1584: size += 32; ! 1585: else if (code == GE) ! 1586: size += 64; ! 1587: else if (code == USE || code == CLOBBER) ! 1588: { ! 1589: /* 34 + 24 for each additional register plus 8 if fr7 saved. (We ! 1590: call it 36 because we need to keep the block length a multiple ! 1591: of four. */ ! 1592: size = 36 - 24; ! 1593: for (i = 0; i <= 7; i++) ! 1594: if (INTVAL (op0) & (1 << (7-i))) ! 1595: size += 24 + 8 * (i == 7); ! 1596: } ! 1597: ! 1598: /* We provide no general-purpose scratch registers. */ ! 1599: size +=16; ! 1600: ! 1601: /* No floating-point scratch registers are provided. Compute extra ! 1602: length due to this. This logic is that shown in the referenced ! 1603: appendix. */ ! 1604: ! 1605: i = 0; ! 1606: if (op0 && GET_CODE (op0) == REG && FP_REGNO_P (REGNO (op0))) ! 1607: i++; ! 1608: if (op1 && GET_CODE (op1) == REG && FP_REGNO_P (REGNO (op1))) ! 1609: i++; ! 1610: if (op2 && GET_CODE (op2) == REG && FP_REGNO_P (REGNO (op2))) ! 1611: i++; ! 1612: ! 1613: if ((op0 == 0 || GET_CODE (op0) != REG || REGNO(op0) != 17) ! 1614: && (op1 == 0 || GET_CODE (op1) != REG || REGNO(op1) != 17) ! 1615: && (op2 == 0 || GET_CODE (op2) != REG || REGNO(op2) != 17)) ! 1616: fr0_avail = 1; ! 1617: ! 1618: if (dyadic) ! 1619: { ! 1620: if (i == 0) ! 1621: size += fr0_avail ? 64 : 112; ! 1622: else if (fpop->noperands == 2 && i == 1) ! 1623: size += fr0_avail ? 0 : 64; ! 1624: else if (fpop->noperands == 3) ! 1625: { ! 1626: if (GET_CODE (op0) == REG && FP_REGNO_P (REGNO (op0)) ! 1627: && GET_CODE (op2) == REG && FP_REGNO_P (REGNO (op2))) ! 1628: { ! 1629: if (REGNO (op0) == REGNO (op2)) ! 1630: #if 1 ! 1631: /* This triggers a bug on the RT. */ ! 1632: abort (); ! 1633: #else ! 1634: size += fr0_avail ? 0 : 64; ! 1635: #endif ! 1636: } ! 1637: else ! 1638: { ! 1639: i = 0; ! 1640: if (GET_CODE (op0) == REG && FP_REGNO_P (REGNO (op0))) ! 1641: i++; ! 1642: if (GET_CODE (op2) == REG && FP_REGNO_P (REGNO (op2))) ! 1643: i++; ! 1644: if (i == 0) ! 1645: size += fr0_avail ? 64 : 112; ! 1646: else if (i == 1) ! 1647: size += fr0_avail ? 0 : 64; ! 1648: } ! 1649: } ! 1650: } ! 1651: else if (code != USE && code != CLOBBER ! 1652: && (GET_CODE (op0) != REG || ! FP_REGNO_P (REGNO (op0)))) ! 1653: size += 64; ! 1654: ! 1655: if (! TARGET_FULL_FP_BLOCKS) ! 1656: { ! 1657: /* If we are not to pad the blocks, just compute its actual length. */ ! 1658: size = 12; /* Header + opcode */ ! 1659: if (code == USE || code == CLOBBER) ! 1660: size += 2; ! 1661: else ! 1662: { ! 1663: if (op0) size += 2; ! 1664: if (op1) size += 2; ! 1665: if (op2) size += 2; ! 1666: } ! 1667: ! 1668: /* If in the middle of a word, round. */ ! 1669: if (size % UNITS_PER_WORD) ! 1670: size += 2; ! 1671: ! 1672: /* Handle any immediates. */ ! 1673: if (code != USE && code != CLOBBER && op0 && GET_CODE (op0) != REG) ! 1674: size += 4; ! 1675: if (op1 && GET_CODE (op1) != REG) ! 1676: size += 4; ! 1677: if (op2 && GET_CODE (op2) != REG) ! 1678: size += 4; ! 1679: ! 1680: if (code != USE && code != CLOBBER && ! 1681: op0 && GET_CODE (op0) == CONST_DOUBLE && GET_MODE (op0) == DFmode) ! 1682: size += 4; ! 1683: if (op1 && GET_CODE (op1) == CONST_DOUBLE && GET_MODE (op1) == DFmode) ! 1684: size += 4; ! 1685: if (op2 && GET_CODE (op2) == CONST_DOUBLE && GET_MODE (op2) == DFmode) ! 1686: size += 4; ! 1687: } ! 1688: ! 1689: /* Done with size computation! Chain this in. */ ! 1690: fpop->size = size; ! 1691: data_offset += size / UNITS_PER_WORD; ! 1692: fpop->next_in_mem = 0; ! 1693: fpop->next_same_hash = 0; ! 1694: ! 1695: if (last_fpop_in_mem) ! 1696: last_fpop_in_mem->next_in_mem = fpop; ! 1697: else ! 1698: first_fpop = fpop; ! 1699: last_fpop_in_mem = fpop; ! 1700: ! 1701: if (last_fpop) ! 1702: last_fpop->next_same_hash = fpop; ! 1703: else ! 1704: fp_hash_table[hash] = fpop; ! 1705: ! 1706: win: ! 1707: /* FPOP describes the operation to be performed. Return a string to branch ! 1708: to it. */ ! 1709: if (fpop->mem_offset < 32768 / UNITS_PER_WORD) ! 1710: sprintf (outbuf, "cal r15,%d(r14)\n\tbalr%s r15,r15", ! 1711: fpop->mem_offset * UNITS_PER_WORD, ! 1712: dbr_sequence_length () ? "x" : ""); ! 1713: else ! 1714: sprintf (outbuf, "get r15,$L%dF%d\n\tbalr%s r15,r15", ! 1715: subr_number, fpop->mem_offset * UNITS_PER_WORD, ! 1716: dbr_sequence_length () ? "x" : ""); ! 1717: return outbuf; ! 1718: } ! 1719: ! 1720: /* If necessary, output a floating-point operation to save or restore all ! 1721: floating-point registers. ! 1722: ! 1723: file is the file to write the operation to, CODE is USE for save, CLOBBER ! 1724: for restore, and ADDR is the address of the same area, as RTL. */ ! 1725: ! 1726: static void ! 1727: output_loadsave_fpregs (file, code, addr) ! 1728: FILE *file; ! 1729: enum rtx_code code; ! 1730: rtx addr; ! 1731: { ! 1732: register int i; ! 1733: register int mask = 0; ! 1734: ! 1735: for (i = 2 + (TARGET_FP_REGS != 0); i <= 7; i++) ! 1736: if (regs_ever_live[i + 17]) ! 1737: mask |= 1 << (7 - i); ! 1738: ! 1739: if (mask) ! 1740: fprintf (file, "\t%s\n", ! 1741: output_fpop (code, gen_rtx (CONST_INT, VOIDmode, mask), ! 1742: gen_rtx (MEM, Pmode, addr), ! 1743: 0, const0_rtx)); ! 1744: ! 1745: } ! 1746: ! 1747: /* Output any floating-point operations at the end of the routine. */ ! 1748: ! 1749: static void ! 1750: output_fpops (file) ! 1751: FILE *file; ! 1752: { ! 1753: register struct fp_op *fpop; ! 1754: register int size_so_far; ! 1755: register int i; ! 1756: rtx immed[3]; ! 1757: ! 1758: if (first_fpop == 0) ! 1759: return; ! 1760: ! 1761: data_section (); ! 1762: ! 1763: ASM_OUTPUT_ALIGN (file, 2); ! 1764: ! 1765: for (fpop = first_fpop; fpop; fpop = fpop->next_in_mem) ! 1766: { ! 1767: if (fpop->mem_offset < 32768 / UNITS_PER_WORD) ! 1768: fprintf (file, "# data area offset = %d\n", ! 1769: fpop->mem_offset * UNITS_PER_WORD); ! 1770: else ! 1771: fprintf (file, "L%dF%d:\n", ! 1772: subr_number, fpop->mem_offset * UNITS_PER_WORD); ! 1773: ! 1774: fprintf (file, "\tcas r0,r15,r0\n"); ! 1775: fprintf (file, "\t.long FPGLUE\n"); ! 1776: switch (fpop->opcode) ! 1777: { ! 1778: case USE: ! 1779: fprintf (file, "\t.byte 0x1d\t# STOREM\n"); ! 1780: break; ! 1781: case CLOBBER: ! 1782: fprintf (file, "\t.byte 0x0f\t# LOADM\n"); ! 1783: break; ! 1784: case ABS: ! 1785: fprintf (file, "\t.byte 0x00\t# ABS\n"); ! 1786: break; ! 1787: case PLUS: ! 1788: fprintf (file, "\t.byte 0x02\t# ADD\n"); ! 1789: break; ! 1790: case EQ: ! 1791: fprintf (file, "\t.byte 0x07\t# CMP\n"); ! 1792: break; ! 1793: case GE: ! 1794: fprintf (file, "\t.byte 0x08\t# CMPT\n"); ! 1795: break; ! 1796: case DIV: ! 1797: fprintf (file, "\t.byte 0x0c\t# DIV\n"); ! 1798: break; ! 1799: case SET: ! 1800: fprintf (file, "\t.byte 0x14\t# MOVE\n"); ! 1801: break; ! 1802: case MULT: ! 1803: fprintf (file, "\t.byte 0x15\t# MUL\n"); ! 1804: break; ! 1805: case NEG: ! 1806: fprintf (file, "\t.byte 0x16\t# NEG\n"); ! 1807: break; ! 1808: case SQRT: ! 1809: fprintf (file, "\t.byte 0x1c\t# SQRT\n"); ! 1810: break; ! 1811: case MINUS: ! 1812: fprintf (file, "\t.byte 0x1e\t# SUB\n"); ! 1813: break; ! 1814: default: ! 1815: abort (); ! 1816: } ! 1817: ! 1818: fprintf (file, "\t.byte %d\n", fpop->noperands); ! 1819: fprintf (file, "\t.short 0x8001\n"); ! 1820: ! 1821: if ((fpop->ops[0] == 0 ! 1822: || GET_CODE (fpop->ops[0]) != REG || REGNO(fpop->ops[0]) != 17) ! 1823: && (fpop->ops[1] == 0 || GET_CODE (fpop->ops[1]) != REG ! 1824: || REGNO(fpop->ops[1]) != 17) ! 1825: && (fpop->ops[2] == 0 || GET_CODE (fpop->ops[2]) != REG ! 1826: || REGNO(fpop->ops[2]) != 17)) ! 1827: fprintf (file, "\t.byte %d, 0x80\n", fpop->size); ! 1828: else ! 1829: fprintf (file, "\t.byte %d, 0\n", fpop->size); ! 1830: size_so_far = 12; ! 1831: for (i = 0; i < fpop->noperands; i++) ! 1832: { ! 1833: register int type; ! 1834: register int opbyte; ! 1835: register char *desc0; ! 1836: char desc1[50]; ! 1837: ! 1838: immed[i] = 0; ! 1839: switch (GET_MODE (fpop->ops[i])) ! 1840: { ! 1841: case SImode: ! 1842: case VOIDmode: ! 1843: desc0 = "int"; ! 1844: type = 0; ! 1845: break; ! 1846: case SFmode: ! 1847: desc0 = "float"; ! 1848: type = 2; ! 1849: break; ! 1850: case DFmode: ! 1851: desc0 = "double"; ! 1852: type = 3; ! 1853: break; ! 1854: default: ! 1855: abort (); ! 1856: } ! 1857: ! 1858: switch (GET_CODE (fpop->ops[i])) ! 1859: { ! 1860: case REG: ! 1861: strcpy(desc1, reg_names[REGNO (fpop->ops[i])]); ! 1862: if (FP_REGNO_P (REGNO (fpop->ops[i]))) ! 1863: { ! 1864: type += 0x10; ! 1865: opbyte = REGNO (fpop->ops[i]) - 17; ! 1866: } ! 1867: else ! 1868: { ! 1869: type += 0x00; ! 1870: opbyte = REGNO (fpop->ops[i]); ! 1871: if (type == 3) ! 1872: opbyte = (opbyte << 4) + opbyte + 1; ! 1873: } ! 1874: break; ! 1875: ! 1876: case MEM: ! 1877: type += 0x30; ! 1878: if (GET_CODE (XEXP (fpop->ops[i], 0)) == PLUS) ! 1879: { ! 1880: immed[i] = XEXP (XEXP (fpop->ops[i], 0), 1); ! 1881: opbyte = REGNO (XEXP (XEXP (fpop->ops[i], 0), 0)); ! 1882: if (GET_CODE (immed[i]) == CONST_INT) ! 1883: sprintf (desc1, "%d(%s)", INTVAL (immed[i]), ! 1884: reg_names[opbyte]); ! 1885: else ! 1886: sprintf (desc1, "<memory> (%s)", reg_names[opbyte]); ! 1887: } ! 1888: else if (GET_CODE (XEXP (fpop->ops[i], 0)) == REG) ! 1889: { ! 1890: opbyte = REGNO (XEXP (fpop->ops[i], 0)); ! 1891: immed[i] = const0_rtx; ! 1892: sprintf (desc1, "(%s)", reg_names[opbyte]); ! 1893: } ! 1894: else ! 1895: { ! 1896: immed[i] = XEXP (fpop->ops[i], 0); ! 1897: opbyte = 0; ! 1898: sprintf(desc1, "<memory>"); ! 1899: } ! 1900: break; ! 1901: ! 1902: case CONST_INT: ! 1903: case CONST_DOUBLE: ! 1904: case CONST: ! 1905: case SYMBOL_REF: ! 1906: case LABEL_REF: ! 1907: type += 0x20; ! 1908: opbyte = 0; ! 1909: immed[i] = fpop->ops[i]; ! 1910: desc1[0] = '$'; ! 1911: desc1[1] = '\0'; ! 1912: break; ! 1913: ! 1914: default: ! 1915: abort (); ! 1916: } ! 1917: ! 1918: /* Save/restore is special. */ ! 1919: if (i == 0 && (fpop->opcode == USE || fpop->opcode == CLOBBER)) ! 1920: type = 0xff, opbyte = INTVAL (fpop->ops[0]), immed[i] = 0; ! 1921: ! 1922: fprintf (file, "\t.byte 0x%x,0x%x # (%s) %s\n", ! 1923: type, opbyte, desc0, desc1); ! 1924: ! 1925: size_so_far += 2; ! 1926: } ! 1927: ! 1928: /* If in the middle of a word, round. */ ! 1929: if (size_so_far % UNITS_PER_WORD) ! 1930: { ! 1931: fprintf (file, "\t.space 2\n"); ! 1932: size_so_far += 2; ! 1933: } ! 1934: ! 1935: for (i = 0; i < fpop->noperands; i++) ! 1936: if (immed[i]) ! 1937: switch (GET_MODE (immed[i])) ! 1938: { ! 1939: case SImode: ! 1940: case VOIDmode: ! 1941: size_so_far += 4; ! 1942: fprintf (file, "\t.long "); ! 1943: output_addr_const (file, immed[i]); ! 1944: fprintf (file, "\n"); ! 1945: break; ! 1946: ! 1947: case DFmode: ! 1948: size_so_far += 4; ! 1949: case SFmode: ! 1950: size_so_far += 4; ! 1951: if (GET_CODE (immed[i]) == CONST_DOUBLE) ! 1952: { ! 1953: union real_extract u; ! 1954: ! 1955: bcopy (&CONST_DOUBLE_LOW (immed[i]), &u, sizeof u); ! 1956: if (GET_MODE (immed[i]) == DFmode) ! 1957: ASM_OUTPUT_DOUBLE (file, u.d); ! 1958: else ! 1959: ASM_OUTPUT_FLOAT (file, u.d); ! 1960: } ! 1961: else ! 1962: abort (); ! 1963: break; ! 1964: ! 1965: default: ! 1966: abort (); ! 1967: } ! 1968: ! 1969: if (size_so_far != fpop->size) ! 1970: { ! 1971: if (TARGET_FULL_FP_BLOCKS) ! 1972: fprintf (file, "\t.space %d\n", fpop->size - size_so_far); ! 1973: else ! 1974: abort (); ! 1975: } ! 1976: } ! 1977: ! 1978: /* Update for next subroutine. */ ! 1979: subr_number++; ! 1980: text_section (); ! 1981: } ! 1982: ! 1983: /* Initialize floating-point operation table. */ ! 1984: ! 1985: static void ! 1986: init_fpops() ! 1987: { ! 1988: register int i; ! 1989: ! 1990: first_fpop = last_fpop_in_mem = 0; ! 1991: for (i = 0; i < FP_HASH_SIZE; i++) ! 1992: fp_hash_table[i] = 0; ! 1993: } ! 1994: ! 1995: /* Return the offset value of an automatic variable (N_LSYM) having ! 1996: the given offset. Basically, we correct by going from a frame pointer to ! 1997: stack pointer value. ! 1998: */ ! 1999: ! 2000: int ! 2001: romp_debugger_auto_correction(offset) ! 2002: int offset; ! 2003: { ! 2004: int fp_to_sp; ! 2005: ! 2006: /* We really want to go from STACK_POINTER_REGNUM to ! 2007: FRAME_POINTER_REGNUM, but this isn't defined. So go the other ! 2008: direction and negate. */ ! 2009: INITIAL_ELIMINATION_OFFSET (FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM, ! 2010: fp_to_sp); ! 2011: ! 2012: /* The offset value points somewhere between the frame pointer and ! 2013: the stack pointer. What is up from the frame pointer is down from the ! 2014: stack pointer. Therefore the negation in the offset value too. */ ! 2015: ! 2016: return -(offset+fp_to_sp+4); ! 2017: } ! 2018: ! 2019: /* Return the offset value of an argument having ! 2020: the given offset. Basically, we correct by going from a arg pointer to ! 2021: stack pointer value. */ ! 2022: ! 2023: int ! 2024: romp_debugger_arg_correction (offset) ! 2025: int offset; ! 2026: { ! 2027: int fp_to_argp; ! 2028: ! 2029: INITIAL_ELIMINATION_OFFSET (ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM, ! 2030: fp_to_argp); ! 2031: ! 2032: /* Actually, something different happens if offset is from a floating-point ! 2033: register argument, but we don't handle it here. */ ! 2034: ! 2035: return (offset - fp_to_argp); ! 2036: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.