|
|
1.1 ! root 1: /* Procedure integration for GNU CC. ! 2: Copyright (C) 1988 Free Software Foundation, Inc. ! 3: Contributed by Michael Tiemann ([email protected]) ! 4: ! 5: This file is part of GNU CC. ! 6: ! 7: GNU CC is distributed in the hope that it will be useful, ! 8: but WITHOUT ANY WARRANTY. No author or distributor ! 9: accepts responsibility to anyone for the consequences of using it ! 10: or for whether it serves any particular purpose or works at all, ! 11: unless he says so in writing. Refer to the GNU CC General Public ! 12: License for full details. ! 13: ! 14: Everyone is granted permission to copy, modify and redistribute ! 15: GNU CC, but only under the conditions described in the ! 16: GNU CC General Public License. A copy of this license is ! 17: supposed to have been given to you along with GNU CC so you ! 18: can know your rights and responsibilities. It should be in a ! 19: file named COPYING. Among other things, the copyright notice ! 20: and this notice must be preserved on all copies. */ ! 21: ! 22: ! 23: #include <ctype.h> ! 24: #include <stdio.h> ! 25: ! 26: #include "config.h" ! 27: #include "rtl.h" ! 28: #include "tree.h" ! 29: #include "flags.h" ! 30: #include "insn-flags.h" ! 31: #include "expr.h" ! 32: ! 33: #include "obstack.h" ! 34: #define obstack_chunk_alloc xmalloc ! 35: #define obstack_chunk_free free ! 36: extern int xmalloc (); ! 37: extern void free (); ! 38: ! 39: extern struct obstack permanent_obstack, maybepermanent_obstack; ! 40: extern struct obstack *rtl_obstack, *saveable_obstack, *current_obstack; ! 41: ! 42: #define MIN(x,y) ((x < y) ? x : y) ! 43: ! 44: extern tree pushdecl (); ! 45: ! 46: /* This is the target of the inline function being expanded, ! 47: or NULL if there is none. */ ! 48: static rtx inline_target; ! 49: ! 50: /* We must take special care not to disrupt life too severely ! 51: when performing procedure integration. One thing that that ! 52: involves is not creating illegitimate address which reload ! 53: cannot fix. Since we don't know what the frame pointer is ! 54: not capable of (in a machine independent way), we create ! 55: a pseudo-frame pointer which will have to do for now. */ ! 56: static rtx inline_fp_rtx; ! 57: ! 58: /* Convert old frame-pointer offsets to new. Parameters which only ! 59: produce values (no addresses, and are never assigned), map directly ! 60: to the pseudo-reg of the incoming value. Parameters that are ! 61: assigned to but do not have their address taken are given a fresh ! 62: pseudo-register. Parameters that have their address take are ! 63: given a fresh stack-slot. */ ! 64: static rtx *parm_map; ! 65: ! 66: /* ?? Should this be done here?? It is not right now. ! 67: Keep track of whether a given pseudo-register is the sum ! 68: of the frame pointer and a const_int (or zero). */ ! 69: static char *fp_addr_p; ! 70: ! 71: /* For the local variables of the procdure being integrated that live ! 72: on the frame, FRAME_POINTER_DELTA says how much to change their ! 73: offsets by, so that they now live in the correct place on the ! 74: frame of the function being compiled. */ ! 75: static int fp_delta; ! 76: ! 77: /* Return a copy of an rtx (as needed), substituting pseudo-register, ! 78: labels, and frame-pointer offsets as necessary. */ ! 79: static rtx copy_rtx_and_substitute (); ! 80: ! 81: static void copy_parm_decls (); ! 82: static void copy_decl_tree (); ! 83: ! 84: static rtx try_fold_cc0 (); ! 85: ! 86: /* We do some simple constant folding optimization. This optimization ! 87: really exists primarily to save time inlining a function. It ! 88: also help users who ask for inline functions without -O. */ ! 89: static rtx fold_out_const_cc0 (); ! 90: ! 91: /* Zero if the current function (whose FUNCTION_DECL is FNDECL) ! 92: is safe and reasonable to integrate into other functions. ! 93: Nonzero means value is a warning message with a single %s ! 94: for the function's name. */ ! 95: ! 96: char * ! 97: function_cannot_inline_p (fndecl) ! 98: register tree fndecl; ! 99: { ! 100: register rtx insn; ! 101: tree last = tree_last (TYPE_ARG_TYPES (TREE_TYPE (fndecl))); ! 102: int nargs = list_length (DECL_ARGUMENTS (fndecl)); ! 103: int max_insns = 4 * (4 + nargs + 16*TREE_INLINE (fndecl)); ! 104: register int ninsns = 0; ! 105: register tree parms; ! 106: ! 107: /* No inlines with varargs. `grokdeclarator' gives a warning ! 108: message about that if `inline' is specified. This code ! 109: it put in to catch the volunteers. */ ! 110: if (last && TREE_VALUE (last) != void_type_node) ! 111: return "varargs function `%s' cannot be inline"; ! 112: ! 113: /* If its not even close, don't even look. */ ! 114: if (get_max_uid () > 2 * max_insns) ! 115: return "function `%s' too large to be inline"; ! 116: ! 117: /* Don't inline functions which have BLKmode arguments. ! 118: Don't inline functions that take the address of ! 119: a parameter and do not specify a function prototype. */ ! 120: for (parms = DECL_ARGUMENTS (fndecl); parms; parms = TREE_CHAIN (parms)) ! 121: { ! 122: if (TYPE_MODE (TREE_TYPE (parms)) == BLKmode) ! 123: return "function `%s' with large aggregate parameter cannot be inline"; ! 124: if (last == NULL_TREE && TREE_ADDRESSABLE (parms)) ! 125: return "function `%s' without prototype uses address of parameter;\n cannot be inline"; ! 126: } ! 127: ! 128: if (get_max_uid () > max_insns) ! 129: { ! 130: for (ninsns = 0, insn = get_first_nonparm_insn (); insn && ninsns < max_insns; ! 131: insn = NEXT_INSN (insn)) ! 132: { ! 133: if (GET_CODE (insn) == INSN ! 134: || GET_CODE (insn) == JUMP_INSN ! 135: || GET_CODE (insn) == CALL_INSN) ! 136: ninsns++; ! 137: } ! 138: ! 139: if (ninsns >= max_insns) ! 140: return "function `%s' too large to be inline"; ! 141: } ! 142: ! 143: return 0; ! 144: } ! 145: ! 146: /* Variables used within save_for_inline. */ ! 147: ! 148: /* Mapping from old pesudo-register to new pseudo-registers. ! 149: The first element of this map is reg_map[FIRST_PSEUDO_REGISTER]. ! 150: It allocated in `save_current_insns' and `expand_function_inline', ! 151: and deallocated on exit from each of those routines. */ ! 152: static rtx *reg_map; ! 153: ! 154: /* Mapping from old code-labels to new code-labels. ! 155: The first element of this map is label_map[min_labelno]. ! 156: It allocated in `save_current_insns' and `expand_function_inline', ! 157: and deallocated on exit from each of those routines. */ ! 158: static rtx *label_map; ! 159: ! 160: /* Map pseudo reg number into the PARM_DECL for the parm living in the reg. ! 161: Zero for a reg that isn't a parm's home. ! 162: Only reg numbers less than max_parm_reg are mapped here. */ ! 163: static tree *parmdecl_map; ! 164: ! 165: /* Keep track of first pseudo-register beyond those that are parms. */ ! 166: static int max_parm_reg; ! 167: ! 168: /* On machines that perform a function return with a single ! 169: instruction, such as the VAX, these return insns must be ! 170: mapped into branch statements. */ ! 171: extern rtx return_label; ! 172: ! 173: /* Copy an rtx for save_for_inline. */ ! 174: static rtx copy_for_inline (); ! 175: ! 176: /* Make the insns and PARM_DECLs of the current function permanent ! 177: and record other information in DECL_SAVED_INSNS to allow inlining ! 178: of this function in subsequent calls. */ ! 179: ! 180: void ! 181: save_for_inline (fndecl) ! 182: tree fndecl; ! 183: { ! 184: extern rtx *regno_reg_rtx; /* in emit-rtl.c. */ ! 185: extern current_function_args_size; ! 186: ! 187: rtx first_insn, last_insn, insn; ! 188: rtx head, copy; ! 189: tree parms; ! 190: int max_labelno, min_labelno, i, len; ! 191: int max_reg; ! 192: ! 193: /* Make and emit a return-label if we have not already done so. */ ! 194: ! 195: if (return_label == 0) ! 196: { ! 197: return_label = gen_label_rtx (); ! 198: emit_label (return_label); ! 199: } ! 200: ! 201: /* Get some bounds on the labels and registers used. */ ! 202: ! 203: max_labelno = max_label_num (); ! 204: min_labelno = get_first_label_num (); ! 205: max_parm_reg = max_parm_reg_num (); ! 206: max_reg = max_reg_num (); ! 207: ! 208: /* Set up PARMDECL_MAP which maps pseudo-reg number to its PARM_DECL. ! 209: ! 210: Set TREE_VOLATILE to 0 if the parm is in a register, otherwise 1. ! 211: Later we set TREE_READONLY to 0 if the parm is modified inside the fn. */ ! 212: ! 213: parmdecl_map = (tree *) alloca (max_parm_reg * sizeof (tree)); ! 214: ! 215: for (parms = DECL_ARGUMENTS (fndecl); parms; parms = TREE_CHAIN (parms)) ! 216: { ! 217: rtx p = DECL_RTL (parms); ! 218: ! 219: if (GET_CODE (p) == REG) ! 220: { ! 221: parmdecl_map[REGNO (p)] = parms; ! 222: TREE_VOLATILE (parms) = 0; ! 223: } ! 224: else ! 225: TREE_VOLATILE (parms) = 1; ! 226: TREE_READONLY (parms) = 1; ! 227: } ! 228: ! 229: /* The list of DECL_SAVES_INSNS, starts off with a header which ! 230: contains the following information: ! 231: ! 232: the first insn of the function (not including the insns that copy ! 233: parameters into registers). ! 234: the first label used by that function, ! 235: the last label used by that function, ! 236: and the total number of registers used. */ ! 237: ! 238: head = gen_inline_header_rtx (NULL, NULL, min_labelno, max_labelno, ! 239: max_parm_reg, max_reg, ! 240: current_function_args_size); ! 241: ! 242: /* We have now allocated all that needs to be allocated permanently ! 243: on the rtx obstack. Set our high-water mark, so that we ! 244: can free the rest of this when the time comes. */ ! 245: ! 246: preserve_data (); ! 247: ! 248: /* Copy the chain insns of this function. ! 249: Install the copied chain as the insns of this function, ! 250: for continued compilation; ! 251: the original chain is recorded as the DECL_SAVED_INSNS ! 252: for inlining future calls. */ ! 253: ! 254: /* If there are insns that copy parms from the stack into pseudo registers, ! 255: those insns are not copied. `expand_inline_function' must ! 256: emit the correct code to handle such things. */ ! 257: ! 258: insn = get_insns (); ! 259: if (GET_CODE (insn) != NOTE) ! 260: abort (); ! 261: first_insn = rtx_alloc (NOTE); ! 262: NOTE_SOURCE_FILE (first_insn) = NOTE_SOURCE_FILE (insn); ! 263: NOTE_LINE_NUMBER (first_insn) = NOTE_LINE_NUMBER (insn); ! 264: INSN_UID (first_insn) = INSN_UID (insn); ! 265: PREV_INSN (first_insn) = NULL; ! 266: NEXT_INSN (first_insn) = NULL; ! 267: last_insn = first_insn; ! 268: ! 269: /* Each pseudo-reg in the old insn chain must have a unique rtx in the copy. ! 270: Make these new rtx's now, and install them in regno_reg_rtx, so they ! 271: will be the official pseudo-reg rtx's for the rest of compilation. */ ! 272: ! 273: reg_map = (rtx *) alloca ((max_reg + 1) * sizeof (rtx)); ! 274: ! 275: len = sizeof (struct rtx_def) + (GET_RTX_LENGTH (REG) - 1) * sizeof (rtunion); ! 276: for (i = max_reg - 1; i >= FIRST_PSEUDO_REGISTER; i--) ! 277: reg_map[i] = (rtx)obstack_copy (&maybepermanent_obstack, regno_reg_rtx[i], len); ! 278: bcopy (reg_map + FIRST_PSEUDO_REGISTER, ! 279: regno_reg_rtx + FIRST_PSEUDO_REGISTER, ! 280: (max_reg_num () - FIRST_PSEUDO_REGISTER) * sizeof (rtx)); ! 281: ! 282: /* Likewise each label rtx must have a unique rtx as its copy. */ ! 283: ! 284: label_map = (rtx *)alloca ((max_labelno - min_labelno) * sizeof (rtx)); ! 285: label_map -= min_labelno; ! 286: ! 287: for (i = min_labelno; i < max_labelno; i++) ! 288: label_map[i] = gen_label_rtx (); ! 289: ! 290: /* Now copy the chain of insns. */ ! 291: ! 292: for (insn = NEXT_INSN (insn); insn; insn = NEXT_INSN (insn)) ! 293: { ! 294: switch (GET_CODE (insn)) ! 295: { ! 296: case NOTE: ! 297: copy = rtx_alloc (NOTE); ! 298: NOTE_SOURCE_FILE (copy) = NOTE_SOURCE_FILE (insn); ! 299: NOTE_LINE_NUMBER (copy) = NOTE_LINE_NUMBER (insn); ! 300: break; ! 301: ! 302: case INSN: ! 303: case CALL_INSN: ! 304: case JUMP_INSN: ! 305: copy = rtx_alloc (GET_CODE (insn)); ! 306: PATTERN (copy) = copy_for_inline (PATTERN (insn)); ! 307: INSN_CODE (copy) = -1; ! 308: LOG_LINKS (copy) = NULL; ! 309: REG_NOTES (copy) = copy_for_inline (REG_NOTES (insn)); ! 310: break; ! 311: ! 312: case CODE_LABEL: ! 313: copy = label_map[CODE_LABEL_NUMBER (insn)]; ! 314: break; ! 315: ! 316: case BARRIER: ! 317: copy = rtx_alloc (BARRIER); ! 318: break; ! 319: ! 320: default: ! 321: abort (); ! 322: } ! 323: INSN_UID (copy) = INSN_UID (insn); ! 324: NEXT_INSN (last_insn) = copy; ! 325: PREV_INSN (copy) = last_insn; ! 326: last_insn = copy; ! 327: } ! 328: ! 329: NEXT_INSN (last_insn) = NULL; ! 330: ! 331: NEXT_INSN (head) = get_first_nonparm_insn (); ! 332: FIRST_PARM_INSN (head) = get_insns (); ! 333: DECL_SAVED_INSNS (fndecl) = head; ! 334: DECL_FRAME_SIZE (fndecl) = get_frame_size (); ! 335: TREE_INLINE (fndecl) = 1; ! 336: ! 337: parmdecl_map = 0; ! 338: label_map = 0; ! 339: reg_map = 0; ! 340: return_label = 0; ! 341: ! 342: set_new_first_and_last_insn (first_insn, last_insn); ! 343: } ! 344: ! 345: /* Copy the rtx ORIG recursively, replacing pseudo-regs and labels ! 346: according to `reg_map' and `label_map'. ! 347: All other kinds of rtx are copied except those that can never be ! 348: changed during compilation. */ ! 349: ! 350: static rtx ! 351: copy_for_inline (orig) ! 352: rtx orig; ! 353: { ! 354: register rtx x = orig; ! 355: register int i; ! 356: register enum rtx_code code; ! 357: register char *format_ptr; ! 358: ! 359: if (x == 0) ! 360: return x; ! 361: ! 362: code = GET_CODE (x); ! 363: ! 364: /* These types may be freely shared. */ ! 365: ! 366: switch (code) ! 367: { ! 368: case QUEUED: ! 369: case CONST_INT: ! 370: case CONST_DOUBLE: ! 371: case SYMBOL_REF: ! 372: case CODE_LABEL: ! 373: case PC: ! 374: case CC0: ! 375: return x; ! 376: ! 377: case MEM: ! 378: /* A MEM is allowed to be shared if its address is constant ! 379: or is a constant plus one of the special registers. */ ! 380: if (CONSTANT_ADDRESS_P (XEXP (x, 0))) ! 381: return x; ! 382: if (GET_CODE (XEXP (x, 0)) == PLUS ! 383: && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG ! 384: && (REGNO (XEXP (XEXP (x, 0), 0)) == FRAME_POINTER_REGNUM ! 385: || REGNO (XEXP (XEXP (x, 0), 0)) == ARG_POINTER_REGNUM) ! 386: && CONSTANT_ADDRESS_P (XEXP (XEXP (x, 0), 1))) ! 387: if (GET_CODE (XEXP (x, 0)) == REG ! 388: && (REGNO (XEXP (x, 0)) == FRAME_POINTER_REGNUM ! 389: || REGNO (XEXP (x, 0)) == ARG_POINTER_REGNUM) ! 390: && CONSTANT_ADDRESS_P (XEXP (x, 1))) ! 391: return x; ! 392: break; ! 393: ! 394: case LABEL_REF: ! 395: { ! 396: /* Must point to the new insn. */ ! 397: return gen_rtx (LABEL_REF, GET_MODE (orig), ! 398: label_map[CODE_LABEL_NUMBER (XEXP (orig, 0))]); ! 399: } ! 400: ! 401: case REG: ! 402: if (REGNO (x) >= FIRST_PSEUDO_REGISTER) ! 403: return reg_map [REGNO (x)]; ! 404: else ! 405: return x; ! 406: ! 407: /* If a parm that gets modified lives in a pseudo-reg, ! 408: set its TREE_VOLATILE to prevent certain optimizations. */ ! 409: case SET: ! 410: { ! 411: rtx dest = SET_DEST (x); ! 412: ! 413: if (GET_CODE (dest) == REG ! 414: && REGNO (dest) < max_parm_reg ! 415: && REGNO (dest) >= FIRST_PSEUDO_REGISTER) ! 416: TREE_READONLY (parmdecl_map[REGNO (dest)]) = 0; ! 417: } ! 418: break; ! 419: } ! 420: ! 421: /* Replace this rtx with a copy of itself. */ ! 422: ! 423: x = rtx_alloc (code); ! 424: bcopy (orig, x, sizeof (int) * (GET_RTX_LENGTH (code) + 1)); ! 425: ! 426: /* Now scan the subexpressions recursively. ! 427: We can store any replaced subexpressions directly into X ! 428: since we know X is not shared! Any vectors in X ! 429: must be copied if X was copied. */ ! 430: ! 431: format_ptr = GET_RTX_FORMAT (code); ! 432: ! 433: for (i = 0; i < GET_RTX_LENGTH (code); i++) ! 434: { ! 435: switch (*format_ptr++) ! 436: { ! 437: case 'e': ! 438: XEXP (x, i) = copy_for_inline (XEXP (x, i)); ! 439: break; ! 440: ! 441: case 'E': ! 442: if (XVEC (x, i) != NULL) ! 443: { ! 444: register int j; ! 445: ! 446: XVEC (x, i) = gen_rtvec_v (XVECLEN (x, i), &XVECEXP (x, i, 0)); ! 447: for (j = 0; j < XVECLEN (x, i); j++) ! 448: XVECEXP (x, i, j) ! 449: = copy_for_inline (XVECEXP (x, i, j)); ! 450: } ! 451: break; ! 452: } ! 453: } ! 454: return x; ! 455: } ! 456: ! 457: /* Integrate the procedure defined by FNDECL. Note that this function ! 458: may wind up calling itself. Since the static variables are not ! 459: reentrant, we do not assign them until after the possibility ! 460: or recursion is eliminated. ! 461: ! 462: If IGNORE is nonzero, do not produce a value. ! 463: Otherwise store the value in TARGET if it is nonzero and that is convenient. ! 464: ! 465: Value is: ! 466: (rtx)-1 if we could not substitute the function ! 467: 0 if we substituted it and it does not produce a value ! 468: else an rtx for where the value is stored. */ ! 469: ! 470: rtx ! 471: expand_inline_function (fndecl, parms, target, ignore, type, structure_value_addr) ! 472: tree fndecl, parms; ! 473: rtx target; ! 474: int ignore; ! 475: tree type; ! 476: rtx structure_value_addr; ! 477: { ! 478: tree formal, actual; ! 479: rtx header = DECL_SAVED_INSNS (fndecl); ! 480: rtx insns = FIRST_FUNCTION_INSN (header); ! 481: rtx insn, protect; ! 482: rtx last_insn = get_last_insn (); ! 483: int max_regno = MAX_REGNUM (header) + 1; ! 484: register int i; ! 485: int keep; ! 486: int min_labelno = FIRST_LABELNO (header); ! 487: int max_labelno = LAST_LABELNO (header); ! 488: int nargs; ! 489: rtx *arg_vec; ! 490: rtx return_label = 0; ! 491: rtx follows_call = 0; ! 492: ! 493: if (max_regno < FIRST_PSEUDO_REGISTER) ! 494: return (rtx)-1; ! 495: ! 496: nargs = list_length (DECL_ARGUMENTS (fndecl)); ! 497: ! 498: /* We expect PARMS to have the right length; don't crash if not. */ ! 499: if (list_length (parms) != nargs) ! 500: return (rtx)-1; ! 501: ! 502: /* Make a fresh binding contour that we can easily remove. */ ! 503: pushlevel (0); ! 504: expand_start_bindings (0); ! 505: ! 506: /* Get all the actual args as RTL, and store them in ARG_VEC. */ ! 507: ! 508: arg_vec = (rtx *)alloca (nargs * sizeof (rtx)); ! 509: ! 510: for (formal = DECL_ARGUMENTS (fndecl), ! 511: actual = parms, ! 512: i = 0; ! 513: formal; ! 514: formal = TREE_CHAIN (formal), ! 515: actual = TREE_CHAIN (actual), ! 516: i++) ! 517: { ! 518: tree arg = TREE_VALUE (actual); /* this has already been converted */ ! 519: enum machine_mode tmode = TYPE_MODE (TREE_TYPE (formal)); ! 520: tree decl = formal; ! 521: rtx copy; ! 522: ! 523: emit_note (DECL_SOURCE_FILE (decl), DECL_SOURCE_LINE (decl)); ! 524: ! 525: if (TREE_ADDRESSABLE (formal)) ! 526: { ! 527: int size = int_size_in_bytes (TREE_TYPE (formal)); ! 528: copy = assign_stack_local (tmode, size); ! 529: store_expr (arg, copy, 0); ! 530: } ! 531: else if (! TREE_READONLY (formal) ! 532: || TREE_VOLATILE (formal)) ! 533: { ! 534: /* If parm is modified or if it hasn't a pseudo reg, ! 535: we may not simply substitute the actual value; ! 536: copy it through a register. */ ! 537: copy = gen_reg_rtx (tmode); ! 538: store_expr (arg, copy, 0); ! 539: } ! 540: else ! 541: { ! 542: copy = expand_expr (arg, 0, tmode, 0); ! 543: ! 544: /* We do not use CONSTANT_ADDRESS_P here because ! 545: the set of cases where that might make a difference ! 546: are a subset of the cases that arise even when ! 547: it is a CONSTANT_ADDRESS_P (i.e., fp_delta ! 548: gets into the act. */ ! 549: if (GET_CODE (copy) != REG && ! CONSTANT_P (copy)) ! 550: copy = copy_to_reg (copy); ! 551: } ! 552: arg_vec[i] = copy; ! 553: } ! 554: ! 555: copy_parm_decls (DECL_ARGUMENTS (fndecl), arg_vec); ! 556: ! 557: /* Perform postincrements before actually calling the function. */ ! 558: emit_queue (); ! 559: ! 560: /* clean up stack so that variables might have smaller offsets. */ ! 561: do_pending_stack_adjust (); ! 562: ! 563: /* Pass the function the address in which to return a structure value. */ ! 564: if (structure_value_addr) ! 565: emit_move_insn (struct_value_rtx, structure_value_addr); ! 566: ! 567: /* Now prepare for copying the insns. ! 568: Set up reg_map, parm_map and label_map saying how to translate ! 569: the pseudo-registers, stack-parm references and labels when copying. */ ! 570: ! 571: reg_map = (rtx *) alloca (max_regno * sizeof (rtx)); ! 572: bzero (reg_map, max_regno * sizeof (rtx)); ! 573: ! 574: if (DECL_ARGUMENTS (fndecl)) ! 575: { ! 576: tree decl = DECL_ARGUMENTS (fndecl); ! 577: tree last = tree_last (decl); ! 578: int offset = FUNCTION_ARGS_SIZE (header); ! 579: parm_map = ! 580: (rtx *)alloca ((offset / UNITS_PER_WORD) * sizeof (rtx)); ! 581: bzero (parm_map, (offset / UNITS_PER_WORD) * sizeof (rtx)); ! 582: parm_map -= FIRST_PARM_OFFSET / UNITS_PER_WORD; ! 583: ! 584: for (formal = decl, i = 0; formal; formal = TREE_CHAIN (formal), i++) ! 585: { ! 586: /* Create an entry in PARM_MAP that says what pseudo register ! 587: is associated with an address we might compute. */ ! 588: parm_map[DECL_OFFSET (formal) / BITS_PER_WORD] = arg_vec[i]; ! 589: /* Create an entry in REG_MAP that says what rtx is associated ! 590: with a pseudo register from the function being inlined. */ ! 591: if (GET_CODE (DECL_RTL (formal)) == REG) ! 592: reg_map[REGNO (DECL_RTL (formal))] = arg_vec[i]; ! 593: } ! 594: } ! 595: else ! 596: { ! 597: parm_map = NULL; ! 598: } ! 599: ! 600: label_map = (rtx *)alloca ((max_labelno - min_labelno) * sizeof (rtx)); ! 601: label_map -= min_labelno; ! 602: ! 603: for (i = min_labelno; i < max_labelno; i++) ! 604: label_map[i] = gen_label_rtx (); ! 605: ! 606: /* Set up a target to translate the inline function's value-register. */ ! 607: ! 608: if (structure_value_addr != 0 || TYPE_MODE (type) == VOIDmode) ! 609: inline_target = 0; ! 610: else if (target && GET_MODE (target) == TYPE_MODE (type)) ! 611: inline_target = target; ! 612: else ! 613: inline_target = gen_reg_rtx (TYPE_MODE (type)); ! 614: ! 615: /* We are about to make space in this function's stack frame ! 616: for a copy of the stack frame of the inline function. ! 617: First, create an RTX that points to that stack frame ! 618: with the same offset usually used for the frame pointer. ! 619: This will be substituted for all frame-pointer references. */ ! 620: ! 621: fp_delta = get_frame_size (); ! 622: #ifdef FRAME_GROWS_DOWNWARD ! 623: fp_delta = - fp_delta; ! 624: #endif ! 625: fp_delta -= STARTING_FRAME_OFFSET; ! 626: ! 627: inline_fp_rtx ! 628: = copy_to_mode_reg (Pmode, ! 629: plus_constant (frame_pointer_rtx, fp_delta)); ! 630: ! 631: /* Now allocate the space for that to point at. */ ! 632: ! 633: assign_stack_local (VOIDmode, DECL_FRAME_SIZE (fndecl)); ! 634: ! 635: /* Now copy the insns one by one. */ ! 636: ! 637: for (insn = insns; insn; insn = NEXT_INSN (insn)) ! 638: { ! 639: rtx copy, pattern, next = 0; ! 640: ! 641: switch (GET_CODE (insn)) ! 642: { ! 643: case INSN: ! 644: pattern = PATTERN (insn); ! 645: ! 646: /* Special handling for the insn immediately after a CALL_INSN ! 647: that returned a value: ! 648: If it does copy the value, we must avoid the usual translation ! 649: of the return-register into INLINE_TARGET. ! 650: If it just USEs the value, the inline function expects it to ! 651: stay in the return-register and be returned, ! 652: so copy it into INLINE_TARGET. */ ! 653: ! 654: if (follows_call ! 655: /* Allow a stack-adjust, handled normally, to come in between ! 656: the call and the value-copying insn. */ ! 657: && ! (GET_CODE (pattern) == SET ! 658: && SET_DEST (pattern) == stack_pointer_rtx)) ! 659: { ! 660: if (GET_CODE (pattern) == SET ! 661: && rtx_equal_p (SET_SRC (pattern), follows_call)) ! 662: /* This insn copies the value: take special care to copy ! 663: that value to this insn's destination. */ ! 664: { ! 665: copy = emit_insn (gen_rtx (SET, VOIDmode, ! 666: copy_rtx_and_substitute (SET_DEST (pattern)), ! 667: follows_call)); ! 668: copy->integrated = 1; ! 669: follows_call = 0; ! 670: break; ! 671: } ! 672: else if (GET_CODE (pattern) == USE ! 673: && rtx_equal_p (XEXP (pattern, 0), follows_call)) ! 674: /* This insn does nothing but says the value is expected ! 675: to flow through to the inline function's return-value. ! 676: Make that happen, then ignore this insn. */ ! 677: { ! 678: copy = emit_insn (gen_rtx (SET, VOIDmode, inline_target, ! 679: follows_call)); ! 680: copy->integrated = 1; ! 681: follows_call = 0; ! 682: break; ! 683: } ! 684: /* If it does neither, this value must be ignored. */ ! 685: follows_call = 0; ! 686: } ! 687: ! 688: /* The (USE (REG n)) at return from the function should be ignored ! 689: since we are changing (REG n) into inline_target. */ ! 690: if (GET_CODE (pattern) == USE ! 691: && GET_CODE (XEXP (pattern, 0)) == REG ! 692: && FUNCTION_VALUE_REGNO_P (REGNO (XEXP (pattern, 0)))) ! 693: break; ! 694: ! 695: /* Try to do some quick constant folding here. ! 696: This will save save execution time of the compiler, ! 697: as well time and space of the program if done here. */ ! 698: if (GET_CODE (pattern) == SET ! 699: && SET_DEST (pattern) == cc0_rtx) ! 700: next = try_fold_cc0 (insn); ! 701: ! 702: if (next != 0) ! 703: { ! 704: insn = next; ! 705: } ! 706: else ! 707: { ! 708: copy = emit_insn (copy_rtx_and_substitute (pattern)); ! 709: copy->integrated = 1; ! 710: } ! 711: break; ! 712: ! 713: case JUMP_INSN: ! 714: follows_call = 0; ! 715: if (GET_CODE (PATTERN (insn)) == RETURN) ! 716: { ! 717: if (return_label == 0) ! 718: return_label = gen_label_rtx (); ! 719: emit_jump (return_label); ! 720: break; ! 721: } ! 722: copy = emit_jump_insn (copy_rtx_and_substitute (PATTERN (insn))); ! 723: copy->integrated = 1; ! 724: break; ! 725: ! 726: case CALL_INSN: ! 727: { ! 728: rtx newbod; ! 729: /* If the call's body is (set (reg...) (call...)), ! 730: the register is a function return register, but DON'T ! 731: translate it into INLINE_TARGET because it describes the ! 732: called function, not the caller's return value. */ ! 733: if (GET_CODE (PATTERN (insn)) == SET) ! 734: newbod = gen_rtx (SET, VOIDmode, SET_DEST (PATTERN (insn)), ! 735: copy_rtx_and_substitute (SET_SRC (PATTERN (insn)))); ! 736: else ! 737: newbod = copy_rtx_and_substitute (PATTERN (insn)); ! 738: copy = emit_call_insn (newbod); ! 739: } ! 740: copy->integrated = 1; ! 741: /* Special handling needed for the following INSN depending on ! 742: whether it copies the value from the fcn return reg. */ ! 743: if (GET_CODE (PATTERN (insn)) == SET) ! 744: follows_call = SET_DEST (PATTERN (insn)); ! 745: break; ! 746: ! 747: case CODE_LABEL: ! 748: emit_label (label_map[CODE_LABEL_NUMBER (insn)]); ! 749: follows_call = 0; ! 750: break; ! 751: ! 752: case BARRIER: ! 753: emit_barrier (); ! 754: break; ! 755: ! 756: case NOTE: ! 757: emit_note (NOTE_SOURCE_FILE (insn), NOTE_LINE_NUMBER (insn)); ! 758: break; ! 759: ! 760: default: ! 761: abort (); ! 762: break; ! 763: } ! 764: } ! 765: ! 766: if (return_label) ! 767: emit_label (return_label); ! 768: ! 769: /* Make copies of the decls of the symbols in the inline function, so that ! 770: the copies of the variables get declared in the current function. */ ! 771: copy_decl_tree (DECL_INITIAL (fndecl), 0); ! 772: ! 773: /* End the scope containing the copied formal parameter variables. */ ! 774: ! 775: expand_end_bindings (getdecls (), 1); ! 776: poplevel (1, 1, 0); ! 777: ! 778: reg_map = NULL; ! 779: label_map = NULL; ! 780: ! 781: if (ignore || TYPE_MODE (type) == VOIDmode) ! 782: return 0; ! 783: ! 784: if (structure_value_addr) ! 785: { ! 786: if (target) ! 787: return target; ! 788: return gen_rtx (MEM, BLKmode, ! 789: memory_address (BLKmode, structure_value_addr)); ! 790: } ! 791: ! 792: return inline_target; ! 793: } ! 794: ! 795: /* Given a chain of PARM_DECLs, ARGS, and a vector of RTL homes VEC, ! 796: copy each decl into a VAR_DECL, push all of those decls ! 797: and give each one the corresponding home. */ ! 798: ! 799: static void ! 800: copy_parm_decls (args, vec) ! 801: tree args; ! 802: rtx *vec; ! 803: { ! 804: register tree tail; ! 805: register int i; ! 806: ! 807: for (tail = args, i = 0; tail; tail = TREE_CHAIN (tail), i++) ! 808: { ! 809: register tree decl = pushdecl (build_decl (VAR_DECL, DECL_NAME (tail), ! 810: TREE_TYPE (tail))); ! 811: DECL_RTL (decl) = vec[i]; ! 812: } ! 813: } ! 814: ! 815: /* Given a LET_STMT node, push decls and levels ! 816: so as to construct in the current function a tree of contexts ! 817: isomorphic to the one that is given. */ ! 818: ! 819: static void ! 820: copy_decl_tree (let, level) ! 821: tree let; ! 822: int level; ! 823: { ! 824: tree t; ! 825: ! 826: pushlevel (0); ! 827: ! 828: for (t = STMT_VARS (let); t; t = TREE_CHAIN (t)) ! 829: { ! 830: tree d = build_decl (TREE_CODE (t), DECL_NAME (t), TREE_TYPE (t)); ! 831: DECL_SOURCE_LINE (d) = DECL_SOURCE_LINE (t); ! 832: DECL_SOURCE_FILE (d) = DECL_SOURCE_FILE (t); ! 833: if (DECL_RTL (t) != 0) ! 834: DECL_RTL (d) = copy_rtx_and_substitute (DECL_RTL (t)); ! 835: TREE_EXTERNAL (d) = TREE_EXTERNAL (t); ! 836: TREE_STATIC (d) = TREE_STATIC (t); ! 837: TREE_PUBLIC (d) = TREE_PUBLIC (t); ! 838: TREE_LITERAL (d) = TREE_LITERAL (t); ! 839: TREE_ADDRESSABLE (d) = TREE_ADDRESSABLE (t); ! 840: TREE_READONLY (d) = TREE_READONLY (t); ! 841: TREE_VOLATILE (d) = TREE_VOLATILE (t); ! 842: pushdecl (d); ! 843: } ! 844: ! 845: for (t = STMT_BODY (let); t; t = TREE_CHAIN (t)) ! 846: copy_decl_tree (t, level + 1); ! 847: ! 848: poplevel (level > 0, 0, 0); ! 849: } ! 850: ! 851: /* Create a new copy of an rtx. ! 852: Recursively copies the operands of the rtx, ! 853: except for those few rtx codes that are sharable. */ ! 854: ! 855: static rtx ! 856: copy_rtx_and_substitute (orig) ! 857: register rtx orig; ! 858: { ! 859: register rtx copy, temp; ! 860: register int i, j; ! 861: register RTX_CODE code; ! 862: register enum machine_mode mode; ! 863: register char *format_ptr; ! 864: int regno; ! 865: ! 866: if (orig == 0) ! 867: return 0; ! 868: ! 869: code = GET_CODE (orig); ! 870: mode = GET_MODE (orig); ! 871: ! 872: switch (code) ! 873: { ! 874: case REG: ! 875: /* If a frame-pointer register shows up, then we ! 876: must `fix' the reference. If the stack pointer ! 877: register shows up, it must be part of stack-adjustments ! 878: (*not* because we eliminated the frame pointer!). ! 879: Small hard registers are returned as-is. Pseudo-registers ! 880: go through their `reg_map'. */ ! 881: regno = REGNO (orig); ! 882: if (regno < FIRST_PSEUDO_REGISTER) ! 883: { ! 884: if (FUNCTION_VALUE_REGNO_P (regno)) ! 885: return inline_target; ! 886: if (regno == FRAME_POINTER_REGNUM) ! 887: return plus_constant (orig, fp_delta); ! 888: return orig; ! 889: } ! 890: if (reg_map[regno] == NULL) ! 891: reg_map[regno] = gen_reg_rtx (mode); ! 892: return reg_map[regno]; ! 893: ! 894: case CODE_LABEL: ! 895: return label_map[CODE_LABEL_NUMBER (orig)]; ! 896: ! 897: case LABEL_REF: ! 898: copy = rtx_alloc (LABEL_REF); ! 899: PUT_MODE (copy, mode); ! 900: XEXP (copy, 0) = label_map[CODE_LABEL_NUMBER (XEXP (orig, 0))]; ! 901: return copy; ! 902: ! 903: case PC: ! 904: case CC0: ! 905: case CONST_INT: ! 906: case CONST_DOUBLE: ! 907: case SYMBOL_REF: ! 908: return orig; ! 909: ! 910: case PLUS: ! 911: /* Note: the PLUS case is not nearly as careful as the MEM ! 912: case in terms of preserving addresses. The reason for this ! 913: is that it is expected that if a PLUS_EXPR turns out not ! 914: to be a legitimate address, reload can fix that up, without ! 915: doing major damage. However, a MEM rtx must preside ! 916: over a legitimate address. The MEM case has lots of hair ! 917: to deal with what happens when it sits on a PLUS... */ ! 918: /* Take care of the easy case quickly. */ ! 919: if (XEXP (orig, 0) == frame_pointer_rtx ! 920: || XEXP (orig, 1) == frame_pointer_rtx ! 921: || (ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM ! 922: && (XEXP (orig, 0) == arg_pointer_rtx ! 923: || XEXP (orig, 1) == arg_pointer_rtx))) ! 924: { ! 925: if (XEXP (orig, 0) == frame_pointer_rtx ! 926: || XEXP (orig, 0) == arg_pointer_rtx) ! 927: copy = XEXP (orig, 1); ! 928: else ! 929: copy = XEXP (orig, 0); ! 930: ! 931: if (GET_CODE (copy) == CONST_INT) ! 932: { ! 933: int c = INTVAL (copy); ! 934: ! 935: if (c > 0) ! 936: { ! 937: copy = parm_map[c / UNITS_PER_WORD]; ! 938: return XEXP (copy, 0); ! 939: } ! 940: return gen_rtx (PLUS, mode, ! 941: frame_pointer_rtx, ! 942: gen_rtx (CONST_INT, SImode, ! 943: c + fp_delta)); ! 944: } ! 945: copy = copy_rtx_and_substitute (copy); ! 946: temp = gen_rtx (PLUS, mode, frame_pointer_rtx, copy); ! 947: return plus_constant (temp, fp_delta); ! 948: } ! 949: else if (reg_mentioned_p (frame_pointer_rtx, orig) ! 950: || (ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM ! 951: && reg_mentioned_p (arg_pointer_rtx, orig))) ! 952: { ! 953: /* If we have a complex sum which has a frame pointer ! 954: in it, and it was a legitimate address, then ! 955: keep it that way. */ ! 956: if (memory_address_p (mode, orig)) ! 957: { ! 958: if (GET_CODE (XEXP (orig, 0)) == CONST_INT) ! 959: { ! 960: copy = copy_rtx_and_substitute (XEXP (orig, 1)); ! 961: temp = plus_constant (copy, INTVAL (XEXP (orig, 0))); ! 962: } ! 963: else if (GET_CODE (XEXP (orig, 1)) == CONST_INT) ! 964: { ! 965: copy = copy_rtx_and_substitute (XEXP (orig, 0)); ! 966: temp = plus_constant (copy, INTVAL (XEXP (orig, 1))); ! 967: } ! 968: else ! 969: { ! 970: temp = gen_rtx (PLUS, GET_MODE (orig), ! 971: copy_rtx_and_substitute (XEXP (orig, 0)), ! 972: copy_rtx_and_substitute (XEXP (orig, 1))); ! 973: } ! 974: temp = memory_address (mode, temp); ! 975: } ! 976: else ! 977: temp = gen_rtx (PLUS, GET_MODE (orig), ! 978: copy_rtx_and_substitute (XEXP (orig, 0)), ! 979: copy_rtx_and_substitute (XEXP (orig, 1))); ! 980: } ! 981: else ! 982: temp = gen_rtx (PLUS, GET_MODE (orig), ! 983: copy_rtx_and_substitute (XEXP (orig, 0)), ! 984: copy_rtx_and_substitute (XEXP (orig, 1))); ! 985: ! 986: return temp; ! 987: ! 988: case MEM: ! 989: /* Take care of easiest case here. */ ! 990: copy = XEXP (orig, 0); ! 991: if (copy == frame_pointer_rtx || copy == arg_pointer_rtx) ! 992: return gen_rtx (MEM, mode, ! 993: plus_constant (frame_pointer_rtx, fp_delta)); ! 994: if (GET_CODE (copy) == PLUS) ! 995: { ! 996: if (XEXP (copy, 0) == frame_pointer_rtx ! 997: || XEXP (copy, 1) == frame_pointer_rtx ! 998: || (ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM ! 999: && (XEXP (copy, 0) == arg_pointer_rtx ! 1000: || XEXP (copy, 1) == arg_pointer_rtx))) ! 1001: { ! 1002: rtx reg; ! 1003: if (XEXP (copy, 0) == frame_pointer_rtx ! 1004: || XEXP (copy, 0) == arg_pointer_rtx) ! 1005: reg = XEXP (copy, 0), copy = XEXP (copy, 1); ! 1006: else ! 1007: reg = XEXP (copy, 1), copy = XEXP (copy, 0); ! 1008: ! 1009: if (GET_CODE (copy) == CONST_INT) ! 1010: { ! 1011: int c = INTVAL (copy); ! 1012: ! 1013: if (reg == arg_pointer_rtx ! 1014: && c >= FIRST_PARM_OFFSET) ! 1015: { ! 1016: copy = parm_map[c / UNITS_PER_WORD]; ! 1017: ! 1018: /* If the MEM is only some of the bytes in the parm, ! 1019: truncate the parm value to the desired mode. */ ! 1020: if (GET_MODE (copy) != mode ! 1021: && GET_MODE (copy) != VOIDmode) ! 1022: return convert_to_mode (mode, copy, 0); ! 1023: return copy; ! 1024: } ! 1025: temp = gen_rtx (PLUS, Pmode, ! 1026: frame_pointer_rtx, ! 1027: gen_rtx (CONST_INT, SImode, ! 1028: c + fp_delta)); ! 1029: if (! memory_address_p (Pmode, temp)) ! 1030: return gen_rtx (MEM, mode, plus_constant (inline_fp_rtx, c)); ! 1031: } ! 1032: copy = copy_rtx_and_substitute (copy); ! 1033: temp = gen_rtx (PLUS, Pmode, frame_pointer_rtx, copy); ! 1034: temp = plus_constant (temp, fp_delta); ! 1035: temp = memory_address (Pmode, temp); ! 1036: } ! 1037: else if (reg_mentioned_p (frame_pointer_rtx, copy) ! 1038: || (ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM ! 1039: && reg_mentioned_p (arg_pointer_rtx, copy))) ! 1040: { ! 1041: if (GET_CODE (XEXP (copy, 0)) == CONST_INT) ! 1042: { ! 1043: temp = copy_rtx_and_substitute (XEXP (copy, 1)); ! 1044: temp = plus_constant (temp, INTVAL (XEXP (copy, 0))); ! 1045: } ! 1046: else if (GET_CODE (XEXP (copy, 1)) == CONST_INT) ! 1047: { ! 1048: temp = copy_rtx_and_substitute (XEXP (copy, 0)); ! 1049: temp = plus_constant (temp, INTVAL (XEXP (copy, 1))); ! 1050: } ! 1051: else ! 1052: { ! 1053: temp = gen_rtx (PLUS, GET_MODE (copy), ! 1054: copy_rtx_and_substitute (XEXP (copy, 0)), ! 1055: copy_rtx_and_substitute (XEXP (copy, 1))); ! 1056: } ! 1057: } ! 1058: else ! 1059: { ! 1060: if (GET_CODE (XEXP (copy, 1)) == CONST_INT) ! 1061: temp = plus_constant (copy_rtx_and_substitute (XEXP (copy, 0)), ! 1062: INTVAL (XEXP (copy, 1))); ! 1063: else if (GET_CODE (XEXP (copy, 0)) == CONST_INT) ! 1064: temp = plus_constant (copy_rtx_and_substitute (XEXP (copy, 1)), ! 1065: INTVAL (XEXP (copy, 0))); ! 1066: else ! 1067: { ! 1068: rtx left = copy_rtx_and_substitute (XEXP (copy, 0)); ! 1069: rtx right = copy_rtx_and_substitute (XEXP (copy, 1)); ! 1070: ! 1071: temp = gen_rtx (PLUS, GET_MODE (copy), left, right); ! 1072: } ! 1073: } ! 1074: } ! 1075: else ! 1076: temp = copy_rtx_and_substitute (copy); ! 1077: ! 1078: return change_address (orig, mode, temp); ! 1079: ! 1080: case RETURN: ! 1081: abort (); ! 1082: } ! 1083: ! 1084: copy = rtx_alloc (code); ! 1085: PUT_MODE (copy, mode); ! 1086: copy->in_struct = orig->in_struct; ! 1087: copy->volatil = orig->volatil; ! 1088: copy->unchanging = orig->unchanging; ! 1089: ! 1090: format_ptr = GET_RTX_FORMAT (GET_CODE (copy)); ! 1091: ! 1092: for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++) ! 1093: { ! 1094: rtx new; ! 1095: ! 1096: switch (*format_ptr++) ! 1097: { ! 1098: case 'u': ! 1099: case '0': ! 1100: break; ! 1101: ! 1102: case 'e': ! 1103: XEXP (copy, i) = copy_rtx_and_substitute (XEXP (orig, i)); ! 1104: break; ! 1105: ! 1106: case 'E': ! 1107: XVEC (copy, i) = XVEC (orig, i); ! 1108: if (XVEC (orig, i) != NULL) ! 1109: { ! 1110: XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i)); ! 1111: for (j = 0; j < XVECLEN (copy, i); j++) ! 1112: XVECEXP (copy, i, j) = copy_rtx_and_substitute (XVECEXP (orig, i, j)); ! 1113: } ! 1114: break; ! 1115: ! 1116: case 'i': ! 1117: XINT (copy, i) = XINT (orig, i); ! 1118: break; ! 1119: ! 1120: case 's': ! 1121: XSTR (copy, i) = XSTR (orig, i); ! 1122: break; ! 1123: ! 1124: default: ! 1125: fprintf (stderr, ! 1126: "switch format wrong in rtl2.copy_rtx_and_substitute(). format was: %c.\n", ! 1127: format_ptr[-1]); ! 1128: abort (); ! 1129: } ! 1130: } ! 1131: return copy; ! 1132: } ! 1133: ! 1134: /* Attempt to simplify INSN while copying it from an inline fn, ! 1135: assuming it is a SET that sets CC0. ! 1136: ! 1137: If we simplify it, we emit the appropriate insns and return ! 1138: the last insn that we have handled (since we may handle the insn ! 1139: that follows INSN as well as INSN itself). ! 1140: ! 1141: Otherwise we do nothing and return zero. */ ! 1142: ! 1143: static rtx ! 1144: try_fold_cc0 (insn) ! 1145: rtx insn; ! 1146: { ! 1147: rtx cnst = copy_rtx_and_substitute (SET_SRC (PATTERN (insn))); ! 1148: rtx pat, copy; ! 1149: ! 1150: if (CONSTANT_P (cnst) ! 1151: /* @@ Cautious: Don't know how many of these tests we need. */ ! 1152: && NEXT_INSN (insn) ! 1153: && GET_CODE (pat = PATTERN (NEXT_INSN (insn))) == SET ! 1154: && SET_DEST (pat) == pc_rtx ! 1155: && GET_CODE (pat = SET_SRC (pat)) == IF_THEN_ELSE ! 1156: && GET_RTX_LENGTH (GET_CODE (XEXP (pat, 0))) == 2) ! 1157: { ! 1158: rtx cnst2; ! 1159: rtx cond = XEXP (pat, 0); ! 1160: ! 1161: if ((XEXP (cond, 0) == cc0_rtx ! 1162: && CONSTANT_P (XEXP (cond, 1)) ! 1163: && (cnst2 = XEXP (cond, 1))) ! 1164: || (XEXP (cond, 1) == cc0_rtx ! 1165: && CONSTANT_P (XEXP (cond, 0)) ! 1166: && (cnst2 = XEXP (cond, 0)))) ! 1167: { ! 1168: copy = fold_out_const_cc0 (cond, XEXP (pat, 1), XEXP (pat, 2), ! 1169: cnst, cnst2); ! 1170: if (copy) ! 1171: { ! 1172: if (GET_CODE (copy) == LABEL_REF) ! 1173: { ! 1174: /* We will branch unconditionally to ! 1175: the label specified by COPY. ! 1176: Eliminate dead code by running down the ! 1177: list of insn until we see a CODE_LABEL. ! 1178: If the CODE_LABEL is the one specified ! 1179: by COPY, we win, and can delete all code ! 1180: up to (but not necessarily including) ! 1181: that label. Otherwise only win a little: ! 1182: emit the branch insn, and continue expanding. */ ! 1183: rtx tmp = NEXT_INSN (insn); ! 1184: while (tmp && GET_CODE (tmp) != CODE_LABEL) ! 1185: tmp = NEXT_INSN (tmp); ! 1186: if (! tmp) ! 1187: abort (); ! 1188: if (label_map[CODE_LABEL_NUMBER (tmp)] == XEXP (copy, 0)) ! 1189: { ! 1190: /* Big win. */ ! 1191: return PREV_INSN (tmp); ! 1192: } ! 1193: else ! 1194: { ! 1195: /* Small win. Emit the unconditional branch, ! 1196: followed by a BARRIER, so that jump optimization ! 1197: will know what to do. */ ! 1198: emit_jump (copy); ! 1199: return NEXT_INSN (insn); ! 1200: } ! 1201: } ! 1202: else if (copy == pc_rtx) ! 1203: { ! 1204: /* Do not take the branch, just fall through. ! 1205: Jump optimize should handle the elimination of ! 1206: dead code if appropriate. */ ! 1207: return NEXT_INSN (insn); ! 1208: } ! 1209: else ! 1210: abort (); ! 1211: } ! 1212: } ! 1213: } ! 1214: return 0; ! 1215: } ! 1216: ! 1217: /* If (COND_RTX CNST1 CNST2) yield a result we can treat ! 1218: as being constant, return THEN_RTX if the result is always ! 1219: non-zero, and return ELSE_RTX otherwise. */ ! 1220: static rtx ! 1221: fold_out_const_cc0 (cond_rtx, then_rtx, else_rtx, cnst1, cnst2) ! 1222: rtx cond_rtx, then_rtx, else_rtx; ! 1223: rtx cnst1, cnst2; ! 1224: { ! 1225: int value1, value2; ! 1226: int int1 = GET_CODE (cnst1) == CONST_INT; ! 1227: int int2 = GET_CODE (cnst2) == CONST_INT; ! 1228: if (int1) ! 1229: value1 = INTVAL (cnst1); ! 1230: else ! 1231: value1 = 1; ! 1232: if (int2) ! 1233: value2 = INTVAL (cnst2); ! 1234: else ! 1235: value2 = 1; ! 1236: ! 1237: switch (GET_CODE (cond_rtx)) ! 1238: { ! 1239: case NE: ! 1240: if (int1 && int2) ! 1241: if (value1 != value2) ! 1242: return copy_rtx_and_substitute (then_rtx); ! 1243: else ! 1244: return copy_rtx_and_substitute (else_rtx); ! 1245: if (value1 == 0 || value2 == 0) ! 1246: return copy_rtx_and_substitute (then_rtx); ! 1247: if (int1 == 0 && int2 == 0) ! 1248: if (rtx_equal_p (cnst1, cnst2)) ! 1249: return copy_rtx_and_substitute (else_rtx); ! 1250: break; ! 1251: case EQ: ! 1252: if (int1 && int2) ! 1253: if (value1 == value2) ! 1254: return copy_rtx_and_substitute (then_rtx); ! 1255: else ! 1256: return copy_rtx_and_substitute (else_rtx); ! 1257: if (value1 == 0 || value2 == 0) ! 1258: return copy_rtx_and_substitute (else_rtx); ! 1259: if (int1 == 0 && int2 == 0) ! 1260: if (rtx_equal_p (cnst1, cnst2)) ! 1261: return copy_rtx_and_substitute (then_rtx); ! 1262: break; ! 1263: case GE: ! 1264: if (int1 && int2) ! 1265: if (value1 >= value2) ! 1266: return copy_rtx_and_substitute (then_rtx); ! 1267: else ! 1268: return copy_rtx_and_substitute (else_rtx); ! 1269: if (value1 == 0) ! 1270: return copy_rtx_and_substitute (else_rtx); ! 1271: if (value2 == 0) ! 1272: return copy_rtx_and_substitute (then_rtx); ! 1273: break; ! 1274: case GT: ! 1275: if (int1 && int2) ! 1276: if (value1 > value2) ! 1277: return copy_rtx_and_substitute (then_rtx); ! 1278: else ! 1279: return copy_rtx_and_substitute (else_rtx); ! 1280: if (value1 == 0) ! 1281: return copy_rtx_and_substitute (else_rtx); ! 1282: if (value2 == 0) ! 1283: return copy_rtx_and_substitute (then_rtx); ! 1284: break; ! 1285: case LE: ! 1286: if (int1 && int2) ! 1287: if (value1 <= value2) ! 1288: return copy_rtx_and_substitute (then_rtx); ! 1289: else ! 1290: return copy_rtx_and_substitute (else_rtx); ! 1291: if (value1 == 0) ! 1292: return copy_rtx_and_substitute (then_rtx); ! 1293: if (value2 == 0) ! 1294: return copy_rtx_and_substitute (else_rtx); ! 1295: break; ! 1296: case LT: ! 1297: if (int1 && int2) ! 1298: if (value1 < value2) ! 1299: return copy_rtx_and_substitute (then_rtx); ! 1300: else ! 1301: return copy_rtx_and_substitute (else_rtx); ! 1302: if (value1 == 0) ! 1303: return copy_rtx_and_substitute (then_rtx); ! 1304: if (value2 == 0) ! 1305: return copy_rtx_and_substitute (else_rtx); ! 1306: break; ! 1307: case GEU: ! 1308: if (int1 && int2) ! 1309: if ((unsigned)value1 >= (unsigned)value2) ! 1310: return copy_rtx_and_substitute (then_rtx); ! 1311: else ! 1312: return copy_rtx_and_substitute (else_rtx); ! 1313: if (value1 == 0) ! 1314: return copy_rtx_and_substitute (else_rtx); ! 1315: if (value2 == 0) ! 1316: return copy_rtx_and_substitute (then_rtx); ! 1317: break; ! 1318: case GTU: ! 1319: if (int1 && int2) ! 1320: if ((unsigned)value1 > (unsigned)value2) ! 1321: return copy_rtx_and_substitute (then_rtx); ! 1322: else ! 1323: return copy_rtx_and_substitute (else_rtx); ! 1324: if (value1 == 0) ! 1325: return copy_rtx_and_substitute (else_rtx); ! 1326: if (value2 == 0) ! 1327: return copy_rtx_and_substitute (then_rtx); ! 1328: break; ! 1329: case LEU: ! 1330: if (int1 && int2) ! 1331: if ((unsigned)value1 <= (unsigned)value2) ! 1332: return copy_rtx_and_substitute (then_rtx); ! 1333: else ! 1334: return copy_rtx_and_substitute (else_rtx); ! 1335: if (value1 == 0) ! 1336: return copy_rtx_and_substitute (then_rtx); ! 1337: if (value2 == 0) ! 1338: return copy_rtx_and_substitute (else_rtx); ! 1339: break; ! 1340: case LTU: ! 1341: if (int1 && int2) ! 1342: if ((unsigned)value1 < (unsigned)value2) ! 1343: return copy_rtx_and_substitute (then_rtx); ! 1344: else ! 1345: return copy_rtx_and_substitute (else_rtx); ! 1346: if (value1 == 0) ! 1347: return copy_rtx_and_substitute (then_rtx); ! 1348: if (value2 == 0) ! 1349: return copy_rtx_and_substitute (else_rtx); ! 1350: break; ! 1351: } ! 1352: /* Could not hack it. */ ! 1353: return 0; ! 1354: } ! 1355: ! 1356: /* Output the assembly language code for the function FNDECL ! 1357: from its DECL_SAVED_INSNS. Used for inline functions that are output ! 1358: at end of compilation instead of where they came in the source. */ ! 1359: ! 1360: void ! 1361: output_inline_function (fndecl) ! 1362: tree fndecl; ! 1363: { ! 1364: rtx head = DECL_SAVED_INSNS (fndecl); ! 1365: rtx last; ! 1366: ! 1367: temporary_allocation (); ! 1368: ! 1369: /* This call is only used to initialize global variables. ! 1370: The rtl code it emits will be discarded below. */ ! 1371: expand_function_start (fndecl); ! 1372: ! 1373: /* Set stack frame size. */ ! 1374: assign_stack_local (BLKmode, DECL_FRAME_SIZE (fndecl)); ! 1375: ! 1376: restore_reg_data (FIRST_PARM_INSN (head)); ! 1377: ! 1378: expand_function_end (fndecl); ! 1379: ! 1380: for (last = head; NEXT_INSN (last); last = NEXT_INSN (last)) ! 1381: ; ! 1382: ! 1383: set_new_first_and_last_insn (FIRST_PARM_INSN (head), last); ! 1384: ! 1385: /* Compile this function all the way down to assembly code. */ ! 1386: rest_of_compilation (fndecl); ! 1387: ! 1388: permanent_allocation (); ! 1389: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.