|
|
1.1 ! root 1: /* Emit RTL for the GNU C-Compiler expander. ! 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: /* Middle-to-low level generation of rtx code and insns. ! 23: ! 24: This file contains the functions `gen_rtx', `gen_reg_rtx' ! 25: and `gen_label_rtx' that are the usual ways of creating rtl ! 26: expressions for most purposes. ! 27: ! 28: It also has the functions for creating insns and linking ! 29: them in the doubly-linked chain. ! 30: ! 31: The patterns of the insns are created by machine-dependent ! 32: routines in insn-emit.c, which is generated automatically from ! 33: the machine description. These routines use `gen_rtx' to make ! 34: the individual rtx's of the pattern; what is machine dependent ! 35: is the kind of rtx's they make and what arguments they use. */ ! 36: ! 37: #include "config.h" ! 38: #include <stdio.h> ! 39: #include "varargs.h" ! 40: #include "rtl.h" ! 41: #include "regs.h" ! 42: #include "insn-config.h" ! 43: ! 44: #define max(A,B) ((A) > (B) ? (A) : (B)) ! 45: #define min(A,B) ((A) < (B) ? (A) : (B)) ! 46: ! 47: /* This is reset to FIRST_PSEUDO_REGISTER at the start each function. ! 48: After rtl generation, it is 1 plus the largest register number used. */ ! 49: ! 50: int reg_rtx_no = FIRST_PSEUDO_REGISTER; ! 51: ! 52: /* This is *not* reset after each function. It gives each CODE_LABEL ! 53: in the entire compilation a unique label number. */ ! 54: ! 55: static int label_num = 1; ! 56: ! 57: /* Value of `label_num' at start of current function. */ ! 58: ! 59: static int first_label_num; ! 60: ! 61: /* Nonzero means do not generate NOTEs for source line numbers. */ ! 62: ! 63: static int no_line_numbers; ! 64: ! 65: /* Commonly used rtx's, so that we only need space for one copy. ! 66: These are initialized once for the entire compilation. ! 67: All of these except perhaps fconst0_rtx and dconst0_rtx ! 68: are unique; no other rtx-object will be equal to any of these. */ ! 69: ! 70: rtx pc_rtx; /* (PC) */ ! 71: rtx cc0_rtx; /* (CC0) */ ! 72: rtx cc1_rtx; /* (CC1) (not actually used nowadays) */ ! 73: rtx const0_rtx; /* (CONST_INT 0) */ ! 74: rtx const1_rtx; /* (CONST_INT 1) */ ! 75: rtx fconst0_rtx; /* (CONST_DOUBLE:SF 0) */ ! 76: rtx dconst0_rtx; /* (CONST_DOUBLE:DF 0) */ ! 77: ! 78: /* All references to the following fixed hard registers go through ! 79: these unique rtl objects. On machines where the frame-pointer and ! 80: arg-pointer are the same register, they use the same unique object. ! 81: ! 82: After register allocation, other rtl objects which used to be pseudo-regs ! 83: may be clobbered to refer to the frame-pointer register. ! 84: But references that were originally to the frame-pointer can be ! 85: distinguished from the others because they contain frame_pointer_rtx. ! 86: ! 87: In an inline procedure, the stack and frame pointer rtxs may not be ! 88: used for anything else. */ ! 89: rtx stack_pointer_rtx; /* (REG:Pmode STACK_POINTER_REGNUM) */ ! 90: rtx frame_pointer_rtx; /* (REG:Pmode FRAME_POINTER_REGNUM) */ ! 91: rtx arg_pointer_rtx; /* (REG:Pmode ARG_POINTER_REGNUM) */ ! 92: rtx struct_value_rtx; /* (REG:Pmode STRUCT_VALUE_REGNUM) */ ! 93: rtx struct_value_incoming_rtx; /* (REG:Pmode STRUCT_VALUE_INCOMING_REGNUM) */ ! 94: rtx static_chain_rtx; /* (REG:Pmode STATIC_CHAIN_REGNUM) */ ! 95: rtx static_chain_incoming_rtx; /* (REG:Pmode STATIC_CHAIN_INCOMING_REGNUM) */ ! 96: ! 97: /* The ends of the doubly-linked chain of rtl for the current function. ! 98: Both are reset to null at the start of rtl generation for the function. */ ! 99: ! 100: static rtx first_insn = NULL; ! 101: static rtx last_insn = NULL; ! 102: ! 103: /* The ends of a similar chain of rtl insns to become part ! 104: of the SEQUENCE returned by a gen_... function (in insn-emit.c). ! 105: This allows define_expand to use subroutines that call emit_insn. */ ! 106: static rtx sequence_first_insn = NULL; ! 107: static rtx sequence_last_insn = NULL; ! 108: ! 109: /* Nonzero if emit_insn should add to the sequence_first_insn chain ! 110: instead of the ordinary chain. */ ! 111: int emit_to_sequence; ! 112: ! 113: /* First insn used for something other than copying parms or changing their modes. */ ! 114: static rtx first_noninit_insn = NULL; ! 115: ! 116: /* INSN_UID for next insn emitted. ! 117: Reset to 1 for each function compiled. */ ! 118: ! 119: static int cur_insn_uid = 1; ! 120: ! 121: /* Line number and source file of the last line-number NOTE emitted. ! 122: This is used to avoid generating duplicates. */ ! 123: ! 124: static int last_linenum = 0; ! 125: static char *last_filename = 0; ! 126: ! 127: /* A vector indexed by pseudo reg number. The allocated length ! 128: of this vector is regno_pointer_flag_length. Since this ! 129: vector is needed during the expansion phase when the total ! 130: number of registers in the function is not yet known, ! 131: it is copied and made bigger when necessary. */ ! 132: ! 133: char *regno_pointer_flag; ! 134: int regno_pointer_flag_length; ! 135: ! 136: /* Indexed by pseudo register number, gives the rtx for that pseudo. ! 137: Allocated in parallel with regno_pointer_flag. */ ! 138: ! 139: rtx *regno_reg_rtx; ! 140: ! 141: /* Chain of all CONST_DOUBLEs made for this function; ! 142: so we can uniquize them. */ ! 143: ! 144: rtx real_constant_chain; ! 145: ! 146: /* rtx gen_rtx (code, mode, [element1, ..., elementn]) ! 147: ** ! 148: ** This routine generates an RTX of the size specified by ! 149: ** <code>, which is an RTX code. The RTX structure is initialized ! 150: ** from the arguments <element1> through <elementn>, which are ! 151: ** interpreted according to the specific RTX type's format. The ! 152: ** special machine mode associated with the rtx (if any) is specified ! 153: ** in <mode>. ! 154: ** ! 155: ** gen_rtx() can be invoked in a way which resembles the lisp-like ! 156: ** rtx it will generate. For example, the following rtx structure: ! 157: ** ! 158: ** (plus:QI (mem:QI (reg:SI 1)) ! 159: ** (mem:QI (plusw:SI (reg:SI 2) (reg:SI 3)))) ! 160: ** ! 161: ** ...would be generated by the following C code: ! 162: ** ! 163: ** gen_rtx (PLUS, QImode, ! 164: ** gen_rtx (MEM, QImode, ! 165: ** gen_rtx (REG, SImode, 1)), ! 166: ** gen_rtx (MEM, QImode, ! 167: ** gen_rtx (PLUS, SImode, ! 168: ** gen_rtx (REG, SImode, 2), ! 169: ** gen_rtx (REG, SImode, 3)))), ! 170: */ ! 171: ! 172: /*VARARGS2*/ ! 173: rtx ! 174: gen_rtx (va_alist) ! 175: va_dcl ! 176: { ! 177: va_list p; ! 178: enum rtx_code code; ! 179: enum machine_mode mode; ! 180: register char *argp; /* Pointer to arguments... */ ! 181: register int i; /* Array indices... */ ! 182: register char *fmt; /* Current rtx's format... */ ! 183: register rtx rt_val; /* RTX to return to caller... */ ! 184: ! 185: va_start (p); ! 186: code = va_arg (p, enum rtx_code); ! 187: mode = va_arg (p, enum machine_mode); ! 188: ! 189: if (code == CONST_INT) ! 190: { ! 191: int arg = va_arg (p, int); ! 192: if (arg == 0) ! 193: return const0_rtx; ! 194: if (arg == 1) ! 195: return const1_rtx; ! 196: rt_val = rtx_alloc (code); ! 197: INTVAL (rt_val) = arg; ! 198: } ! 199: else if (code == CONST_DOUBLE) ! 200: { ! 201: int arg0 = va_arg (p, int); ! 202: int arg1 = va_arg (p, int); ! 203: if (arg0 == XINT (fconst0_rtx, 0) ! 204: && arg1 == XINT (fconst0_rtx, 1)) ! 205: return (mode == DFmode ? dconst0_rtx : fconst0_rtx); ! 206: rt_val = rtx_alloc (code); ! 207: rt_val->mode = mode; ! 208: XINT (rt_val, 0) = arg0; ! 209: XINT (rt_val, 1) = arg1; ! 210: } ! 211: else ! 212: { ! 213: rt_val = rtx_alloc (code); /* Allocate the storage space. */ ! 214: rt_val->mode = mode; /* Store the machine mode... */ ! 215: ! 216: fmt = GET_RTX_FORMAT (code); /* Find the right format... */ ! 217: for (i = 0; i < GET_RTX_LENGTH (code); i++) ! 218: { ! 219: switch (*fmt++) ! 220: { ! 221: case '0': /* Unused field. */ ! 222: break; ! 223: ! 224: case 'i': /* An integer? */ ! 225: XINT (rt_val, i) = va_arg (p, int); ! 226: break; ! 227: ! 228: case 's': /* A string? */ ! 229: XSTR (rt_val, i) = va_arg (p, char *); ! 230: break; ! 231: ! 232: case 'e': /* An expression? */ ! 233: case 'u': /* An insn? Same except when printing. */ ! 234: XEXP (rt_val, i) = va_arg (p, rtx); ! 235: break; ! 236: ! 237: case 'E': /* An RTX vector? */ ! 238: XVEC (rt_val, i) = va_arg (p, rtvec); ! 239: break; ! 240: ! 241: default: ! 242: abort(); ! 243: } ! 244: } ! 245: } ! 246: va_end (p); ! 247: return rt_val; /* Return the new RTX... */ ! 248: } ! 249: ! 250: /* gen_rtvec (n, [rt1, ..., rtn]) ! 251: ** ! 252: ** This routine creates an rtvec and stores within it the ! 253: ** pointers to rtx's which are its arguments. ! 254: */ ! 255: ! 256: /*VARARGS1*/ ! 257: rtvec ! 258: gen_rtvec (va_alist) ! 259: va_dcl ! 260: { ! 261: int n, i; ! 262: rtx first; ! 263: va_list p; ! 264: rtx *vector; ! 265: ! 266: va_start (p); ! 267: n = va_arg (p, int); ! 268: ! 269: if (n == 0) ! 270: return NULL_RTVEC; /* Don't allocate an empty rtvec... */ ! 271: ! 272: vector = (rtx *) alloca (n * sizeof (rtx)); ! 273: for (i = 0; i < n; i++) ! 274: vector[i] = va_arg (p, rtx); ! 275: va_end (p); ! 276: ! 277: return gen_rtvec_v (n, vector); ! 278: } ! 279: ! 280: rtvec ! 281: gen_rtvec_v (n, argp) ! 282: int n; ! 283: rtx *argp; ! 284: { ! 285: register int i; ! 286: register rtvec rt_val; ! 287: ! 288: if (n == 0) ! 289: return NULL_RTVEC; /* Don't allocate an empty rtvec... */ ! 290: ! 291: rt_val = rtvec_alloc (n); /* Allocate an rtvec... */ ! 292: ! 293: for (i = 0; i < n; i++) ! 294: rt_val->elem[i].rtx = *argp++; ! 295: ! 296: return rt_val; ! 297: } ! 298: ! 299: /* Generate a REG rtx for a new pseudo register of mode MODE. ! 300: This pseudo is assigned the next sequential register number. */ ! 301: ! 302: rtx ! 303: gen_reg_rtx (mode) ! 304: enum machine_mode mode; ! 305: { ! 306: register rtx val; ! 307: ! 308: /* Make sure regno_pointer_flag and regno_reg_rtx are large ! 309: enough to have an element for this pseudo reg number. */ ! 310: ! 311: if (reg_rtx_no == regno_pointer_flag_length) ! 312: { ! 313: rtx *new1; ! 314: char *new = ! 315: (char *) oballoc (regno_pointer_flag_length * 2); ! 316: bzero (new, regno_pointer_flag_length * 2); ! 317: bcopy (regno_pointer_flag, new, regno_pointer_flag_length); ! 318: regno_pointer_flag = new; ! 319: ! 320: new1 = (rtx *) oballoc (regno_pointer_flag_length * 2 * sizeof (rtx)); ! 321: bzero (new1, regno_pointer_flag_length * 2 * sizeof (rtx)); ! 322: bcopy (regno_reg_rtx, new1, regno_pointer_flag_length * sizeof (rtx)); ! 323: regno_reg_rtx = new1; ! 324: ! 325: regno_pointer_flag_length *= 2; ! 326: } ! 327: ! 328: val = gen_rtx (REG, mode, reg_rtx_no); ! 329: regno_reg_rtx[reg_rtx_no++] = val; ! 330: return val; ! 331: } ! 332: ! 333: /* Identify REG as a probable pointer register. */ ! 334: ! 335: void ! 336: mark_reg_pointer (reg) ! 337: rtx reg; ! 338: { ! 339: REGNO_POINTER_FLAG (REGNO (reg)) = 1; ! 340: } ! 341: ! 342: /* Return 1 plus largest pseudo reg number used in the current function. */ ! 343: ! 344: int ! 345: max_reg_num () ! 346: { ! 347: return reg_rtx_no; ! 348: } ! 349: ! 350: /* Return 1 + the largest label number used so far. */ ! 351: ! 352: int ! 353: max_label_num () ! 354: { ! 355: return label_num; ! 356: } ! 357: ! 358: /* Return first label number used in this function (if any were used). */ ! 359: ! 360: int ! 361: get_first_label_num () ! 362: { ! 363: return first_label_num; ! 364: } ! 365: ! 366: /* Assuming that X is an rtx (MEM, REG or SUBREG) for a fixed-point number, ! 367: return a MEM or SUBREG rtx that refers to the least-significant part of X. ! 368: MODE specifies how big a part of X to return; ! 369: it must not be larger than a word. ! 370: If X is a MEM whose address is a QUEUED, the value may be so also. */ ! 371: ! 372: rtx ! 373: gen_lowpart (mode, x) ! 374: enum machine_mode mode; ! 375: register rtx x; ! 376: { ! 377: /* This case loses if X is a subreg. To catch bugs early, ! 378: complain if an invalid MODE is used even in other cases. */ ! 379: if (GET_MODE_SIZE (mode) > UNITS_PER_WORD) ! 380: abort (); ! 381: if (GET_CODE (x) == SUBREG) ! 382: return (GET_MODE (SUBREG_REG (x)) == mode && SUBREG_WORD (x) == 0 ! 383: ? SUBREG_REG (x) ! 384: : gen_rtx (SUBREG, mode, SUBREG_REG (x), SUBREG_WORD (x))); ! 385: if (GET_MODE (x) == mode) ! 386: return x; ! 387: if (GET_CODE (x) == CONST_INT) ! 388: return gen_rtx (CONST_INT, VOIDmode, INTVAL (x) & GET_MODE_MASK (mode)); ! 389: if (GET_CODE (x) == MEM) ! 390: { ! 391: register int offset = 0; ! 392: #ifdef WORDS_BIG_ENDIAN ! 393: offset = (max (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD) ! 394: - max (GET_MODE_SIZE (mode), UNITS_PER_WORD)); ! 395: #endif ! 396: #ifdef BYTES_BIG_ENDIAN ! 397: /* Adjust the address so that the address-after-the-data ! 398: is unchanged. */ ! 399: offset -= (min (UNITS_PER_WORD, GET_MODE_SIZE (mode)) ! 400: - min (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x)))); ! 401: #endif ! 402: return gen_rtx (MEM, mode, ! 403: memory_address (mode, ! 404: plus_constant (XEXP (x, 0), offset))); ! 405: } ! 406: else if (GET_CODE (x) == REG) ! 407: { ! 408: #ifdef WORDS_BIG_ENDIAN ! 409: if (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD) ! 410: { ! 411: return gen_rtx (SUBREG, mode, x, ! 412: ((GET_MODE_SIZE (GET_MODE (x)) ! 413: - max (GET_MODE_SIZE (mode), UNITS_PER_WORD)) ! 414: / UNITS_PER_WORD)); ! 415: } ! 416: #endif ! 417: return gen_rtx (SUBREG, mode, x, 0); ! 418: } ! 419: else ! 420: abort (); ! 421: } ! 422: ! 423: /* Like `gen_lowpart', but refer to the most significant part. */ ! 424: ! 425: rtx ! 426: gen_highpart (mode, x) ! 427: enum machine_mode mode; ! 428: register rtx x; ! 429: { ! 430: if (GET_CODE (x) == MEM) ! 431: { ! 432: register int offset = 0; ! 433: #ifndef WORDS_BIG_ENDIAN ! 434: offset = (max (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD) ! 435: - max (GET_MODE_SIZE (mode), UNITS_PER_WORD)); ! 436: #endif ! 437: #ifndef BYTES_BIG_ENDIAN ! 438: if (GET_MODE_SIZE (mode) < UNITS_PER_WORD) ! 439: offset -= (GET_MODE_SIZE (mode) ! 440: - min (UNITS_PER_WORD, ! 441: GET_MODE_SIZE (GET_MODE (x)))); ! 442: #endif ! 443: return gen_rtx (MEM, mode, ! 444: memory_address (mode, ! 445: plus_constant (XEXP (x, 0), offset))); ! 446: } ! 447: else if (GET_CODE (x) == REG) ! 448: { ! 449: #ifndef WORDS_BIG_ENDIAN ! 450: if (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD) ! 451: { ! 452: return gen_rtx (SUBREG, mode, x, ! 453: ((GET_MODE_SIZE (GET_MODE (x)) ! 454: - max (GET_MODE_SIZE (mode), UNITS_PER_WORD)) ! 455: / UNITS_PER_WORD)); ! 456: } ! 457: #endif ! 458: return gen_rtx (SUBREG, mode, x, 0); ! 459: } ! 460: else ! 461: abort (); ! 462: } ! 463: ! 464: /* Return 1 iff X, assumed to be a SUBREG, ! 465: refers to the least significant part of its containing reg. ! 466: If X is not a SUBREG, always return 1 (it is its own low part!). */ ! 467: ! 468: int ! 469: subreg_lowpart_p (x) ! 470: rtx x; ! 471: { ! 472: if (GET_CODE (x) != SUBREG) ! 473: return 1; ! 474: #ifdef WORDS_BIG_ENDIAN ! 475: if (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD) ! 476: { ! 477: register enum machine_mode mode = GET_MODE (SUBREG_REG (x)); ! 478: return (SUBREG_WORD (x) ! 479: == ((GET_MODE_SIZE (GET_MODE (x)) ! 480: - max (GET_MODE_SIZE (mode), UNITS_PER_WORD)) ! 481: / UNITS_PER_WORD)); ! 482: } ! 483: #endif ! 484: return SUBREG_WORD (x) == 0; ! 485: } ! 486: ! 487: /* Return a memory reference like MEMREF, but with its mode changed ! 488: to MODE and its address changed to ADDR. ! 489: (VOIDmode means don't change the mode. ! 490: NULL for ADDR means don't change the address.) */ ! 491: ! 492: rtx ! 493: change_address (memref, mode, addr) ! 494: rtx memref; ! 495: enum machine_mode mode; ! 496: rtx addr; ! 497: { ! 498: rtx new; ! 499: ! 500: if (mode == VOIDmode) ! 501: mode = GET_MODE (memref); ! 502: if (addr == 0) ! 503: addr = XEXP (memref, 0); ! 504: ! 505: new = gen_rtx (MEM, mode, memory_address (mode, addr)); ! 506: new->volatil = memref->volatil; ! 507: new->unchanging = memref->unchanging; ! 508: new->in_struct = memref->in_struct; ! 509: return new; ! 510: } ! 511: ! 512: /* Return a newly created CODE_LABEL rtx with a unique label number. */ ! 513: ! 514: rtx ! 515: gen_label_rtx () ! 516: { ! 517: register rtx label = gen_rtx (CODE_LABEL, VOIDmode, 0, 0, 0, label_num++); ! 518: LABEL_NUSES (label) = 0; ! 519: return label; ! 520: } ! 521: ! 522: /* For procedure integration. */ ! 523: ! 524: /* Return a newly created INLINE_HEADER rtx. Should allocate this ! 525: from a permanent obstack when the opportunity arises. */ ! 526: ! 527: rtx ! 528: gen_inline_header_rtx (insn, last_insn, ! 529: first_labelno, last_labelno, ! 530: max_parm_regnum, max_regnum, args_size) ! 531: rtx insn, last_insn; ! 532: int first_labelno, last_labelno, max_parm_regnum, max_regnum, args_size; ! 533: { ! 534: rtx header = gen_rtx (INLINE_HEADER, VOIDmode, ! 535: cur_insn_uid++, NULL, ! 536: insn, last_insn, ! 537: first_labelno, last_labelno, ! 538: max_parm_regnum, max_regnum, args_size); ! 539: return header; ! 540: } ! 541: ! 542: /* Install new pointers to the first and last insns in the chain. ! 543: Used for an inline-procedure after copying the insn chain. */ ! 544: ! 545: void ! 546: set_new_first_and_last_insn (first, last) ! 547: rtx first, last; ! 548: { ! 549: first_insn = first; ! 550: last_insn = last; ! 551: } ! 552: ! 553: /* Go through all the RTL insn bodies and copy any invalid shared structure. ! 554: It does not work to do this twice, because the mark bits set here ! 555: are not cleared afterwards. */ ! 556: ! 557: static int unshare_copies = 0; /* Count rtx's that were copied. */ ! 558: ! 559: static rtx copy_rtx_if_shared (); ! 560: ! 561: void ! 562: unshare_all_rtl (insn) ! 563: register rtx insn; ! 564: { ! 565: for (; insn; insn = NEXT_INSN (insn)) ! 566: if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN ! 567: || GET_CODE (insn) == CALL_INSN) ! 568: { ! 569: rtx tail; ! 570: PATTERN (insn) = copy_rtx_if_shared (PATTERN (insn)); ! 571: /* Copy the contents of the reg-notes */ ! 572: for (tail = REG_NOTES (insn); tail; tail = XEXP (tail, 1)) ! 573: /* But if contents are an insn, don't copy that. */ ! 574: if (GET_CODE (tail) == EXPR_LIST) ! 575: XEXP (tail, 0) = copy_rtx_if_shared (XEXP (tail, 0)); ! 576: } ! 577: } ! 578: ! 579: /* Mark ORIG as in use, and return a copy of it if it was already in use. ! 580: Recursively does the same for subexpressions. */ ! 581: ! 582: static rtx ! 583: copy_rtx_if_shared (orig) ! 584: rtx orig; ! 585: { ! 586: register rtx x = orig; ! 587: register int i; ! 588: register enum rtx_code code; ! 589: register char *format_ptr; ! 590: int copied = 0; ! 591: ! 592: code = GET_CODE (x); ! 593: ! 594: /* These types may be freely shared. */ ! 595: ! 596: switch (code) ! 597: { ! 598: case REG: ! 599: case QUEUED: ! 600: case CONST_INT: ! 601: case CONST_DOUBLE: ! 602: case SYMBOL_REF: ! 603: case CODE_LABEL: ! 604: case PC: ! 605: case CC0: ! 606: return x; ! 607: ! 608: case MEM: ! 609: /* A MEM is allowed to be shared if its address is constant ! 610: or is a constant plus one of the special registers. */ ! 611: if (CONSTANT_ADDRESS_P (XEXP (x, 0))) ! 612: return x; ! 613: if (GET_CODE (XEXP (x, 0)) == PLUS ! 614: && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG ! 615: && (REGNO (XEXP (XEXP (x, 0), 0)) == FRAME_POINTER_REGNUM ! 616: || REGNO (XEXP (XEXP (x, 0), 0)) == ARG_POINTER_REGNUM) ! 617: && CONSTANT_ADDRESS_P (XEXP (XEXP (x, 0), 1))) ! 618: if (GET_CODE (XEXP (x, 0)) == REG ! 619: && (REGNO (XEXP (x, 0)) == FRAME_POINTER_REGNUM ! 620: || REGNO (XEXP (x, 0)) == ARG_POINTER_REGNUM) ! 621: && CONSTANT_ADDRESS_P (XEXP (x, 1))) ! 622: return x; ! 623: } ! 624: ! 625: /* This rtx may not be shared. If it has already been seen, ! 626: replace it with a copy of itself. */ ! 627: ! 628: if (x->used) ! 629: { ! 630: register rtx copy; ! 631: ! 632: unshare_copies++; ! 633: ! 634: copy = rtx_alloc (code); ! 635: bcopy (x, copy, sizeof (int) * (GET_RTX_LENGTH (code) + 1)); ! 636: x = copy; ! 637: copied = 1; ! 638: } ! 639: x->used = 1; ! 640: ! 641: /* Now scan the subexpressions recursively. ! 642: We can store any replaced subexpressions directly into X ! 643: since we know X is not shared! Any vectors in X ! 644: must be copied if X was copied. */ ! 645: ! 646: format_ptr = GET_RTX_FORMAT (code); ! 647: ! 648: for (i = 0; i < GET_RTX_LENGTH (code); i++) ! 649: { ! 650: switch (*format_ptr++) ! 651: { ! 652: case 'e': ! 653: XEXP (x, i) = copy_rtx_if_shared (XEXP (x, i)); ! 654: break; ! 655: ! 656: case 'E': ! 657: if (XVEC (x, i) != NULL) ! 658: { ! 659: register int j; ! 660: ! 661: if (copied) ! 662: XVEC (x, i) = gen_rtvec_v (XVECLEN (x, i), &XVECEXP (x, i, 0)); ! 663: for (j = 0; j < XVECLEN (x, i); j++) ! 664: XVECEXP (x, i, j) ! 665: = copy_rtx_if_shared (XVECEXP (x, i, j)); ! 666: } ! 667: break; ! 668: } ! 669: } ! 670: return x; ! 671: } ! 672: ! 673: /* Copy X if necessary so that it won't be altered by changes in OTHER. ! 674: Return X or the rtx for the pseudo reg the value of X was copied into. ! 675: OTHER must be valid as a SET_DEST. */ ! 676: ! 677: rtx ! 678: make_safe_from (x, other) ! 679: rtx x, other; ! 680: { ! 681: rtx out = other; ! 682: while (1) ! 683: switch (GET_CODE (other)) ! 684: { ! 685: case SUBREG: ! 686: other = SUBREG_REG (other); ! 687: break; ! 688: case STRICT_LOW_PART: ! 689: case SIGN_EXTEND: ! 690: case ZERO_EXTEND: ! 691: other = XEXP (other, 0); ! 692: break; ! 693: default: ! 694: goto done; ! 695: } ! 696: done: ! 697: if ((GET_CODE (other) == MEM ! 698: && ! CONSTANT_P (x) ! 699: && GET_CODE (x) != CONST_DOUBLE ! 700: && GET_CODE (x) != REG) ! 701: || (GET_CODE (other) == REG ! 702: && (REGNO (other) < FIRST_PSEUDO_REGISTER ! 703: || reg_mentioned_p (other, x)))) ! 704: { ! 705: rtx temp = gen_reg_rtx (GET_MODE (x)); ! 706: emit_move_insn (temp, x); ! 707: return temp; ! 708: } ! 709: return x; ! 710: } ! 711: ! 712: /* Emission of insns (adding them to the doubly-linked list). */ ! 713: ! 714: /* Return the first insn of the current function. */ ! 715: ! 716: rtx ! 717: get_insns () ! 718: { ! 719: return first_insn; ! 720: } ! 721: ! 722: /* Return the last insn of the current function. */ ! 723: ! 724: rtx ! 725: get_last_insn () ! 726: { ! 727: return last_insn; ! 728: } ! 729: ! 730: /* Return a number larger than any instruction's uid in this function. */ ! 731: ! 732: int ! 733: get_max_uid () ! 734: { ! 735: return cur_insn_uid; ! 736: } ! 737: ! 738: /* Make and return an INSN rtx, initializing all its slots. ! 739: Store PATTERN in the pattern slots. ! 740: PAT_FORMALS is an idea that never really went anywhere. */ ! 741: ! 742: static rtx ! 743: make_insn_raw (pattern, pat_formals) ! 744: rtx pattern; ! 745: rtvec pat_formals; ! 746: { ! 747: register rtx insn; ! 748: ! 749: insn = rtx_alloc(INSN); ! 750: INSN_UID(insn) = cur_insn_uid++; ! 751: ! 752: PATTERN (insn) = pattern; ! 753: INSN_CODE (insn) = -1; ! 754: LOG_LINKS(insn) = NULL; ! 755: REG_NOTES(insn) = NULL; ! 756: ! 757: return insn; ! 758: } ! 759: ! 760: /* Like `make_insn' but make a JUMP_INSN instead of an insn. */ ! 761: ! 762: static rtx ! 763: make_jump_insn_raw (pattern, pat_formals) ! 764: rtx pattern; ! 765: rtvec pat_formals; ! 766: { ! 767: register rtx insn; ! 768: ! 769: insn = rtx_alloc(JUMP_INSN); ! 770: INSN_UID(insn) = cur_insn_uid++; ! 771: ! 772: PATTERN (insn) = pattern; ! 773: INSN_CODE (insn) = -1; ! 774: LOG_LINKS(insn) = NULL; ! 775: REG_NOTES(insn) = NULL; ! 776: JUMP_LABEL(insn) = NULL; ! 777: ! 778: return insn; ! 779: } ! 780: ! 781: /* Add INSN to the end of the doubly-linked list. ! 782: INSN may be an INSN, JUMP_INSN, CALL_INSN, CODE_LABEL, BARRIER or NOTE. */ ! 783: ! 784: static void ! 785: add_insn (insn) ! 786: register rtx insn; ! 787: { ! 788: if (emit_to_sequence) ! 789: { ! 790: PREV_INSN (insn) = sequence_last_insn; ! 791: NEXT_INSN (insn) = 0; ! 792: ! 793: if (NULL != sequence_last_insn) ! 794: NEXT_INSN (sequence_last_insn) = insn; ! 795: ! 796: if (NULL == sequence_first_insn) ! 797: sequence_first_insn = insn; ! 798: ! 799: sequence_last_insn = insn; ! 800: } ! 801: else ! 802: { ! 803: PREV_INSN (insn) = last_insn; ! 804: NEXT_INSN (insn) = 0; ! 805: ! 806: if (NULL != last_insn) ! 807: NEXT_INSN (last_insn) = insn; ! 808: ! 809: if (NULL == first_insn) ! 810: first_insn = insn; ! 811: ! 812: last_insn = insn; ! 813: } ! 814: } ! 815: ! 816: /* Add INSN, an rtx of code INSN, into the doubly-linked list ! 817: after insn AFTER. */ ! 818: ! 819: static void ! 820: add_insn_after (insn, after) ! 821: rtx insn, after; ! 822: { ! 823: NEXT_INSN (insn) = NEXT_INSN (after); ! 824: PREV_INSN (insn) = after; ! 825: ! 826: if (NEXT_INSN (insn)) ! 827: PREV_INSN (NEXT_INSN (insn)) = insn; ! 828: else ! 829: last_insn = insn; ! 830: NEXT_INSN (after) = insn; ! 831: } ! 832: ! 833: /* Delete all insns made since FROM. ! 834: FROM becomes the new last instruction. */ ! 835: ! 836: void ! 837: delete_insns_since (from) ! 838: rtx from; ! 839: { ! 840: NEXT_INSN (from) = 0; ! 841: last_insn = from; ! 842: } ! 843: ! 844: /* Move a consecutive bunch of insns to a different place in the chain. ! 845: The insns to be moved are those between FROM and TO. ! 846: They are moved to a new position after the insn AFTER. */ ! 847: ! 848: void ! 849: reorder_insns (from, to, after) ! 850: rtx from, to, after; ! 851: { ! 852: /* Splice this bunch out of where it is now. */ ! 853: if (PREV_INSN (from)) ! 854: NEXT_INSN (PREV_INSN (from)) = NEXT_INSN (to); ! 855: if (NEXT_INSN (to)) ! 856: PREV_INSN (NEXT_INSN (to)) = PREV_INSN (from); ! 857: if (last_insn == to) ! 858: last_insn = PREV_INSN (from); ! 859: if (first_insn == from) ! 860: first_insn = NEXT_INSN (to); ! 861: ! 862: /* Make the new neighbors point to it and it to them. */ ! 863: if (NEXT_INSN (after)) ! 864: { ! 865: PREV_INSN (NEXT_INSN (after)) = to; ! 866: NEXT_INSN (to) = NEXT_INSN (after); ! 867: } ! 868: PREV_INSN (from) = after; ! 869: NEXT_INSN (after) = from; ! 870: if (after == last_insn) ! 871: last_insn = to; ! 872: } ! 873: ! 874: /* Emit an insn of given code and pattern ! 875: at a specified place within the doubly-linked list. */ ! 876: ! 877: /* Make an instruction with body PATTERN ! 878: and output it before the instruction BEFORE. */ ! 879: ! 880: rtx ! 881: emit_insn_before (pattern, before) ! 882: register rtx pattern, before; ! 883: { ! 884: register rtx insn; ! 885: ! 886: if (GET_CODE (pattern) == SEQUENCE) ! 887: { ! 888: register int i; ! 889: /* For an empty sequence, emit nothing. */ ! 890: if (XVEC (pattern, 0)) ! 891: for (i = 0; i < XVECLEN (pattern, 0); i++) ! 892: add_insn_after (XVECEXP (pattern, 0, i), PREV_INSN (before)); ! 893: return PREV_INSN (before); ! 894: } ! 895: ! 896: insn = make_insn_raw (pattern, 0); ! 897: ! 898: PREV_INSN (insn) = PREV_INSN (before); ! 899: NEXT_INSN (insn) = before; ! 900: ! 901: if (PREV_INSN (insn)) ! 902: NEXT_INSN (PREV_INSN (insn)) = insn; ! 903: else ! 904: first_insn = insn; ! 905: PREV_INSN (before) = insn; ! 906: ! 907: return insn; ! 908: } ! 909: ! 910: /* Make an instruction with body PATTERN and code JUMP_INSN ! 911: and output it before the instruction BEFORE. */ ! 912: ! 913: rtx ! 914: emit_jump_insn_before (pattern, before) ! 915: register rtx pattern, before; ! 916: { ! 917: register rtx insn = make_jump_insn_raw (pattern, 0); ! 918: ! 919: PREV_INSN (insn) = PREV_INSN (before); ! 920: NEXT_INSN (insn) = before; ! 921: ! 922: if (PREV_INSN (insn)) ! 923: NEXT_INSN (PREV_INSN (insn)) = insn; ! 924: else ! 925: first_insn = insn; ! 926: PREV_INSN (before) = insn; ! 927: ! 928: return insn; ! 929: } ! 930: ! 931: /* Make an insn of code INSN with body PATTERN ! 932: and output it after the insn AFTER. */ ! 933: ! 934: rtx ! 935: emit_insn_after (pattern, after) ! 936: register rtx pattern, after; ! 937: { ! 938: if (GET_CODE (pattern) == SEQUENCE) ! 939: { ! 940: register int i; ! 941: /* For an empty sequence, emit nothing. */ ! 942: if (XVEC (pattern, 0)) ! 943: for (i = 0; i < XVECLEN (pattern, 0); i++) ! 944: { ! 945: add_insn_after (XVECEXP (pattern, 0, i), after); ! 946: after = NEXT_INSN (after); ! 947: } ! 948: return after; ! 949: } ! 950: else ! 951: { ! 952: register rtx insn = make_insn_raw (pattern, 0); ! 953: add_insn_after (insn, after); ! 954: return insn; ! 955: } ! 956: } ! 957: ! 958: /* Make an insn of code JUMP_INSN with body PATTERN ! 959: and output it after the insn AFTER. */ ! 960: ! 961: rtx ! 962: emit_jump_insn_after (pattern, after) ! 963: register rtx pattern, after; ! 964: { ! 965: register rtx insn = make_jump_insn_raw (pattern, 0); ! 966: ! 967: add_insn_after (insn, after); ! 968: return insn; ! 969: } ! 970: ! 971: /* Make an insn of code BARRIER ! 972: and output it after the insn AFTER. */ ! 973: ! 974: rtx ! 975: emit_barrier_after (after) ! 976: register rtx after; ! 977: { ! 978: register rtx insn = rtx_alloc (BARRIER); ! 979: ! 980: INSN_UID (insn) = cur_insn_uid++; ! 981: ! 982: add_insn_after (insn, after); ! 983: return insn; ! 984: } ! 985: ! 986: /* Emit the label LABEL after the insn AFTER. */ ! 987: ! 988: void ! 989: emit_label_after (label, after) ! 990: rtx label, after; ! 991: { ! 992: /* This can be called twice for the same label ! 993: as a result of the confusion that follows a syntax error! ! 994: So make it harmless. */ ! 995: if (INSN_UID (label) == 0) ! 996: { ! 997: INSN_UID (label) = cur_insn_uid++; ! 998: add_insn_after (label, after); ! 999: } ! 1000: } ! 1001: ! 1002: /* Emit a note of subtype SUBTYPE after the insn AFTER. */ ! 1003: ! 1004: void ! 1005: emit_note_after (subtype, after) ! 1006: int subtype; ! 1007: rtx after; ! 1008: { ! 1009: register rtx note = rtx_alloc (NOTE); ! 1010: INSN_UID (note) = cur_insn_uid++; ! 1011: XSTR (note, 3) = 0; ! 1012: XINT (note, 4) = subtype; ! 1013: add_insn_after (note, after); ! 1014: } ! 1015: ! 1016: /* Make an insn of code INSN with pattern PATTERN ! 1017: and add it to the end of the doubly-linked list. ! 1018: If PATTERN is a SEQUENCE, take the elements of it ! 1019: and emit an insn for each element. ! 1020: ! 1021: Returns the last insn emitted. */ ! 1022: ! 1023: rtx ! 1024: emit_insn (pattern) ! 1025: rtx pattern; ! 1026: { ! 1027: rtx insn; ! 1028: ! 1029: if (GET_CODE (pattern) == SEQUENCE) ! 1030: { ! 1031: register int i; ! 1032: /* For an empty sequence, emit nothing. */ ! 1033: if (XVEC (pattern, 0)) ! 1034: for (i = 0; i < XVECLEN (pattern, 0); i++) ! 1035: add_insn (insn = XVECEXP (pattern, 0, i)); ! 1036: } ! 1037: else ! 1038: { ! 1039: insn = make_insn_raw (pattern, NULL); ! 1040: add_insn (insn); ! 1041: } ! 1042: return insn; ! 1043: } ! 1044: ! 1045: /* Make an insn of code JUMP_INSN with pattern PATTERN ! 1046: and add it to the end of the doubly-linked list. */ ! 1047: ! 1048: rtx ! 1049: emit_jump_insn (pattern) ! 1050: rtx pattern; ! 1051: { ! 1052: if (GET_CODE (pattern) == SEQUENCE) ! 1053: return emit_insn (pattern); ! 1054: else ! 1055: { ! 1056: register rtx insn = make_jump_insn_raw (pattern, NULL); ! 1057: add_insn (insn); ! 1058: return insn; ! 1059: } ! 1060: } ! 1061: ! 1062: /* Make an insn of code CALL_INSN with pattern PATTERN ! 1063: and add it to the end of the doubly-linked list. */ ! 1064: ! 1065: rtx ! 1066: emit_call_insn (pattern) ! 1067: rtx pattern; ! 1068: { ! 1069: if (GET_CODE (pattern) == SEQUENCE) ! 1070: return emit_insn (pattern); ! 1071: else ! 1072: { ! 1073: register rtx insn = make_insn_raw (pattern, NULL); ! 1074: add_insn (insn); ! 1075: PUT_CODE (insn, CALL_INSN); ! 1076: return insn; ! 1077: } ! 1078: } ! 1079: ! 1080: /* Add the label LABEL to the end of the doubly-linked list. */ ! 1081: ! 1082: void ! 1083: emit_label (label) ! 1084: rtx label; ! 1085: { ! 1086: /* This can be called twice for the same label ! 1087: as a result of the confusion that follows a syntax error! ! 1088: So make it harmless. */ ! 1089: if (INSN_UID (label) == 0) ! 1090: { ! 1091: INSN_UID (label) = cur_insn_uid++; ! 1092: add_insn (label); ! 1093: } ! 1094: } ! 1095: ! 1096: /* Make an insn of code BARRIER ! 1097: and add it to the end of the doubly-linked list. */ ! 1098: ! 1099: void ! 1100: emit_barrier () ! 1101: { ! 1102: register rtx barrier = rtx_alloc (BARRIER); ! 1103: INSN_UID (barrier) = cur_insn_uid++; ! 1104: add_insn (barrier); ! 1105: } ! 1106: ! 1107: /* Make an insn of code NOTE ! 1108: with data-fields specified by FILE and LINE ! 1109: and add it to the end of the doubly-linked list. */ ! 1110: ! 1111: rtx ! 1112: emit_note (file, line) ! 1113: char *file; ! 1114: int line; ! 1115: { ! 1116: register rtx note; ! 1117: ! 1118: if (no_line_numbers && line > 0) ! 1119: return 0; ! 1120: ! 1121: if (line > 0) ! 1122: { ! 1123: if (file && last_filename && !strcmp (file, last_filename) ! 1124: && line == last_linenum) ! 1125: return 0; ! 1126: last_filename = file; ! 1127: last_linenum = line; ! 1128: } ! 1129: ! 1130: note = rtx_alloc (NOTE); ! 1131: INSN_UID (note) = cur_insn_uid++; ! 1132: XSTR (note, 3) = file; ! 1133: XINT (note, 4) = line; ! 1134: add_insn (note); ! 1135: return note; ! 1136: } ! 1137: ! 1138: /* Return an indication of which type of insn should have X as a body. ! 1139: The value is CODE_LABEL, INSN, CALL_INSN or JUMP_INSN. */ ! 1140: ! 1141: enum rtx_code ! 1142: classify_insn (x) ! 1143: rtx x; ! 1144: { ! 1145: if (GET_CODE (x) == CODE_LABEL) ! 1146: return CODE_LABEL; ! 1147: if (GET_CODE (x) == CALL) ! 1148: return CALL_INSN; ! 1149: if (GET_CODE (x) == RETURN) ! 1150: return JUMP_INSN; ! 1151: if (GET_CODE (x) == SET) ! 1152: { ! 1153: if (SET_DEST (x) == pc_rtx) ! 1154: return JUMP_INSN; ! 1155: else if (GET_CODE (SET_SRC (x)) == CALL) ! 1156: return CALL_INSN; ! 1157: else ! 1158: return INSN; ! 1159: } ! 1160: if (GET_CODE (x) == PARALLEL) ! 1161: { ! 1162: register int j; ! 1163: for (j = XVECLEN (x, 0) - 1; j >= 0; j--) ! 1164: if (GET_CODE (XVECEXP (x, 0, j)) == CALL) ! 1165: return CALL_INSN; ! 1166: else if (GET_CODE (XVECEXP (x, 0, j)) == SET ! 1167: && SET_DEST (XVECEXP (x, 0, j)) == pc_rtx) ! 1168: return JUMP_INSN; ! 1169: else if (GET_CODE (XVECEXP (x, 0, j)) == SET ! 1170: && GET_CODE (SET_SRC (XVECEXP (x, 0, j))) == CALL) ! 1171: return CALL_INSN; ! 1172: } ! 1173: return INSN; ! 1174: } ! 1175: ! 1176: /* Emit the rtl pattern X as an appropriate kind of insn. ! 1177: If X is a label, it is simply added into the insn chain. */ ! 1178: ! 1179: rtx ! 1180: emit (x) ! 1181: rtx x; ! 1182: { ! 1183: enum rtx_code code = classify_insn (x); ! 1184: ! 1185: if (code == CODE_LABEL) ! 1186: emit_label (x); ! 1187: else if (code == INSN) ! 1188: emit_insn (x); ! 1189: else if (code == JUMP_INSN) ! 1190: { ! 1191: emit_jump_insn (x); ! 1192: if (simplejump_p (x) || GET_CODE (x) == RETURN) ! 1193: emit_barrier (); ! 1194: } ! 1195: else if (code == CALL_INSN) ! 1196: emit_call_insn (x); ! 1197: } ! 1198: ! 1199: /* Generate a SEQUENCE rtx containing the insn-patterns in VEC ! 1200: following any insns previously placed on sequence_first_insn. ! 1201: This is how the gen_... function from a DEFINE_EXPAND ! 1202: constructs the SEQUENCE that it returns. */ ! 1203: ! 1204: rtx ! 1205: gen_sequence () ! 1206: { ! 1207: rtx tem; ! 1208: rtvec newvec; ! 1209: int i; ! 1210: int len; ! 1211: ! 1212: /* Count the insns in the chain. */ ! 1213: len = 0; ! 1214: for (tem = sequence_first_insn; tem; tem = NEXT_INSN (tem)) ! 1215: len++; ! 1216: ! 1217: /* For an empty sequence... */ ! 1218: if (len == 0) ! 1219: return gen_rtx (SEQUENCE, VOIDmode, NULL); ! 1220: ! 1221: /* If only one insn, return its pattern rather than a SEQUENCE. */ ! 1222: if (len == 1) ! 1223: { ! 1224: tem = PATTERN (sequence_first_insn); ! 1225: sequence_first_insn = 0; ! 1226: sequence_last_insn = 0; ! 1227: return tem; ! 1228: } ! 1229: ! 1230: /* Put them in a vector. */ ! 1231: newvec = rtvec_alloc (len); ! 1232: i = 0; ! 1233: for (tem = sequence_first_insn; tem; tem = NEXT_INSN (tem), i++) ! 1234: newvec->elem[i].rtx = tem; ! 1235: ! 1236: /* Clear the chain and make a SEQUENCE from this vector. */ ! 1237: sequence_first_insn = 0; ! 1238: sequence_last_insn = 0; ! 1239: return gen_rtx (SEQUENCE, VOIDmode, newvec); ! 1240: } ! 1241: ! 1242: /* Set up regno_reg_rtx, reg_rtx_no and regno_pointer_flag ! 1243: according to the chain of insns starting with FIRST. ! 1244: ! 1245: This is used when an inline function's rtl is saved ! 1246: and passed to rest_of_compilation later. */ ! 1247: ! 1248: static void restore_reg_data_1 (); ! 1249: ! 1250: void ! 1251: restore_reg_data (first) ! 1252: rtx first; ! 1253: { ! 1254: rtx insn; ! 1255: int i; ! 1256: ! 1257: for (insn = first; insn; insn = NEXT_INSN (insn)) ! 1258: { ! 1259: switch (GET_CODE (insn)) ! 1260: { ! 1261: case NOTE: ! 1262: case CODE_LABEL: ! 1263: case BARRIER: ! 1264: break; ! 1265: ! 1266: case JUMP_INSN: ! 1267: case CALL_INSN: ! 1268: case INSN: ! 1269: restore_reg_data_1 (PATTERN (insn)); ! 1270: break; ! 1271: } ! 1272: } ! 1273: ! 1274: /* If any regs are missing, make them up. */ ! 1275: for (i = FIRST_PSEUDO_REGISTER; i < reg_rtx_no; i++) ! 1276: if (regno_reg_rtx[i] == 0) ! 1277: regno_reg_rtx[i] = gen_rtx (REG, SImode, i); ! 1278: } ! 1279: ! 1280: static void ! 1281: restore_reg_data_1 (orig) ! 1282: rtx orig; ! 1283: { ! 1284: register rtx x = orig; ! 1285: register int i; ! 1286: register enum rtx_code code; ! 1287: register char *format_ptr; ! 1288: ! 1289: code = GET_CODE (x); ! 1290: ! 1291: switch (code) ! 1292: { ! 1293: case QUEUED: ! 1294: case CONST_INT: ! 1295: case CONST_DOUBLE: ! 1296: case SYMBOL_REF: ! 1297: case CODE_LABEL: ! 1298: case PC: ! 1299: case CC0: ! 1300: case LABEL_REF: ! 1301: return; ! 1302: ! 1303: case REG: ! 1304: if (REGNO (x) >= FIRST_PSEUDO_REGISTER) ! 1305: { ! 1306: /* Make sure regno_pointer_flag and regno_reg_rtx are large ! 1307: enough to have an element for this pseudo reg number. */ ! 1308: if (REGNO (x) >= reg_rtx_no) ! 1309: { ! 1310: reg_rtx_no = REGNO (x); ! 1311: ! 1312: if (reg_rtx_no == regno_pointer_flag_length) ! 1313: { ! 1314: rtx *new1; ! 1315: char *new = ! 1316: (char *) oballoc (regno_pointer_flag_length * 2); ! 1317: bzero (new, regno_pointer_flag_length * 2); ! 1318: bcopy (regno_pointer_flag, new, regno_pointer_flag_length); ! 1319: regno_pointer_flag = new; ! 1320: ! 1321: new1 = (rtx *) oballoc (regno_pointer_flag_length * 2 * sizeof (rtx)); ! 1322: bzero (new1, regno_pointer_flag_length * 2 * sizeof (rtx)); ! 1323: bcopy (regno_reg_rtx, new1, regno_pointer_flag_length * sizeof (rtx)); ! 1324: regno_reg_rtx = new1; ! 1325: ! 1326: regno_pointer_flag_length *= 2; ! 1327: } ! 1328: reg_rtx_no ++; ! 1329: } ! 1330: regno_reg_rtx[REGNO (x)] = x; ! 1331: } ! 1332: return; ! 1333: ! 1334: case MEM: ! 1335: restore_reg_data_1 (XEXP (x, 0)); ! 1336: return; ! 1337: } ! 1338: ! 1339: /* Now scan the subexpressions recursively. */ ! 1340: ! 1341: format_ptr = GET_RTX_FORMAT (code); ! 1342: ! 1343: for (i = 0; i < GET_RTX_LENGTH (code); i++) ! 1344: { ! 1345: switch (*format_ptr++) ! 1346: { ! 1347: case 'e': ! 1348: restore_reg_data_1 (XEXP (x, i)); ! 1349: break; ! 1350: ! 1351: case 'E': ! 1352: if (XVEC (x, i) != NULL) ! 1353: { ! 1354: register int j; ! 1355: ! 1356: for (j = 0; j < XVECLEN (x, i); j++) ! 1357: restore_reg_data_1 (XVECEXP (x, i, j)); ! 1358: } ! 1359: break; ! 1360: } ! 1361: } ! 1362: } ! 1363: ! 1364: /* Initialize data structures and variables in this file ! 1365: before generating rtl for each function. ! 1366: WRITE_SYMBOLS is nonzero if any kind of debugging info ! 1367: is to be generated. */ ! 1368: ! 1369: void ! 1370: init_emit (write_symbols) ! 1371: int write_symbols; ! 1372: { ! 1373: first_insn = NULL; ! 1374: last_insn = NULL; ! 1375: cur_insn_uid = 1; ! 1376: reg_rtx_no = FIRST_PSEUDO_REGISTER; ! 1377: last_linenum = 0; ! 1378: last_filename = 0; ! 1379: real_constant_chain = 0; ! 1380: first_label_num = label_num; ! 1381: sequence_first_insn = NULL; ! 1382: sequence_last_insn = NULL; ! 1383: emit_to_sequence = 0; ! 1384: ! 1385: no_line_numbers = ! write_symbols; ! 1386: ! 1387: /* Init the tables that describe all the pseudo regs. */ ! 1388: ! 1389: regno_pointer_flag_length = 100; ! 1390: ! 1391: regno_pointer_flag ! 1392: = (char *) oballoc (regno_pointer_flag_length); ! 1393: bzero (regno_pointer_flag, regno_pointer_flag_length); ! 1394: ! 1395: regno_reg_rtx ! 1396: = (rtx *) oballoc (regno_pointer_flag_length * sizeof (rtx)); ! 1397: bzero (regno_reg_rtx, regno_pointer_flag_length * sizeof (rtx)); ! 1398: } ! 1399: ! 1400: /* Create some permanent unique rtl objects shared between all functions. */ ! 1401: ! 1402: void ! 1403: init_emit_once () ! 1404: { ! 1405: /* Create the unique rtx's for certain rtx codes and operand values. */ ! 1406: ! 1407: pc_rtx = gen_rtx (PC, VOIDmode); ! 1408: cc0_rtx = gen_rtx (CC0, VOIDmode); ! 1409: ! 1410: /* Don't use gen_rtx here since gen_rtx in this case ! 1411: tries to use these variables. */ ! 1412: const0_rtx = rtx_alloc (CONST_INT); ! 1413: INTVAL (const0_rtx) = 0; ! 1414: const1_rtx = rtx_alloc (CONST_INT); ! 1415: INTVAL (const1_rtx) = 1; ! 1416: ! 1417: fconst0_rtx = rtx_alloc (CONST_DOUBLE); ! 1418: { ! 1419: union { double d; int i[2]; } u; ! 1420: u.d = 0; ! 1421: XINT (fconst0_rtx, 0) = u.i[0]; ! 1422: XINT (fconst0_rtx, 1) = u.i[1]; ! 1423: XEXP (fconst0_rtx, 2) = const0_rtx; ! 1424: } ! 1425: PUT_MODE (fconst0_rtx, SFmode); ! 1426: ! 1427: dconst0_rtx = rtx_alloc (CONST_DOUBLE); ! 1428: { ! 1429: union { double d; int i[2]; } u; ! 1430: u.d = 0; ! 1431: XINT (dconst0_rtx, 0) = u.i[0]; ! 1432: XINT (dconst0_rtx, 1) = u.i[1]; ! 1433: XEXP (dconst0_rtx, 2) = const0_rtx; ! 1434: } ! 1435: PUT_MODE (dconst0_rtx, DFmode); ! 1436: ! 1437: stack_pointer_rtx = gen_rtx (REG, Pmode, STACK_POINTER_REGNUM); ! 1438: frame_pointer_rtx = gen_rtx (REG, Pmode, FRAME_POINTER_REGNUM); ! 1439: struct_value_rtx = gen_rtx (REG, Pmode, STRUCT_VALUE_REGNUM); ! 1440: ! 1441: #ifdef STRUCT_VALUE_INCOMING_REGNUM ! 1442: if (STRUCT_VALUE_INCOMING_REGNUM != STRUCT_VALUE_REGNUM) ! 1443: struct_value_incoming_rtx = gen_rtx (REG, Pmode, STRUCT_VALUE_INCOMING_REGNUM); ! 1444: else ! 1445: #endif ! 1446: struct_value_incoming_rtx = struct_value_rtx; ! 1447: ! 1448: static_chain_rtx = gen_rtx (REG, Pmode, STATIC_CHAIN_REGNUM); ! 1449: ! 1450: #ifdef STATIC_CHAIN_INCOMING_REGNUM ! 1451: if (STATIC_CHAIN_INCOMING_REGNUM != STATIC_CHAIN_REGNUM) ! 1452: static_chain_incoming_rtx = gen_rtx (REG, Pmode, STATIC_CHAIN_INCOMING_REGNUM); ! 1453: else ! 1454: #endif ! 1455: static_chain_incoming_rtx = static_chain_rtx; ! 1456: ! 1457: if (FRAME_POINTER_REGNUM == ARG_POINTER_REGNUM) ! 1458: arg_pointer_rtx = frame_pointer_rtx; ! 1459: else ! 1460: arg_pointer_rtx = gen_rtx (REG, Pmode, ARG_POINTER_REGNUM); ! 1461: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.