|
|
1.1 ! root 1: /* Manage RTL for C-Compiler ! 2: Copyright (C) 1987, 1988 Free Software Foundation, Inc. ! 3: ! 4: This file is part of GNU CC. ! 5: ! 6: GNU CC is distributed in the hope that it will be useful, ! 7: but WITHOUT ANY WARRANTY. No author or distributor ! 8: accepts responsibility to anyone for the consequences of using it ! 9: or for whether it serves any particular purpose or works at all, ! 10: unless he says so in writing. Refer to the GNU CC General Public ! 11: License for full details. ! 12: ! 13: Everyone is granted permission to copy, modify and redistribute ! 14: GNU CC, but only under the conditions described in the ! 15: GNU CC General Public License. A copy of this license is ! 16: supposed to have been given to you along with GNU CC so you ! 17: can know your rights and responsibilities. It should be in a ! 18: file named COPYING. Among other things, the copyright notice ! 19: and this notice must be preserved on all copies. */ ! 20: ! 21: ! 22: /* This file contains the low level primitives for allocating, ! 23: printing and reading rtl expressions and vectors. ! 24: It also contains some functions for semantic analysis ! 25: on rtl expressions. */ ! 26: ! 27: #include "config.h" ! 28: #include <ctype.h> ! 29: #include <stdio.h> ! 30: #include "rtl.h" ! 31: ! 32: #include "obstack.h" ! 33: #define obstack_chunk_alloc xmalloc ! 34: #define obstack_chunk_free free ! 35: extern int xmalloc (); ! 36: extern void free (); ! 37: ! 38: /* Obstack used for allocating RTL objects. ! 39: Between functions, this is the permanent_obstack. ! 40: While parsing and expanding a function, this is maybepermanent_obstack ! 41: so we can save it if it is an inline function. ! 42: During optimization and output, this is temporary_obstack. */ ! 43: ! 44: extern struct obstack *rtl_obstack; ! 45: ! 46: #define MIN(x,y) ((x < y) ? x : y) ! 47: ! 48: extern long ftell(); ! 49: ! 50: /* Indexed by rtx code, gives number of operands for an rtx with that code. ! 51: Does NOT include rtx header data (code and links). ! 52: This array is initialized in init_rtx. */ ! 53: ! 54: int rtx_length[NUM_RTX_CODE + 1]; ! 55: ! 56: /* Indexed by rtx code, gives the name of that kind of rtx, as a C string. */ ! 57: ! 58: #define DEF_RTL_EXPR(ENUM, NAME, FORMAT) NAME , ! 59: ! 60: char *rtx_name[] = { ! 61: #include "rtl.def" /* rtl expressions are documented here */ ! 62: }; ! 63: ! 64: #undef DEF_RTL_EXPR ! 65: ! 66: /* Indexed by machine mode, gives the name of that machine mode. ! 67: This name does not include the letters "mode". */ ! 68: ! 69: #define DEF_MACHMODE(SYM, NAME, CLASS, SIZE, UNIT) NAME, ! 70: ! 71: char *mode_name[] = { ! 72: #include "machmode.def" ! 73: }; ! 74: ! 75: #undef DEF_MACHMODE ! 76: ! 77: /* Indexed by machine mode, gives the length of the mode, in bytes. ! 78: GET_MODE_CLASS uses this. */ ! 79: ! 80: #define DEF_MACHMODE(SYM, NAME, CLASS, SIZE, UNIT) CLASS, ! 81: ! 82: enum mode_class mode_class[] = { ! 83: #include "machmode.def" ! 84: }; ! 85: ! 86: #undef DEF_MACHMODE ! 87: ! 88: /* Indexed by machine mode, gives the length of the mode, in bytes. ! 89: GET_MODE_SIZE uses this. */ ! 90: ! 91: #define DEF_MACHMODE(SYM, NAME, CLASS, SIZE, UNIT) SIZE, ! 92: ! 93: int mode_size[] = { ! 94: #include "machmode.def" ! 95: }; ! 96: ! 97: #undef DEF_MACHMODE ! 98: ! 99: /* Indexed by machine mode, gives the length of the mode's subunit. ! 100: GET_MODE_UNIT_SIZE uses this. */ ! 101: ! 102: #define DEF_MACHMODE(SYM, NAME, CLASS, SIZE, UNIT) UNIT, ! 103: ! 104: int mode_unit_size[] = { ! 105: #include "machmode.def" /* machine modes are documented here */ ! 106: }; ! 107: ! 108: #undef DEF_MACHMODE ! 109: ! 110: /* Indexed by rtx code, gives a sequence of operand-types for ! 111: rtx's of that code. The sequence is a C string in which ! 112: each charcter describes one operand. */ ! 113: ! 114: char *rtx_format[] = { ! 115: /* "*" undefined. ! 116: can cause a warning message ! 117: "0" field is unused (or used in a phase-dependent manner) ! 118: prints nothing ! 119: "i" an integer ! 120: prints the integer ! 121: "s" a pointer to a string ! 122: prints the string ! 123: "e" a pointer to an rtl expression ! 124: prints the expression ! 125: "E" a pointer to a vector that points to a number of rtl expressions ! 126: prints a list of the rtl expressions ! 127: "u" a pointer to another insn ! 128: prints the uid of the insn. */ ! 129: ! 130: #define DEF_RTL_EXPR(ENUM, NAME, FORMAT) FORMAT , ! 131: #include "rtl.def" /* rtl expressions are defined here */ ! 132: #undef DEF_RTL_EXPR ! 133: }; ! 134: ! 135: /* Allocate an rtx vector of N elements. ! 136: Store the length, and initialize all elements to zero. */ ! 137: ! 138: rtvec ! 139: rtvec_alloc (n) ! 140: int n; ! 141: { ! 142: rtvec rt; ! 143: int i; ! 144: ! 145: rt = (rtvec) obstack_alloc (rtl_obstack, ! 146: sizeof (struct rtvec_def) ! 147: + (( n - 1) * sizeof (rtunion))); ! 148: ! 149: /* clear out the vector */ ! 150: PUT_NUM_ELEM(rt, n); ! 151: for (i=0; i < n; i++) ! 152: rt->elem[i].rtvec = NULL; /* @@ not portable due to rtunion */ ! 153: ! 154: return rt; ! 155: } ! 156: ! 157: /* Allocate an rtx of code CODE. The CODE is stored in the rtx; ! 158: all the rest is initialized to zero. */ ! 159: ! 160: rtx ! 161: rtx_alloc (code) ! 162: RTX_CODE code; ! 163: { ! 164: rtx rt; ! 165: register int nelts = GET_RTX_LENGTH (code); ! 166: register int length = sizeof (struct rtx_def) ! 167: + (nelts - 1) * sizeof (rtunion); ! 168: ! 169: rt = (rtx) obstack_alloc (rtl_obstack, length); ! 170: ! 171: * (int *) rt = 0; ! 172: PUT_CODE (rt, code); ! 173: ! 174: return rt; ! 175: } ! 176: ! 177: /* Create a new copy of an rtx. ! 178: Recursively copies the operands of the rtx, ! 179: except for those few rtx codes that are sharable. */ ! 180: ! 181: rtx ! 182: copy_rtx (orig) ! 183: register rtx orig; ! 184: { ! 185: register rtx copy; ! 186: register int i, j; ! 187: register RTX_CODE code; ! 188: register char *format_ptr; ! 189: ! 190: code = GET_CODE (orig); ! 191: ! 192: switch (code) ! 193: { ! 194: case REG: ! 195: case QUEUED: ! 196: case CONST_INT: ! 197: case CONST_DOUBLE: ! 198: case SYMBOL_REF: ! 199: case CODE_LABEL: ! 200: case PC: ! 201: case CC0: ! 202: return orig; ! 203: } ! 204: ! 205: copy = rtx_alloc (code); ! 206: PUT_MODE (copy, GET_MODE (orig)); ! 207: copy->in_struct = orig->in_struct; ! 208: copy->volatil = orig->volatil; ! 209: copy->unchanging = orig->unchanging; ! 210: copy->integrated = orig->integrated; ! 211: ! 212: format_ptr = GET_RTX_FORMAT (GET_CODE (copy)); ! 213: ! 214: for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++) ! 215: { ! 216: switch (*format_ptr++) ! 217: { ! 218: case 'e': ! 219: XEXP (copy, i) = copy_rtx (XEXP (orig, i)); ! 220: break; ! 221: ! 222: case 'E': ! 223: XVEC (copy, i) = XVEC (orig, i); ! 224: if (XVEC (orig, i) != NULL) ! 225: { ! 226: XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i)); ! 227: for (j = 0; j < XVECLEN (copy, i); j++) ! 228: XVECEXP (copy, i, j) = copy_rtx (XVECEXP (orig, i, j)); ! 229: } ! 230: break; ! 231: ! 232: default: ! 233: XINT (copy, i) = XINT (orig, i); ! 234: break; ! 235: } ! 236: } ! 237: return copy; ! 238: } ! 239: ! 240: /* Return 1 if the value of X is unstable ! 241: (would be different at a different point in the program). ! 242: The frame pointer, arg pointer, etc. are considered stable ! 243: (within one function) and so is anything marked `unchanging'. */ ! 244: ! 245: int ! 246: rtx_unstable_p (x) ! 247: rtx x; ! 248: { ! 249: register RTX_CODE code = GET_CODE (x); ! 250: register int i; ! 251: register char *fmt; ! 252: ! 253: if (code == MEM) ! 254: return ! x->unchanging; ! 255: ! 256: if (code == QUEUED) ! 257: return 1; ! 258: ! 259: if (code == CONST || code == CONST_INT) ! 260: return 0; ! 261: ! 262: if (code == REG) ! 263: return ! (REGNO (x) == FRAME_POINTER_REGNUM ! 264: || REGNO (x) == ARG_POINTER_REGNUM ! 265: || x->unchanging); ! 266: ! 267: fmt = GET_RTX_FORMAT (code); ! 268: for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) ! 269: if (fmt[i] == 'e') ! 270: if (rtx_unstable_p (XEXP (x, i))) ! 271: return 1; ! 272: return 0; ! 273: } ! 274: ! 275: /* Return 1 if X has a value that can vary even between two ! 276: executions of the program. 0 means X can be compared reliably ! 277: against certain constants or near-constants. ! 278: The frame pointer and the arg pointer are considered constant. */ ! 279: ! 280: int ! 281: rtx_varies_p (x) ! 282: rtx x; ! 283: { ! 284: register RTX_CODE code = GET_CODE (x); ! 285: register int i; ! 286: register char *fmt; ! 287: ! 288: if (code == MEM) ! 289: return 1; ! 290: ! 291: if (code == QUEUED) ! 292: return 1; ! 293: ! 294: if (code == CONST || code == CONST_INT) ! 295: return 0; ! 296: ! 297: if (code == REG) ! 298: return ! (REGNO (x) == FRAME_POINTER_REGNUM ! 299: || REGNO (x) == ARG_POINTER_REGNUM); ! 300: ! 301: fmt = GET_RTX_FORMAT (code); ! 302: for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) ! 303: if (fmt[i] == 'e') ! 304: if (rtx_varies_p (XEXP (x, i))) ! 305: return 1; ! 306: return 0; ! 307: } ! 308: ! 309: /* Return 1 if X refers to a memory location whose address ! 310: cannot be compared reliably with constant addresses, ! 311: or if X refers to a BLKmode memory object. */ ! 312: ! 313: int ! 314: rtx_addr_varies_p (x) ! 315: rtx x; ! 316: { ! 317: register RTX_CODE code = GET_CODE (x); ! 318: register int i; ! 319: register char *fmt; ! 320: ! 321: if (code == MEM) ! 322: return GET_MODE (x) == BLKmode || rtx_varies_p (XEXP (x, 0)); ! 323: ! 324: fmt = GET_RTX_FORMAT (code); ! 325: for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) ! 326: if (fmt[i] == 'e') ! 327: if (rtx_addr_varies_p (XEXP (x, i))) ! 328: return 1; ! 329: return 0; ! 330: } ! 331: ! 332: /* Nonzero if register REG appears somewhere within IN. ! 333: Also works if REG is not a register; in this case it checks ! 334: for a subexpression of IN that is Lisp "equal" to REG. */ ! 335: ! 336: int ! 337: reg_mentioned_p (reg, in) ! 338: register rtx reg, in; ! 339: { ! 340: register char *fmt; ! 341: register int i; ! 342: register enum rtx_code code; ! 343: ! 344: if (in == 0) ! 345: return 0; ! 346: ! 347: if (reg == in) ! 348: return 1; ! 349: ! 350: code = GET_CODE (in); ! 351: ! 352: switch (code) ! 353: { ! 354: /* Compare registers by number. */ ! 355: case REG: ! 356: return GET_CODE (reg) == REG && REGNO (in) == REGNO (reg); ! 357: ! 358: /* These codes have no constituent expressions ! 359: and are unique. */ ! 360: case CC0: ! 361: case PC: ! 362: case CONST_INT: ! 363: case CONST: ! 364: case CONST_DOUBLE: ! 365: case LABEL_REF: ! 366: case SYMBOL_REF: ! 367: return 0; ! 368: } ! 369: ! 370: if (GET_CODE (reg) == code && rtx_equal_p (reg, in)) ! 371: return 1; ! 372: ! 373: fmt = GET_RTX_FORMAT (code); ! 374: ! 375: for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) ! 376: { ! 377: if (fmt[i] == 'E') ! 378: { ! 379: register int j; ! 380: for (j = XVECLEN (in, i) - 1; j >= 0; j--) ! 381: if (reg_mentioned_p (reg, XVECEXP (in, i, j))) ! 382: return 1; ! 383: } ! 384: else if (fmt[i] == 'e' ! 385: && reg_mentioned_p (reg, XEXP (in, i))) ! 386: return 1; ! 387: } ! 388: return 0; ! 389: } ! 390: ! 391: /* Nonzero if register REG is used in an insn between ! 392: FROM_INSN and TO_INSN (exclusive of those two). */ ! 393: ! 394: int ! 395: reg_used_between_p (reg, from_insn, to_insn) ! 396: rtx reg, from_insn, to_insn; ! 397: { ! 398: register rtx insn; ! 399: register RTX_CODE code; ! 400: for (insn = NEXT_INSN (from_insn); insn != to_insn; insn = NEXT_INSN (insn)) ! 401: if (((code = GET_CODE (insn)) == INSN ! 402: || code == JUMP_INSN || code == CALL_INSN) ! 403: && reg_mentioned_p (reg, PATTERN (insn))) ! 404: return 1; ! 405: return 0; ! 406: } ! 407: ! 408: /* Return 1 if X and Y are identical-looking rtx's. ! 409: This is the Lisp function EQUAL for rtx arguments. */ ! 410: ! 411: int ! 412: rtx_equal_p (x, y) ! 413: rtx x, y; ! 414: { ! 415: register int i; ! 416: register int hash = 0; ! 417: register RTX_CODE code = GET_CODE (x); ! 418: register char *fmt; ! 419: ! 420: if (x == y) ! 421: return 1; ! 422: ! 423: /* Rtx's of different codes cannot be equal. */ ! 424: if (code != GET_CODE (y)) ! 425: return 0; ! 426: ! 427: /* (MULT:SI x y) and (MULT:HI x y) are NOT equivalent. ! 428: (REG:SI x) and (REG:HI x) are NOT equivalent. */ ! 429: ! 430: if (GET_MODE (x) != GET_MODE (y)) ! 431: return 0; ! 432: ! 433: /* These three types of rtx's can be compared nonrecursively. */ ! 434: if (code == REG) ! 435: return (REGNO (x) == REGNO (y)); ! 436: if (code == LABEL_REF) ! 437: return XEXP (x, 0) == XEXP (y, 0); ! 438: if (code == SYMBOL_REF) ! 439: return XSTR (x, 0) == XSTR (y, 0); ! 440: ! 441: /* Compare the elements. If any pair of corresponding elements ! 442: fail to match, return 0 for the whole things. */ ! 443: ! 444: fmt = GET_RTX_FORMAT (code); ! 445: for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) ! 446: { ! 447: switch (fmt[i]) ! 448: { ! 449: case 'i': ! 450: if (XINT (x, i) != XINT (y, i)) ! 451: return 0; ! 452: break; ! 453: ! 454: case 'e': ! 455: if (rtx_equal_p (XEXP (x, i), XEXP (y, i)) == 0) ! 456: return 0; ! 457: break; ! 458: ! 459: case 's': ! 460: if (strcmp (XSTR (x, i), XSTR (y, i))) ! 461: return 0; ! 462: break; ! 463: ! 464: case '0': ! 465: break; ! 466: ! 467: /* It is believed that rtx's at this level will never ! 468: contain anything but integers and other rtx's, ! 469: except for within LABEL_REFs and SYMBOL_REFs. */ ! 470: default: ! 471: abort (); ! 472: } ! 473: } ! 474: return 1; ! 475: } ! 476: ! 477: /* Call FUN on each register or MEM that is stored into or clobbered by X. ! 478: (X would be the pattern of an insn). ! 479: FUN receives two arguments: ! 480: the REG, MEM, CC0 or PC being stored in or clobbered, ! 481: the SET or CLOBBER rtx that does the store. */ ! 482: ! 483: void ! 484: note_stores (x, fun) ! 485: register rtx x; ! 486: void (*fun) (); ! 487: { ! 488: if ((GET_CODE (x) == SET || GET_CODE (x) == CLOBBER)) ! 489: { ! 490: register rtx dest = SET_DEST (x); ! 491: while (GET_CODE (dest) == SUBREG ! 492: || GET_CODE (dest) == ZERO_EXTRACT ! 493: || GET_CODE (dest) == SIGN_EXTRACT ! 494: || GET_CODE (dest) == STRICT_LOW_PART) ! 495: dest = XEXP (dest, 0); ! 496: (*fun) (dest, GET_CODE (x) == CLOBBER); ! 497: } ! 498: else if (GET_CODE (x) == PARALLEL) ! 499: { ! 500: register int i; ! 501: for (i = XVECLEN (x, 0) - 1; i >= 0; i--) ! 502: { ! 503: register rtx y = XVECEXP (x, 0, i); ! 504: if (GET_CODE (y) == SET || GET_CODE (y) == CLOBBER) ! 505: { ! 506: register rtx dest = SET_DEST (y); ! 507: while (GET_CODE (dest) == SUBREG ! 508: || GET_CODE (dest) == ZERO_EXTRACT ! 509: || GET_CODE (dest) == SIGN_EXTRACT ! 510: || GET_CODE (dest) == STRICT_LOW_PART) ! 511: dest = XEXP (dest, 0); ! 512: (*fun) (dest, GET_CODE (y) == CLOBBER); ! 513: } ! 514: } ! 515: } ! 516: } ! 517: ! 518: /* Return nonzero if register REG's old contents don't survive after INSN. ! 519: This can be because REG dies in INSN or because INSN entirely sets REG. ! 520: ! 521: "Entirely set" means set directly and not through a SUBREG, ! 522: ZERO_EXTRACT or SIGN_EXTRACT, so no trace of the old contents remains. ! 523: ! 524: REG may be a hard or pseudo reg. Renumbering is not taken into account, ! 525: but for this use that makes no difference, since regs don't overlap ! 526: during their lifetimes. Therefore, this function may be used ! 527: at any time after deaths have been computed (in flow.c). */ ! 528: ! 529: int ! 530: dead_or_set_p (insn, reg) ! 531: rtx insn; ! 532: rtx reg; ! 533: { ! 534: register rtx link; ! 535: register int regno = REGNO (reg); ! 536: ! 537: for (link = REG_NOTES (insn); link; link = XEXP (link, 1)) ! 538: if ((REG_NOTE_KIND (link) == REG_DEAD ! 539: || REG_NOTE_KIND (link) == REG_INC) ! 540: && REGNO (XEXP (link, 0)) == regno) ! 541: return 1; ! 542: ! 543: if (GET_CODE (PATTERN (insn)) == SET) ! 544: return SET_DEST (PATTERN (insn)) == reg; ! 545: else if (GET_CODE (PATTERN (insn)) == PARALLEL) ! 546: { ! 547: register int i; ! 548: for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--) ! 549: { ! 550: if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == SET ! 551: && SET_DEST (XVECEXP (PATTERN (insn), 0, i)) == reg) ! 552: return 1; ! 553: } ! 554: } ! 555: return 0; ! 556: } ! 557: ! 558: /* Return the reg-note of kind KIND in insn INSN, if there is one. ! 559: If DATUM is nonzero, look for one whose datum is DATUM. */ ! 560: ! 561: rtx ! 562: find_reg_note (insn, kind, datum) ! 563: rtx insn; ! 564: enum reg_note kind; ! 565: rtx datum; ! 566: { ! 567: register rtx link; ! 568: ! 569: for (link = REG_NOTES (insn); link; link = XEXP (link, 1)) ! 570: if (REG_NOTE_KIND (link) == kind ! 571: && (datum == 0 || datum == XEXP (link, 0))) ! 572: return link; ! 573: return 0; ! 574: } ! 575: ! 576: /* Return the reg-note of kind KIND in insn INSN which applies to register ! 577: number REGNO, if any. Return 0 if there is no such reg-note. */ ! 578: ! 579: rtx ! 580: find_regno_note (insn, kind, regno) ! 581: rtx insn; ! 582: enum reg_note kind; ! 583: int regno; ! 584: { ! 585: register rtx link; ! 586: ! 587: for (link = REG_NOTES (insn); link; link = XEXP (link, 1)) ! 588: if (REG_NOTE_KIND (link) == kind ! 589: && REGNO (XEXP (link, 0)) == regno) ! 590: return link; ! 591: return 0; ! 592: } ! 593: ! 594: /* Printing rtl for debugging dumps. */ ! 595: ! 596: static FILE *outfile; ! 597: ! 598: char spaces[] = " "; ! 599: ! 600: static int sawclose = 0; ! 601: ! 602: /* Print IN_RTX onto OUTFILE. This is the recursive part of printing. */ ! 603: ! 604: static void ! 605: print_rtx (in_rtx) ! 606: register rtx in_rtx; ! 607: { ! 608: static int indent; ! 609: register int i, j; ! 610: register char *format_ptr; ! 611: ! 612: if (sawclose) ! 613: { ! 614: fprintf (outfile, "\n%s", ! 615: (spaces + (sizeof spaces - indent * 2))); ! 616: sawclose = 0; ! 617: } ! 618: ! 619: if (in_rtx == 0) ! 620: { ! 621: fprintf (outfile, "(nil)"); ! 622: sawclose = 1; ! 623: return; ! 624: } ! 625: ! 626: /* print name of expression code */ ! 627: fprintf (outfile, "(%s", GET_RTX_NAME (GET_CODE (in_rtx))); ! 628: ! 629: if (in_rtx->in_struct) ! 630: fprintf (outfile, "/s"); ! 631: ! 632: if (in_rtx->volatil) ! 633: fprintf (outfile, "/v"); ! 634: ! 635: if (in_rtx->unchanging) ! 636: fprintf (outfile, "/u"); ! 637: ! 638: if (in_rtx->integrated) ! 639: fprintf (outfile, "/i"); ! 640: ! 641: if (GET_MODE (in_rtx) != VOIDmode) ! 642: fprintf (outfile, ":%s", GET_MODE_NAME (GET_MODE (in_rtx))); ! 643: ! 644: format_ptr = GET_RTX_FORMAT (GET_CODE (in_rtx)); ! 645: ! 646: for (i = 0; i < GET_RTX_LENGTH (GET_CODE (in_rtx)); i++) ! 647: switch (*format_ptr++) ! 648: { ! 649: case 's': ! 650: if (XSTR (in_rtx, i) == 0) ! 651: fprintf (outfile, " \"\""); ! 652: else ! 653: fprintf (outfile, " (\"%s\")", XSTR (in_rtx, i)); ! 654: sawclose = 1; ! 655: break; ! 656: ! 657: /* 0 indicates a field for internal use that should not be printed. */ ! 658: case '0': ! 659: break; ! 660: ! 661: case 'e': ! 662: indent += 2; ! 663: if (!sawclose) ! 664: fprintf (outfile, " "); ! 665: print_rtx (XEXP (in_rtx, i)); ! 666: indent -= 2; ! 667: break; ! 668: ! 669: case 'E': ! 670: indent += 2; ! 671: if (sawclose) ! 672: { ! 673: fprintf (outfile, "\n%s", ! 674: (spaces + (sizeof spaces - indent * 2))); ! 675: sawclose = 0; ! 676: } ! 677: fprintf (outfile, "[ "); ! 678: if (NULL != XVEC (in_rtx, i)) ! 679: { ! 680: indent += 2; ! 681: if (XVECLEN (in_rtx, i)) ! 682: sawclose = 1; ! 683: ! 684: for (j = 0; j < XVECLEN (in_rtx, i); j++) ! 685: print_rtx (XVECEXP (in_rtx, i, j)); ! 686: ! 687: indent -= 2; ! 688: } ! 689: if (sawclose) ! 690: fprintf (outfile, "\n%s", ! 691: (spaces + (sizeof spaces - indent * 2))); ! 692: ! 693: fprintf (outfile, "] "); ! 694: sawclose = 1; ! 695: indent -= 2; ! 696: break; ! 697: ! 698: case 'i': ! 699: fprintf (outfile, " %d", XINT (in_rtx, i)); ! 700: sawclose = 0; ! 701: break; ! 702: ! 703: case 'u': ! 704: if (XEXP (in_rtx, i) != NULL) ! 705: fprintf(outfile, " %d", INSN_UID (XEXP (in_rtx, i))); ! 706: else ! 707: fprintf(outfile, " 0"); ! 708: sawclose = 0; ! 709: break; ! 710: ! 711: default: ! 712: fprintf (stderr, ! 713: "switch format wrong in rtl.print_rtx(). format was: %c.\n", ! 714: format_ptr[-1]); ! 715: abort (); ! 716: } ! 717: ! 718: fprintf (outfile, ")"); ! 719: sawclose = 1; ! 720: } ! 721: ! 722: /* Call this function from the debugger to see what X looks like. */ ! 723: ! 724: void ! 725: debug_rtx (x) ! 726: rtx x; ! 727: { ! 728: outfile = stderr; ! 729: print_rtx (x); ! 730: fprintf (stderr, "\n"); ! 731: } ! 732: ! 733: /* External entry point for printing a chain of INSNs ! 734: starting with RTX_FIRST onto file OUTF. */ ! 735: ! 736: void ! 737: print_rtl (outf, rtx_first) ! 738: FILE *outf; ! 739: rtx rtx_first; ! 740: { ! 741: register rtx tmp_rtx; ! 742: ! 743: outfile = outf; ! 744: sawclose = 0; ! 745: ! 746: for (tmp_rtx = rtx_first; NULL != tmp_rtx; tmp_rtx = NEXT_INSN (tmp_rtx)) ! 747: { ! 748: print_rtx (tmp_rtx); ! 749: fprintf (outfile, "\n"); ! 750: } ! 751: } ! 752: ! 753: /* Subroutines of read_rtx. */ ! 754: ! 755: /* Dump code after printing a message. Used when read_rtx finds ! 756: invalid data. */ ! 757: ! 758: static void ! 759: dump_and_abort (expected_c, actual_c, infile) ! 760: int expected_c, actual_c; ! 761: FILE *infile; ! 762: { ! 763: int c, i; ! 764: ! 765: fprintf (stderr, ! 766: "Expected character %c. Read character %c. At file position: %ld\n", ! 767: expected_c, actual_c, ftell (infile)); ! 768: fprintf (stderr, "Following characters are:\n\t"); ! 769: for (i = 0; i < 200; i++) ! 770: { ! 771: c = getc (infile); ! 772: if (EOF == c) break; ! 773: putc (c, stderr); ! 774: } ! 775: fprintf (stderr, "Aborting.\n"); ! 776: abort (); ! 777: } ! 778: ! 779: /* Read chars from INFILE until a non-whitespace char ! 780: and return that. Comments, both Lisp style and C style, ! 781: are treated as whitespace. ! 782: Tools such as genflags use this function. */ ! 783: ! 784: int ! 785: read_skip_spaces (infile) ! 786: FILE *infile; ! 787: { ! 788: register int c; ! 789: while (c = getc (infile)) ! 790: { ! 791: if (c == ' ' || c == '\n' || c == '\t' || c == '\f') ! 792: ; ! 793: else if (c == ';') ! 794: { ! 795: while ((c = getc (infile)) && c != '\n') ; ! 796: } ! 797: else if (c == '/') ! 798: { ! 799: register int prevc; ! 800: c = getc (infile); ! 801: if (c != '*') ! 802: dump_and_abort ('*', c, infile); ! 803: ! 804: prevc = 0; ! 805: while (c = getc (infile)) ! 806: { ! 807: if (prevc == '*' && c == '/') ! 808: break; ! 809: prevc = c; ! 810: } ! 811: } ! 812: else break; ! 813: } ! 814: return c; ! 815: } ! 816: ! 817: /* Read an rtx code name into the buffer STR[]. ! 818: It is terminated by any of the punctuation chars of rtx printed syntax. */ ! 819: ! 820: static void ! 821: read_name (str, infile) ! 822: char *str; ! 823: FILE *infile; ! 824: { ! 825: register char *p; ! 826: register int c; ! 827: ! 828: c = read_skip_spaces(infile); ! 829: ! 830: p = str; ! 831: while (1) ! 832: { ! 833: if (c == ' ' || c == '\n' || c == '\t' || c == '\f') ! 834: break; ! 835: if (c == ':' || c == ')' || c == ']' || c == '"' || c == '/' ! 836: || c == '(' || c == '[') ! 837: { ! 838: ungetc (c, infile); ! 839: break; ! 840: } ! 841: *p++ = c; ! 842: c = getc (infile); ! 843: } ! 844: *p = NULL; ! 845: } ! 846: ! 847: /* Read an rtx in printed representation from INFILE ! 848: and return an actual rtx in core constructed accordingly. ! 849: read_rtx is not used in the compiler proper, but rather in ! 850: the utilities gen*.c that construct C code from machine descriptions. */ ! 851: ! 852: rtx ! 853: read_rtx (infile) ! 854: FILE *infile; ! 855: { ! 856: register int i, j, list_counter; ! 857: RTX_CODE tmp_code; ! 858: register char *format_ptr; ! 859: /* tmp_char is a buffer used for reading decimal integers ! 860: and names of rtx types and machine modes. ! 861: Therefore, 256 must be enough. */ ! 862: char tmp_char[256]; ! 863: rtx return_rtx; ! 864: register int c; ! 865: int tmp_int; ! 866: ! 867: /* Linked list structure for making RTXs: */ ! 868: struct rtx_list ! 869: { ! 870: struct rtx_list *next; ! 871: rtx value; /* Value of this node... */ ! 872: }; ! 873: ! 874: c = read_skip_spaces (infile); /* Should be open paren. */ ! 875: if (c != '(') ! 876: dump_and_abort ('(', c, infile); ! 877: ! 878: read_name (tmp_char, infile); ! 879: ! 880: tmp_code = UNKNOWN; ! 881: ! 882: for (i=0; i < NUM_RTX_CODE; i++) /* @@ might speed this search up */ ! 883: { ! 884: if (!(strcmp (tmp_char, GET_RTX_NAME (i)))) ! 885: { ! 886: tmp_code = (RTX_CODE) i; /* get value for name */ ! 887: break; ! 888: } ! 889: } ! 890: if (tmp_code == UNKNOWN) ! 891: { ! 892: fprintf (stderr, ! 893: "Unknown rtx read in rtl.read_rtx(). Code name was %s .", ! 894: tmp_char); ! 895: } ! 896: /* (NIL) stands for an expression that isn't there. */ ! 897: if (tmp_code == NIL) ! 898: { ! 899: /* Discard the closeparen. */ ! 900: while ((c = getc (infile)) && c != ')'); ! 901: return 0; ! 902: } ! 903: ! 904: return_rtx = rtx_alloc (tmp_code); /* if we end up with an insn expression ! 905: then we free this space below. */ ! 906: format_ptr = GET_RTX_FORMAT (GET_CODE (return_rtx)); ! 907: ! 908: /* If what follows is `: mode ', read it and ! 909: store the mode in the rtx. */ ! 910: ! 911: i = read_skip_spaces (infile); ! 912: if (i == ':') ! 913: { ! 914: register int k; ! 915: read_name (tmp_char, infile); ! 916: for (k = 0; k < NUM_MACHINE_MODES; k++) ! 917: if (!strcmp (GET_MODE_NAME (k), tmp_char)) ! 918: break; ! 919: ! 920: PUT_MODE (return_rtx, (enum machine_mode) k ); ! 921: } ! 922: else ! 923: ungetc (i, infile); ! 924: ! 925: for (i = 0; i < GET_RTX_LENGTH (GET_CODE (return_rtx)); i++) ! 926: switch (*format_ptr++) ! 927: { ! 928: /* 0 means a field for internal use only. ! 929: Don't expect it to be present in the input. */ ! 930: case '0': ! 931: break; ! 932: ! 933: case 'e': ! 934: case 'u': ! 935: XEXP (return_rtx, i) = read_rtx (infile); ! 936: break; ! 937: ! 938: case 'E': ! 939: { ! 940: register struct rtx_list *next_rtx, *rtx_list_link; ! 941: struct rtx_list *list_rtx; ! 942: ! 943: c = read_skip_spaces (infile); ! 944: if (c != '[') ! 945: dump_and_abort ('[', c, infile); ! 946: ! 947: /* add expressions to a list, while keeping a count */ ! 948: next_rtx = NULL; ! 949: list_counter = 0; ! 950: while ((c = read_skip_spaces (infile)) && c != ']') ! 951: { ! 952: ungetc (c, infile); ! 953: list_counter++; ! 954: rtx_list_link = (struct rtx_list *) ! 955: alloca (sizeof (struct rtx_list)); ! 956: rtx_list_link->value = read_rtx (infile); ! 957: if (next_rtx == 0) ! 958: list_rtx = rtx_list_link; ! 959: else ! 960: next_rtx->next = rtx_list_link; ! 961: next_rtx = rtx_list_link; ! 962: rtx_list_link->next = 0; ! 963: } ! 964: /* get vector length and allocate it */ ! 965: XVEC (return_rtx, i) = (list_counter ! 966: ? rtvec_alloc (list_counter) ! 967: : NULL); ! 968: if (list_counter > 0) ! 969: { ! 970: next_rtx = list_rtx; ! 971: for (j = 0; j < list_counter; j++, ! 972: next_rtx = next_rtx->next) ! 973: XVECEXP (return_rtx, i, j) = next_rtx->value; ! 974: } ! 975: /* close bracket gotten */ ! 976: } ! 977: break; ! 978: ! 979: case 's': ! 980: { ! 981: int saw_paren = 0; ! 982: register char *stringbuf; ! 983: int stringbufsize; ! 984: ! 985: c = read_skip_spaces (infile); ! 986: if (c == '(') ! 987: { ! 988: saw_paren = 1; ! 989: c = read_skip_spaces (infile); ! 990: } ! 991: if (c != '"') ! 992: dump_and_abort ('"', c, infile); ! 993: j = 0; ! 994: stringbufsize = 10; ! 995: stringbuf = (char *) xmalloc (stringbufsize + 1); ! 996: ! 997: while (1) ! 998: { ! 999: if (j >= stringbufsize - 4) ! 1000: { ! 1001: stringbufsize *= 2; ! 1002: stringbuf = (char *) xrealloc (stringbuf, stringbufsize + 1); ! 1003: } ! 1004: stringbuf[j] = getc (infile); /* Read the string */ ! 1005: if (stringbuf[j] == '\\') ! 1006: { ! 1007: stringbuf[j] = getc (infile); /* Read the string */ ! 1008: /* \; makes stuff for a C string constant containing ! 1009: newline and tab. */ ! 1010: if (stringbuf[j] == ';') ! 1011: { ! 1012: strcpy (&stringbuf[j], "\\n\\t"); ! 1013: j += 3; ! 1014: } ! 1015: } ! 1016: else if (stringbuf[j] == '"') ! 1017: break; ! 1018: j++; ! 1019: } ! 1020: ! 1021: stringbuf[j] = 0; /* NUL terminate the string */ ! 1022: stringbuf = (char *) xrealloc (stringbuf, j + 1); ! 1023: ! 1024: if (saw_paren) ! 1025: { ! 1026: c = read_skip_spaces (infile); ! 1027: if (c != ')') ! 1028: dump_and_abort (')', c, infile); ! 1029: } ! 1030: XSTR (return_rtx, i) = stringbuf; ! 1031: } ! 1032: break; ! 1033: ! 1034: case 'i': ! 1035: read_name (tmp_char, infile); ! 1036: tmp_int = atoi (tmp_char); ! 1037: XINT (return_rtx, i) = tmp_int; ! 1038: break; ! 1039: ! 1040: default: ! 1041: fprintf (stderr, ! 1042: "switch format wrong in rtl.read_rtx(). format was: %c.\n", ! 1043: format_ptr[-1]); ! 1044: fprintf (stderr, "\tfile position: %ld\n", ftell (infile)); ! 1045: abort (); ! 1046: } ! 1047: ! 1048: c = read_skip_spaces (infile); ! 1049: if (c != ')') ! 1050: dump_and_abort (')', c, infile); ! 1051: ! 1052: return return_rtx; ! 1053: } ! 1054: ! 1055: /* This is called once per compilation, before any rtx's are constructed. ! 1056: It initializes the vector `rtx_length'. */ ! 1057: ! 1058: void ! 1059: init_rtl () ! 1060: { ! 1061: int i; ! 1062: ! 1063: for (i = 0; i < NUM_RTX_CODE; i++) ! 1064: rtx_length[i] = strlen (rtx_format[i]); ! 1065: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.