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