|
|
1.1 ! root 1: /* Procedure integration for GNU CC. ! 2: Copyright (C) 1988, 1991 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 free software; you can redistribute it and/or modify ! 8: it under the terms of the GNU General Public License as published by ! 9: the Free Software Foundation; either version 2, or (at your option) ! 10: any later version. ! 11: ! 12: GNU CC is distributed in the hope that it will be useful, ! 13: but WITHOUT ANY WARRANTY; without even the implied warranty of ! 14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 15: GNU General Public License for more details. ! 16: ! 17: You should have received a copy of the GNU General Public License ! 18: along with GNU CC; see the file COPYING. If not, write to ! 19: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ ! 20: ! 21: ! 22: #include <stdio.h> ! 23: ! 24: #include "config.h" ! 25: #include "rtl.h" ! 26: #include "tree.h" ! 27: #include "flags.h" ! 28: #include "insn-config.h" ! 29: #include "insn-flags.h" ! 30: #include "expr.h" ! 31: #include "output.h" ! 32: #include "integrate.h" ! 33: #include "real.h" ! 34: #include "function.h" ! 35: ! 36: #include "obstack.h" ! 37: #define obstack_chunk_alloc xmalloc ! 38: #define obstack_chunk_free free ! 39: extern int xmalloc (); ! 40: extern void free (); ! 41: ! 42: extern struct obstack *function_maybepermanent_obstack; ! 43: ! 44: extern tree pushdecl (); ! 45: extern tree poplevel (); ! 46: ! 47: /* Similar, but round to the next highest integer that meets the ! 48: alignment. */ ! 49: #define CEIL_ROUND(VALUE,ALIGN) (((VALUE) + (ALIGN) - 1) & ~((ALIGN)- 1)) ! 50: ! 51: /* Default max number of insns a function can have and still be inline. ! 52: This is overridden on RISC machines. */ ! 53: #ifndef INTEGRATE_THRESHOLD ! 54: #define INTEGRATE_THRESHOLD(DECL) \ ! 55: (8 * (8 + list_length (DECL_ARGUMENTS (DECL)))) ! 56: #endif ! 57: ! 58: /* Save any constant pool constants in an insn. */ ! 59: static void save_constants (); ! 60: ! 61: /* Note when parameter registers are the destination of a SET. */ ! 62: static void note_modified_parmregs (); ! 63: ! 64: /* Copy an rtx for save_for_inline_copying. */ ! 65: static rtx copy_for_inline (); ! 66: ! 67: /* Make copies of MEMs in DECL_RTLs. */ ! 68: static void copy_decl_rtls (); ! 69: ! 70: static tree copy_decl_tree (); ! 71: ! 72: /* Return the constant equivalent of a given rtx, or 0 if none. */ ! 73: static rtx const_equiv (); ! 74: ! 75: static void integrate_parm_decls (); ! 76: static void integrate_decl_tree (); ! 77: ! 78: static void subst_constants (); ! 79: static rtx fold_out_const_cc0 (); ! 80: ! 81: /* Zero if the current function (whose FUNCTION_DECL is FNDECL) ! 82: is safe and reasonable to integrate into other functions. ! 83: Nonzero means value is a warning message with a single %s ! 84: for the function's name. */ ! 85: ! 86: char * ! 87: function_cannot_inline_p (fndecl) ! 88: register tree fndecl; ! 89: { ! 90: register rtx insn; ! 91: tree last = tree_last (TYPE_ARG_TYPES (TREE_TYPE (fndecl))); ! 92: int max_insns = INTEGRATE_THRESHOLD (fndecl); ! 93: register int ninsns = 0; ! 94: register tree parms; ! 95: ! 96: /* No inlines with varargs. `grokdeclarator' gives a warning ! 97: message about that if `inline' is specified. This code ! 98: it put in to catch the volunteers. */ ! 99: if ((last && TREE_VALUE (last) != void_type_node) ! 100: || (DECL_ARGUMENTS (fndecl) && DECL_NAME (DECL_ARGUMENTS (fndecl)) ! 101: && ! strcmp (IDENTIFIER_POINTER (DECL_NAME (DECL_ARGUMENTS (fndecl))), ! 102: "__builtin_va_alist"))) ! 103: return "varargs function cannot be inline"; ! 104: ! 105: if (current_function_calls_alloca) ! 106: return "function using alloca cannot be inline"; ! 107: ! 108: if (current_function_contains_functions) ! 109: return "function with nested functions cannot be inline"; ! 110: ! 111: /* This restriction may be eliminated sometime soon. But for now, don't ! 112: worry about remapping the static chain. */ ! 113: if (current_function_needs_context) ! 114: return "nested function cannot be inline"; ! 115: ! 116: /* If its not even close, don't even look. */ ! 117: if (!TREE_INLINE (fndecl) && get_max_uid () > 3 * max_insns) ! 118: return "function too large to be inline"; ! 119: ! 120: #if 0 ! 121: /* Large stacks are OK now that inlined functions can share them. */ ! 122: /* Don't inline functions with large stack usage, ! 123: since they can make other recursive functions burn up stack. */ ! 124: if (!TREE_INLINE (fndecl) && get_frame_size () > 100) ! 125: return "function stack frame for inlining"; ! 126: #endif ! 127: ! 128: #if 0 ! 129: /* Don't inline functions which do not specify a function prototype and ! 130: have BLKmode argument or take the address of a parameter. */ ! 131: for (parms = DECL_ARGUMENTS (fndecl); parms; parms = TREE_CHAIN (parms)) ! 132: { ! 133: if (TYPE_MODE (TREE_TYPE (parms)) == BLKmode) ! 134: TREE_ADDRESSABLE (parms) = 1; ! 135: if (last == NULL_TREE && TREE_ADDRESSABLE (parms)) ! 136: return "no prototype, and parameter address used; cannot be inline"; ! 137: } ! 138: #endif ! 139: ! 140: /* We can't inline functions that return structures ! 141: the old-fashioned PCC way, copying into a static block. */ ! 142: if (current_function_returns_pcc_struct) ! 143: return "inline functions not supported for this return value type"; ! 144: ! 145: /* We can't inline functions that return structures of varying size. */ ! 146: if (int_size_in_bytes (TREE_TYPE (TREE_TYPE (fndecl))) < 0) ! 147: return "function with varying-size return value cannot be inline"; ! 148: ! 149: /* Cannot inline a function with a varying size argument. */ ! 150: for (parms = DECL_ARGUMENTS (fndecl); parms; parms = TREE_CHAIN (parms)) ! 151: if (int_size_in_bytes (TREE_TYPE (parms)) < 0) ! 152: return "function with varying-size parameter cannot be inline"; ! 153: ! 154: if (!TREE_INLINE (fndecl) && get_max_uid () > max_insns) ! 155: { ! 156: for (ninsns = 0, insn = get_first_nonparm_insn (); insn && ninsns < max_insns; ! 157: insn = NEXT_INSN (insn)) ! 158: { ! 159: if (GET_RTX_CLASS (GET_CODE (insn)) == 'i') ! 160: ninsns++; ! 161: } ! 162: ! 163: if (ninsns >= max_insns) ! 164: return "function too large to be inline"; ! 165: } ! 166: ! 167: return 0; ! 168: } ! 169: ! 170: /* Variables used within save_for_inline. */ ! 171: ! 172: /* Mapping from old pseudo-register to new pseudo-registers. ! 173: The first element of this map is reg_map[FIRST_PSEUDO_REGISTER]. ! 174: It is allocated in `save_for_inline' and `expand_inline_function', ! 175: and deallocated on exit from each of those routines. */ ! 176: static rtx *reg_map; ! 177: ! 178: /* Mapping from old code-labels to new code-labels. ! 179: The first element of this map is label_map[min_labelno]. ! 180: It is allocated in `save_for_inline' and `expand_inline_function', ! 181: and deallocated on exit from each of those routines. */ ! 182: static rtx *label_map; ! 183: ! 184: /* Mapping from old insn uid's to copied insns. ! 185: It is allocated in `save_for_inline' and `expand_inline_function', ! 186: and deallocated on exit from each of those routines. */ ! 187: static rtx *insn_map; ! 188: ! 189: /* Map pseudo reg number into the PARM_DECL for the parm living in the reg. ! 190: Zero for a reg that isn't a parm's home. ! 191: Only reg numbers less than max_parm_reg are mapped here. */ ! 192: static tree *parmdecl_map; ! 193: ! 194: /* Keep track of first pseudo-register beyond those that are parms. */ ! 195: static int max_parm_reg; ! 196: ! 197: /* When an insn is being copied by copy_for_inline, ! 198: this is nonzero if we have copied an ASM_OPERANDS. ! 199: In that case, it is the original input-operand vector. */ ! 200: static rtvec orig_asm_operands_vector; ! 201: ! 202: /* When an insn is being copied by copy_for_inline, ! 203: this is nonzero if we have copied an ASM_OPERANDS. ! 204: In that case, it is the copied input-operand vector. */ ! 205: static rtvec copy_asm_operands_vector; ! 206: ! 207: /* Likewise, this is the copied constraints vector. */ ! 208: static rtvec copy_asm_constraints_vector; ! 209: ! 210: /* In save_for_inline, nonzero if past the parm-initialization insns. */ ! 211: static int in_nonparm_insns; ! 212: ! 213: /* Subroutine for `save_for_inline{copying,nocopy}'. Performs initialization ! 214: needed to save FNDECL's insns and info for future inline expansion. */ ! 215: ! 216: static rtx ! 217: initialize_for_inline (fndecl, min_labelno, max_labelno, max_reg, copy) ! 218: tree fndecl; ! 219: int min_labelno; ! 220: int max_labelno; ! 221: int max_reg; ! 222: int copy; ! 223: { ! 224: int function_flags, i; ! 225: rtvec arg_vector; ! 226: tree parms; ! 227: ! 228: /* Compute the values of any flags we must restore when inlining this. */ ! 229: ! 230: function_flags ! 231: = (current_function_calls_alloca * FUNCTION_FLAGS_CALLS_ALLOCA ! 232: + current_function_calls_setjmp * FUNCTION_FLAGS_CALLS_SETJMP ! 233: + current_function_calls_longjmp * FUNCTION_FLAGS_CALLS_LONGJMP ! 234: + current_function_returns_struct * FUNCTION_FLAGS_RETURNS_STRUCT ! 235: + current_function_returns_pcc_struct * FUNCTION_FLAGS_RETURNS_PCC_STRUCT ! 236: + current_function_needs_context * FUNCTION_FLAGS_NEEDS_CONTEXT ! 237: + current_function_has_nonlocal_label * FUNCTION_FLAGS_HAS_NONLOCAL_LABEL ! 238: + current_function_returns_pointer * FUNCTION_FLAGS_RETURNS_POINTER ! 239: + current_function_uses_const_pool * FUNCTION_FLAGS_USES_CONST_POOL ! 240: + current_function_uses_pic_offset_table * FUNCTION_FLAGS_USES_PIC_OFFSET_TABLE); ! 241: ! 242: /* Clear out PARMDECL_MAP. It was allocated in the caller's frame. */ ! 243: bzero (parmdecl_map, max_parm_reg * sizeof (tree)); ! 244: arg_vector = rtvec_alloc (list_length (DECL_ARGUMENTS (fndecl))); ! 245: ! 246: for (parms = DECL_ARGUMENTS (fndecl), i = 0; ! 247: parms; ! 248: parms = TREE_CHAIN (parms), i++) ! 249: { ! 250: rtx p = DECL_RTL (parms); ! 251: ! 252: if (GET_CODE (p) == MEM && copy) ! 253: /* Copy the rtl so that modifications of the address ! 254: later in compilation won't affect this arg_vector. ! 255: Virtual register instantiation can screw the address ! 256: of the rtl. */ ! 257: DECL_RTL (parms) = copy_rtx (p); ! 258: ! 259: RTVEC_ELT (arg_vector, i) = p; ! 260: ! 261: if (GET_CODE (p) == REG) ! 262: parmdecl_map[REGNO (p)] = parms; ! 263: TREE_READONLY (parms) = 1; ! 264: } ! 265: ! 266: /* Assume we start out in the insns that set up the parameters. */ ! 267: in_nonparm_insns = 0; ! 268: ! 269: /* The list of DECL_SAVED_INSNS, starts off with a header which ! 270: contains the following information: ! 271: ! 272: the first insn of the function (not including the insns that copy ! 273: parameters into registers). ! 274: the first parameter insn of the function, ! 275: the first label used by that function, ! 276: the last label used by that function, ! 277: the highest register number used for parameters, ! 278: the total number of registers used, ! 279: the size of the incoming stack area for parameters, ! 280: the number of bytes popped on return, ! 281: the stack slot list, ! 282: some flags that are used to restore compiler globals, ! 283: the value of current_function_outgoing_args_size, ! 284: the original argument vector, ! 285: and the original DECL_INITIAL. */ ! 286: ! 287: return gen_inline_header_rtx (NULL, NULL, min_labelno, max_labelno, ! 288: max_parm_reg, max_reg, ! 289: current_function_args_size, ! 290: current_function_pops_args, ! 291: stack_slot_list, function_flags, ! 292: current_function_outgoing_args_size, ! 293: arg_vector, (rtx) DECL_INITIAL (fndecl)); ! 294: } ! 295: ! 296: /* Subroutine for `save_for_inline{copying,nocopy}'. Finishes up the ! 297: things that must be done to make FNDECL expandable as an inline function. ! 298: HEAD contains the chain of insns to which FNDECL will expand. */ ! 299: ! 300: static void ! 301: finish_inline (fndecl, head) ! 302: tree fndecl; ! 303: rtx head; ! 304: { ! 305: NEXT_INSN (head) = get_first_nonparm_insn (); ! 306: FIRST_PARM_INSN (head) = get_insns (); ! 307: DECL_SAVED_INSNS (fndecl) = head; ! 308: DECL_FRAME_SIZE (fndecl) = get_frame_size (); ! 309: TREE_INLINE (fndecl) = 1; ! 310: } ! 311: ! 312: /* Make the insns and PARM_DECLs of the current function permanent ! 313: and record other information in DECL_SAVED_INSNS to allow inlining ! 314: of this function in subsequent calls. ! 315: ! 316: This function is called when we are going to immediately compile ! 317: the insns for FNDECL. The insns in maybepermanent_obstack cannot be ! 318: modified by the compilation process, so we copy all of them to ! 319: new storage and consider the new insns to be the insn chain to be ! 320: compiled. */ ! 321: ! 322: void ! 323: save_for_inline_copying (fndecl) ! 324: tree fndecl; ! 325: { ! 326: rtx first_insn, last_insn, insn; ! 327: rtx head, copy; ! 328: int max_labelno, min_labelno, i, len; ! 329: int max_reg; ! 330: int max_uid; ! 331: rtx first_nonparm_insn; ! 332: ! 333: /* Make and emit a return-label if we have not already done so. ! 334: Do this before recording the bounds on label numbers. */ ! 335: ! 336: if (return_label == 0) ! 337: { ! 338: return_label = gen_label_rtx (); ! 339: emit_label (return_label); ! 340: } ! 341: ! 342: /* Get some bounds on the labels and registers used. */ ! 343: ! 344: max_labelno = max_label_num (); ! 345: min_labelno = get_first_label_num (); ! 346: max_reg = max_reg_num (); ! 347: ! 348: /* Set up PARMDECL_MAP which maps pseudo-reg number to its PARM_DECL. ! 349: Later we set TREE_READONLY to 0 if the parm is modified inside the fn. ! 350: Also set up ARG_VECTOR, which holds the unmodified DECL_RTX values ! 351: for the parms, prior to elimination of virtual registers. ! 352: These values are needed for substituting parms properly. */ ! 353: ! 354: max_parm_reg = max_parm_reg_num (); ! 355: parmdecl_map = (tree *) alloca (max_parm_reg * sizeof (tree)); ! 356: ! 357: head = initialize_for_inline (fndecl, min_labelno, max_labelno, max_reg, 1); ! 358: ! 359: if (current_function_uses_const_pool) ! 360: { ! 361: /* Replace any constant pool references with the actual constant. We ! 362: will put the constants back in the copy made below. */ ! 363: for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) ! 364: if (GET_RTX_CLASS (GET_CODE (insn)) == 'i') ! 365: { ! 366: save_constants (&PATTERN (insn)); ! 367: if (REG_NOTES (insn)) ! 368: save_constants (®_NOTES (insn)); ! 369: } ! 370: ! 371: /* Clear out the constant pool so that we can recreate it with the ! 372: copied constants below. */ ! 373: init_const_rtx_hash_table (); ! 374: clear_const_double_mem (); ! 375: } ! 376: ! 377: max_uid = INSN_UID (head); ! 378: ! 379: /* We have now allocated all that needs to be allocated permanently ! 380: on the rtx obstack. Set our high-water mark, so that we ! 381: can free the rest of this when the time comes. */ ! 382: ! 383: preserve_data (); ! 384: ! 385: /* Copy the chain insns of this function. ! 386: Install the copied chain as the insns of this function, ! 387: for continued compilation; ! 388: the original chain is recorded as the DECL_SAVED_INSNS ! 389: for inlining future calls. */ ! 390: ! 391: /* If there are insns that copy parms from the stack into pseudo registers, ! 392: those insns are not copied. `expand_inline_function' must ! 393: emit the correct code to handle such things. */ ! 394: ! 395: insn = get_insns (); ! 396: if (GET_CODE (insn) != NOTE) ! 397: abort (); ! 398: first_insn = rtx_alloc (NOTE); ! 399: NOTE_SOURCE_FILE (first_insn) = NOTE_SOURCE_FILE (insn); ! 400: NOTE_LINE_NUMBER (first_insn) = NOTE_LINE_NUMBER (insn); ! 401: INSN_UID (first_insn) = INSN_UID (insn); ! 402: PREV_INSN (first_insn) = NULL; ! 403: NEXT_INSN (first_insn) = NULL; ! 404: last_insn = first_insn; ! 405: ! 406: /* Each pseudo-reg in the old insn chain must have a unique rtx in the copy. ! 407: Make these new rtx's now, and install them in regno_reg_rtx, so they ! 408: will be the official pseudo-reg rtx's for the rest of compilation. */ ! 409: ! 410: reg_map = (rtx *) alloca ((max_reg + 1) * sizeof (rtx)); ! 411: ! 412: len = sizeof (struct rtx_def) + (GET_RTX_LENGTH (REG) - 1) * sizeof (rtunion); ! 413: for (i = max_reg - 1; i > LAST_VIRTUAL_REGISTER; i--) ! 414: reg_map[i] = (rtx)obstack_copy (function_maybepermanent_obstack, ! 415: regno_reg_rtx[i], len); ! 416: ! 417: bcopy (reg_map + LAST_VIRTUAL_REGISTER + 1, ! 418: regno_reg_rtx + LAST_VIRTUAL_REGISTER + 1, ! 419: (max_reg - (LAST_VIRTUAL_REGISTER + 1)) * sizeof (rtx)); ! 420: ! 421: /* Likewise each label rtx must have a unique rtx as its copy. */ ! 422: ! 423: label_map = (rtx *)alloca ((max_labelno - min_labelno) * sizeof (rtx)); ! 424: label_map -= min_labelno; ! 425: ! 426: for (i = min_labelno; i < max_labelno; i++) ! 427: label_map[i] = gen_label_rtx (); ! 428: ! 429: /* Record the mapping of old insns to copied insns. */ ! 430: ! 431: insn_map = (rtx *) alloca (max_uid * sizeof (rtx)); ! 432: bzero (insn_map, max_uid * sizeof (rtx)); ! 433: ! 434: /* Get the insn which signals the end of parameter setup code. */ ! 435: first_nonparm_insn = get_first_nonparm_insn (); ! 436: ! 437: /* Copy any entries in regno_reg_rtx or DECL_RTLs that reference MEM ! 438: (the former occurs when a variable has its address taken) ! 439: since these may be shared and can be changed by virtual ! 440: register instantiation. DECL_RTL values for our arguments ! 441: have already been copied by initialize_for_inline. */ ! 442: for (i = LAST_VIRTUAL_REGISTER + 1; i < max_reg; i++) ! 443: if (GET_CODE (regno_reg_rtx[i]) == MEM) ! 444: XEXP (regno_reg_rtx[i], 0) ! 445: = copy_for_inline (XEXP (regno_reg_rtx[i], 0)); ! 446: ! 447: /* Copy the tree of subblocks of the function, and the decls in them. ! 448: We will use the copy for compiling this function, then restore the original ! 449: subblocks and decls for use when inlining this function. ! 450: ! 451: Several parts of the compiler modify BLOCK trees. In particular, ! 452: instantiate_virtual_regs will instantiate any virtual regs ! 453: mentioned in the DECL_RTLs of the decls, and loop ! 454: unrolling will replicate any BLOCK trees inside an unrolled loop. ! 455: ! 456: The modified subblocks or DECL_RTLs would be incorrect for the original rtl ! 457: which we will use for inlining. The rtl might even contain pseudoregs ! 458: whose space has been freed. */ ! 459: ! 460: DECL_INITIAL (fndecl) = copy_decl_tree (DECL_INITIAL (fndecl)); ! 461: ! 462: /* Now copy each DECL_RTL which is a MEM, ! 463: so it is safe to modify their addresses. */ ! 464: copy_decl_rtls (DECL_INITIAL (fndecl)); ! 465: ! 466: /* Now copy the chain of insns. Do this twice. The first copy the insn ! 467: itself and its body. The second time copy of REG_NOTES. This is because ! 468: a REG_NOTE may have a forward pointer to another insn. */ ! 469: ! 470: for (insn = NEXT_INSN (insn); insn; insn = NEXT_INSN (insn)) ! 471: { ! 472: orig_asm_operands_vector = 0; ! 473: ! 474: if (insn == first_nonparm_insn) ! 475: in_nonparm_insns = 1; ! 476: ! 477: switch (GET_CODE (insn)) ! 478: { ! 479: case NOTE: ! 480: /* No need to keep these. */ ! 481: if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED) ! 482: continue; ! 483: ! 484: copy = rtx_alloc (NOTE); ! 485: NOTE_SOURCE_FILE (copy) = NOTE_SOURCE_FILE (insn); ! 486: NOTE_LINE_NUMBER (copy) = NOTE_LINE_NUMBER (insn); ! 487: break; ! 488: ! 489: case INSN: ! 490: case CALL_INSN: ! 491: case JUMP_INSN: ! 492: copy = rtx_alloc (GET_CODE (insn)); ! 493: PATTERN (copy) = copy_for_inline (PATTERN (insn)); ! 494: INSN_CODE (copy) = -1; ! 495: LOG_LINKS (copy) = NULL; ! 496: RTX_INTEGRATED_P (copy) = RTX_INTEGRATED_P (insn); ! 497: break; ! 498: ! 499: case CODE_LABEL: ! 500: copy = label_map[CODE_LABEL_NUMBER (insn)]; ! 501: break; ! 502: ! 503: case BARRIER: ! 504: copy = rtx_alloc (BARRIER); ! 505: break; ! 506: ! 507: default: ! 508: abort (); ! 509: } ! 510: INSN_UID (copy) = INSN_UID (insn); ! 511: insn_map[INSN_UID (insn)] = copy; ! 512: NEXT_INSN (last_insn) = copy; ! 513: PREV_INSN (copy) = last_insn; ! 514: last_insn = copy; ! 515: } ! 516: ! 517: /* Now copy the REG_NOTES. */ ! 518: for (insn = NEXT_INSN (get_insns ()); insn; insn = NEXT_INSN (insn)) ! 519: if (GET_RTX_CLASS (GET_CODE (insn)) == 'i' ! 520: && insn_map[INSN_UID(insn)]) ! 521: REG_NOTES (insn_map[INSN_UID (insn)]) ! 522: = copy_for_inline (REG_NOTES (insn)); ! 523: ! 524: NEXT_INSN (last_insn) = NULL; ! 525: ! 526: finish_inline (fndecl, head); ! 527: ! 528: set_new_first_and_last_insn (first_insn, last_insn); ! 529: } ! 530: ! 531: /* Make a copy of the entire tree of blocks BLOCK, and return it. */ ! 532: ! 533: static tree ! 534: copy_decl_tree (block) ! 535: tree block; ! 536: { ! 537: tree t, vars, subblocks; ! 538: ! 539: vars = copy_list (BLOCK_VARS (block)); ! 540: subblocks = 0; ! 541: ! 542: /* Process all subblocks. */ ! 543: for (t = BLOCK_SUBBLOCKS (block); t; t = TREE_CHAIN (t)) ! 544: { ! 545: tree copy = copy_decl_tree (t); ! 546: TREE_CHAIN (copy) = subblocks; ! 547: subblocks = copy; ! 548: } ! 549: ! 550: t = copy_node (block); ! 551: BLOCK_VARS (t) = vars; ! 552: BLOCK_SUBBLOCKS (t) = nreverse (subblocks); ! 553: return t; ! 554: } ! 555: ! 556: /* Copy DECL_RTLs in all decls in the given BLOCK node. */ ! 557: ! 558: static void ! 559: copy_decl_rtls (block) ! 560: tree block; ! 561: { ! 562: tree t; ! 563: ! 564: for (t = BLOCK_VARS (block); t; t = TREE_CHAIN (t)) ! 565: if (DECL_RTL (t) && GET_CODE (DECL_RTL (t)) == MEM) ! 566: DECL_RTL (t) = copy_for_inline (DECL_RTL (t)); ! 567: ! 568: /* Process all subblocks. */ ! 569: for (t = BLOCK_SUBBLOCKS (block); t; t = TREE_CHAIN (t)) ! 570: copy_decl_rtls (t); ! 571: } ! 572: ! 573: /* Make the insns and PARM_DECLs of the current function permanent ! 574: and record other information in DECL_SAVED_INSNS to allow inlining ! 575: of this function in subsequent calls. ! 576: ! 577: This routine need not copy any insns because we are not going ! 578: to immediately compile the insns in the insn chain. There ! 579: are two cases when we would compile the insns for FNDECL: ! 580: (1) when FNDECL is expanded inline, and (2) when FNDECL needs to ! 581: be output at the end of other compilation, because somebody took ! 582: its address. In the first case, the insns of FNDECL are copied ! 583: as it is expanded inline, so FNDECL's saved insns are not ! 584: modified. In the second case, FNDECL is used for the last time, ! 585: so modifying the rtl is not a problem. ! 586: ! 587: ??? Actually, we do not verify that FNDECL is not inline expanded ! 588: by other functions which must also be written down at the end ! 589: of compilation. We could set flag_no_inline to nonzero when ! 590: the time comes to write down such functions. */ ! 591: ! 592: void ! 593: save_for_inline_nocopy (fndecl) ! 594: tree fndecl; ! 595: { ! 596: rtx insn; ! 597: rtx head, copy; ! 598: tree parms; ! 599: int max_labelno, min_labelno, i, len; ! 600: int max_reg; ! 601: int max_uid; ! 602: rtx first_nonparm_insn; ! 603: int function_flags; ! 604: ! 605: /* Set up PARMDECL_MAP which maps pseudo-reg number to its PARM_DECL. ! 606: Later we set TREE_READONLY to 0 if the parm is modified inside the fn. ! 607: Also set up ARG_VECTOR, which holds the unmodified DECL_RTX values ! 608: for the parms, prior to elimination of virtual registers. ! 609: These values are needed for substituting parms properly. */ ! 610: ! 611: max_parm_reg = max_parm_reg_num (); ! 612: parmdecl_map = (tree *) alloca (max_parm_reg * sizeof (tree)); ! 613: ! 614: /* Make and emit a return-label if we have not already done so. */ ! 615: ! 616: if (return_label == 0) ! 617: { ! 618: return_label = gen_label_rtx (); ! 619: emit_label (return_label); ! 620: } ! 621: ! 622: head = initialize_for_inline (fndecl, get_first_label_num (), ! 623: max_label_num (), max_reg_num (), 0); ! 624: ! 625: /* If there are insns that copy parms from the stack into pseudo registers, ! 626: those insns are not copied. `expand_inline_function' must ! 627: emit the correct code to handle such things. */ ! 628: ! 629: insn = get_insns (); ! 630: if (GET_CODE (insn) != NOTE) ! 631: abort (); ! 632: ! 633: /* Get the insn which signals the end of parameter setup code. */ ! 634: first_nonparm_insn = get_first_nonparm_insn (); ! 635: ! 636: /* Now just scan the chain of insns to see what happens to our ! 637: PARM_DECLs. If a PARM_DECL is used but never modified, we ! 638: can substitute its rtl directly when expanding inline (and ! 639: perform constant folding when its incoming value is constant). ! 640: Otherwise, we have to copy its value into a new register and track ! 641: the new register's life. */ ! 642: ! 643: for (insn = NEXT_INSN (insn); insn; insn = NEXT_INSN (insn)) ! 644: { ! 645: if (insn == first_nonparm_insn) ! 646: in_nonparm_insns = 1; ! 647: ! 648: if (GET_RTX_CLASS (GET_CODE (insn)) == 'i') ! 649: { ! 650: if (current_function_uses_const_pool) ! 651: { ! 652: /* Replace any constant pool references with the actual constant. ! 653: We will put the constant back if we need to write the ! 654: function out after all. */ ! 655: save_constants (&PATTERN (insn)); ! 656: if (REG_NOTES (insn)) ! 657: save_constants (®_NOTES (insn)); ! 658: } ! 659: ! 660: /* Record what interesting things happen to our parameters. */ ! 661: note_stores (PATTERN (insn), note_modified_parmregs); ! 662: } ! 663: } ! 664: ! 665: /* We have now allocated all that needs to be allocated permanently ! 666: on the rtx obstack. Set our high-water mark, so that we ! 667: can free the rest of this when the time comes. */ ! 668: ! 669: preserve_data (); ! 670: ! 671: finish_inline (fndecl, head); ! 672: } ! 673: ! 674: /* Given PX, a pointer into an insn, search for references to the constant ! 675: pool. Replace each with a CONST that has the mode of the original ! 676: constant, contains the constant, and has RTX_INTEGRATED_P set. ! 677: Similarly, constant pool addresses not enclosed in a MEM are replaced ! 678: with an ADDRESS rtx which also gives the constant, mode, and has ! 679: RTX_INTEGRATED_P set. */ ! 680: ! 681: static void ! 682: save_constants (px) ! 683: rtx *px; ! 684: { ! 685: rtx x; ! 686: int i, j; ! 687: ! 688: again: ! 689: x = *px; ! 690: ! 691: /* If this is a CONST_DOUBLE, don't try to fix things up in ! 692: CONST_DOUBLE_MEM, because this is an infinite recursion. */ ! 693: if (GET_CODE (x) == CONST_DOUBLE) ! 694: return; ! 695: else if (GET_CODE (x) == MEM && GET_CODE (XEXP (x, 0)) == SYMBOL_REF ! 696: && CONSTANT_POOL_ADDRESS_P (XEXP (x,0))) ! 697: { ! 698: enum machine_mode const_mode = get_pool_mode (XEXP (x, 0)); ! 699: rtx new = gen_rtx (CONST, const_mode, get_pool_constant (XEXP (x, 0))); ! 700: RTX_INTEGRATED_P (new) = 1; ! 701: ! 702: /* If the MEM was in a different mode than the constant (perhaps we ! 703: were only looking at the low-order part), surround it with a ! 704: SUBREG so we can save both modes. */ ! 705: ! 706: if (GET_MODE (x) != const_mode) ! 707: { ! 708: new = gen_rtx (SUBREG, GET_MODE (x), new, 0); ! 709: RTX_INTEGRATED_P (new) = 1; ! 710: } ! 711: ! 712: *px = new; ! 713: save_constants (&XEXP (*px, 0)); ! 714: } ! 715: else if (GET_CODE (x) == SYMBOL_REF ! 716: && CONSTANT_POOL_ADDRESS_P (x)) ! 717: { ! 718: *px = gen_rtx (ADDRESS, get_pool_mode (x), get_pool_constant (x)); ! 719: save_constants (&XEXP (*px, 0)); ! 720: RTX_INTEGRATED_P (*px) = 1; ! 721: } ! 722: ! 723: else ! 724: { ! 725: char *fmt = GET_RTX_FORMAT (GET_CODE (x)); ! 726: int len = GET_RTX_LENGTH (GET_CODE (x)); ! 727: ! 728: for (i = len-1; i >= 0; i--) ! 729: { ! 730: switch (fmt[i]) ! 731: { ! 732: case 'E': ! 733: for (j = 0; j < XVECLEN (x, i); j++) ! 734: save_constants (&XVECEXP (x, i, j)); ! 735: break; ! 736: ! 737: case 'e': ! 738: if (XEXP (x, i) == 0) ! 739: continue; ! 740: if (i == 0) ! 741: { ! 742: /* Hack tail-recursion here. */ ! 743: px = &XEXP (x, 0); ! 744: goto again; ! 745: } ! 746: save_constants (&XEXP (x, i)); ! 747: break; ! 748: } ! 749: } ! 750: } ! 751: } ! 752: ! 753: /* Note whether a parameter is modified or not. */ ! 754: ! 755: static void ! 756: note_modified_parmregs (reg, x) ! 757: rtx reg; ! 758: rtx x; ! 759: { ! 760: if (GET_CODE (reg) == REG && in_nonparm_insns ! 761: && REGNO (reg) < max_parm_reg ! 762: && REGNO (reg) >= FIRST_PSEUDO_REGISTER ! 763: && parmdecl_map[REGNO (reg)] != 0) ! 764: TREE_READONLY (parmdecl_map[REGNO (reg)]) = 0; ! 765: } ! 766: ! 767: /* Copy the rtx ORIG recursively, replacing pseudo-regs and labels ! 768: according to `reg_map' and `label_map'. The original rtl insns ! 769: will be saved for inlining; this is used to make a copy ! 770: which is used to finish compiling the inline function itself. ! 771: ! 772: If we find a "saved" constant pool entry, one which was replaced with ! 773: the value of the constant, convert it back to a constant pool entry. ! 774: Since the pool wasn't touched, this should simply restore the old ! 775: address. ! 776: ! 777: All other kinds of rtx are copied except those that can never be ! 778: changed during compilation. */ ! 779: ! 780: static rtx ! 781: copy_for_inline (orig) ! 782: rtx orig; ! 783: { ! 784: register rtx x = orig; ! 785: register int i; ! 786: register enum rtx_code code; ! 787: register char *format_ptr; ! 788: ! 789: if (x == 0) ! 790: return x; ! 791: ! 792: code = GET_CODE (x); ! 793: ! 794: /* These types may be freely shared. */ ! 795: ! 796: switch (code) ! 797: { ! 798: case QUEUED: ! 799: case CONST_INT: ! 800: case SYMBOL_REF: ! 801: case PC: ! 802: case CC0: ! 803: return x; ! 804: ! 805: case CONST_DOUBLE: ! 806: /* We have to make a new CONST_DOUBLE to ensure that we account for ! 807: it correctly. Using the old CONST_DOUBLE_MEM data is wrong. */ ! 808: if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT) ! 809: { ! 810: REAL_VALUE_TYPE d; ! 811: ! 812: REAL_VALUE_FROM_CONST_DOUBLE (d, x); ! 813: return immed_real_const_1 (d, GET_MODE (x)); ! 814: } ! 815: else ! 816: return immed_double_const (CONST_DOUBLE_LOW (x), CONST_DOUBLE_HIGH (x), ! 817: VOIDmode); ! 818: ! 819: case CONST: ! 820: /* Get constant pool entry for constant in the pool. */ ! 821: if (RTX_INTEGRATED_P (x)) ! 822: return validize_mem (force_const_mem (GET_MODE (x), ! 823: copy_for_inline (XEXP (x, 0)))); ! 824: break; ! 825: ! 826: case SUBREG: ! 827: /* Get constant pool entry, but access in different mode. */ ! 828: if (RTX_INTEGRATED_P (x)) ! 829: { ! 830: rtx new ! 831: = force_const_mem (GET_MODE (SUBREG_REG (x)), ! 832: copy_for_inline (XEXP (SUBREG_REG (x), 0))); ! 833: ! 834: PUT_MODE (new, GET_MODE (x)); ! 835: return validize_mem (new); ! 836: } ! 837: break; ! 838: ! 839: case ADDRESS: ! 840: /* If not special for constant pool error. Else get constant pool ! 841: address. */ ! 842: if (! RTX_INTEGRATED_P (x)) ! 843: abort (); ! 844: ! 845: return XEXP (force_const_mem (GET_MODE (x), ! 846: copy_for_inline (XEXP (x, 0))), 0); ! 847: ! 848: case ASM_OPERANDS: ! 849: /* If a single asm insn contains multiple output operands ! 850: then it contains multiple ASM_OPERANDS rtx's that share operand 3. ! 851: We must make sure that the copied insn continues to share it. */ ! 852: if (orig_asm_operands_vector == XVEC (orig, 3)) ! 853: { ! 854: x = rtx_alloc (ASM_OPERANDS); ! 855: XSTR (x, 0) = XSTR (orig, 0); ! 856: XSTR (x, 1) = XSTR (orig, 1); ! 857: XINT (x, 2) = XINT (orig, 2); ! 858: XVEC (x, 3) = copy_asm_operands_vector; ! 859: XVEC (x, 4) = copy_asm_constraints_vector; ! 860: XSTR (x, 5) = XSTR (orig, 5); ! 861: XINT (x, 6) = XINT (orig, 6); ! 862: return x; ! 863: } ! 864: break; ! 865: ! 866: case MEM: ! 867: /* A MEM is usually allowed to be shared if its address is constant ! 868: or is a constant plus one of the special registers. ! 869: ! 870: We do not allow sharing of addresses that are either a special ! 871: register or the sum of a constant and a special register because ! 872: it is possible for unshare_all_rtl to copy the address, into memory ! 873: that won't be saved. Although the MEM can safely be shared, and ! 874: won't be copied there, the address itself cannot be shared, and may ! 875: need to be copied. ! 876: ! 877: There are also two exceptions with constants: The first is if the ! 878: constant is a LABEL_REF or the sum of the LABEL_REF ! 879: and an integer. This case can happen if we have an inline ! 880: function that supplies a constant operand to the call of another ! 881: inline function that uses it in a switch statement. In this case, ! 882: we will be replacing the LABEL_REF, so we have to replace this MEM ! 883: as well. ! 884: ! 885: The second case is if we have a (const (plus (address ..) ...)). ! 886: In that case we need to put back the address of the constant pool ! 887: entry. */ ! 888: ! 889: if (CONSTANT_ADDRESS_P (XEXP (x, 0)) ! 890: && GET_CODE (XEXP (x, 0)) != LABEL_REF ! 891: && ! (GET_CODE (XEXP (x, 0)) == CONST ! 892: && (GET_CODE (XEXP (XEXP (x, 0), 0)) == PLUS ! 893: && ((GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) ! 894: == LABEL_REF) ! 895: || (GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) ! 896: == ADDRESS))))) ! 897: return x; ! 898: break; ! 899: ! 900: case LABEL_REF: ! 901: { ! 902: /* Must point to the new insn. */ ! 903: return gen_rtx (LABEL_REF, GET_MODE (orig), ! 904: label_map[CODE_LABEL_NUMBER (XEXP (orig, 0))]); ! 905: } ! 906: ! 907: case REG: ! 908: if (REGNO (x) > LAST_VIRTUAL_REGISTER) ! 909: return reg_map [REGNO (x)]; ! 910: else ! 911: return x; ! 912: ! 913: case SET: ! 914: /* If a parm that gets modified lives in a pseudo-reg, ! 915: clear its TREE_READONLY to prevent certain optimizations. */ ! 916: { ! 917: rtx dest = SET_DEST (x); ! 918: ! 919: while (GET_CODE (dest) == STRICT_LOW_PART ! 920: || GET_CODE (dest) == ZERO_EXTRACT ! 921: || GET_CODE (dest) == SUBREG) ! 922: dest = XEXP (dest, 0); ! 923: ! 924: if (GET_CODE (dest) == REG ! 925: && REGNO (dest) < max_parm_reg ! 926: && REGNO (dest) >= FIRST_PSEUDO_REGISTER ! 927: && parmdecl_map[REGNO (dest)] != 0 ! 928: /* The insn to load an arg pseudo from a stack slot ! 929: does not count as modifying it. */ ! 930: && in_nonparm_insns) ! 931: TREE_READONLY (parmdecl_map[REGNO (dest)]) = 0; ! 932: } ! 933: break; ! 934: ! 935: #if 0 /* This is a good idea, but here is the wrong place for it. */ ! 936: /* Arrange that CONST_INTs always appear as the second operand ! 937: if they appear, and that `frame_pointer_rtx' or `arg_pointer_rtx' ! 938: always appear as the first. */ ! 939: case PLUS: ! 940: if (GET_CODE (XEXP (x, 0)) == CONST_INT ! 941: || (XEXP (x, 1) == frame_pointer_rtx ! 942: || (ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM ! 943: && XEXP (x, 1) == arg_pointer_rtx))) ! 944: { ! 945: rtx t = XEXP (x, 0); ! 946: XEXP (x, 0) = XEXP (x, 1); ! 947: XEXP (x, 1) = t; ! 948: } ! 949: break; ! 950: #endif ! 951: } ! 952: ! 953: /* Replace this rtx with a copy of itself. */ ! 954: ! 955: x = rtx_alloc (code); ! 956: bcopy (orig, x, (sizeof (*x) - sizeof (x->fld) ! 957: + sizeof (x->fld[0]) * GET_RTX_LENGTH (code))); ! 958: ! 959: /* Now scan the subexpressions recursively. ! 960: We can store any replaced subexpressions directly into X ! 961: since we know X is not shared! Any vectors in X ! 962: must be copied if X was copied. */ ! 963: ! 964: format_ptr = GET_RTX_FORMAT (code); ! 965: ! 966: for (i = 0; i < GET_RTX_LENGTH (code); i++) ! 967: { ! 968: switch (*format_ptr++) ! 969: { ! 970: case 'e': ! 971: XEXP (x, i) = copy_for_inline (XEXP (x, i)); ! 972: break; ! 973: ! 974: case 'u': ! 975: /* Change any references to old-insns to point to the ! 976: corresponding copied insns. */ ! 977: XEXP (x, i) = insn_map[INSN_UID (XEXP (x, i))]; ! 978: break; ! 979: ! 980: case 'E': ! 981: if (XVEC (x, i) != NULL && XVECLEN (x, i) != 0) ! 982: { ! 983: register int j; ! 984: ! 985: XVEC (x, i) = gen_rtvec_v (XVECLEN (x, i), &XVECEXP (x, i, 0)); ! 986: for (j = 0; j < XVECLEN (x, i); j++) ! 987: XVECEXP (x, i, j) ! 988: = copy_for_inline (XVECEXP (x, i, j)); ! 989: } ! 990: break; ! 991: } ! 992: } ! 993: ! 994: if (code == ASM_OPERANDS && orig_asm_operands_vector == 0) ! 995: { ! 996: orig_asm_operands_vector = XVEC (orig, 3); ! 997: copy_asm_operands_vector = XVEC (x, 3); ! 998: copy_asm_constraints_vector = XVEC (x, 4); ! 999: } ! 1000: ! 1001: return x; ! 1002: } ! 1003: ! 1004: /* Unfortunately, we need a global copy of const_equiv map for communication ! 1005: with a function called from note_stores. Be *very* careful that this ! 1006: is used properly in the presence of recursion. */ ! 1007: ! 1008: rtx *global_const_equiv_map; ! 1009: ! 1010: #define FIXED_BASE_PLUS_P(X) \ ! 1011: (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == CONST_INT \ ! 1012: && GET_CODE (XEXP (X, 0)) == REG \ ! 1013: && REGNO (XEXP (X, 0)) >= FIRST_VIRTUAL_REGISTER \ ! 1014: && REGNO (XEXP (X, 0)) < LAST_VIRTUAL_REGISTER) ! 1015: ! 1016: /* Integrate the procedure defined by FNDECL. Note that this function ! 1017: may wind up calling itself. Since the static variables are not ! 1018: reentrant, we do not assign them until after the possibility ! 1019: or recursion is eliminated. ! 1020: ! 1021: If IGNORE is nonzero, do not produce a value. ! 1022: Otherwise store the value in TARGET if it is nonzero and that is convenient. ! 1023: ! 1024: Value is: ! 1025: (rtx)-1 if we could not substitute the function ! 1026: 0 if we substituted it and it does not produce a value ! 1027: else an rtx for where the value is stored. */ ! 1028: ! 1029: rtx ! 1030: expand_inline_function (fndecl, parms, target, ignore, type, structure_value_addr) ! 1031: tree fndecl, parms; ! 1032: rtx target; ! 1033: int ignore; ! 1034: tree type; ! 1035: rtx structure_value_addr; ! 1036: { ! 1037: tree formal, actual; ! 1038: rtx header = DECL_SAVED_INSNS (fndecl); ! 1039: rtx insns = FIRST_FUNCTION_INSN (header); ! 1040: rtx parm_insns = FIRST_PARM_INSN (header); ! 1041: tree *arg_trees; ! 1042: rtx *arg_vals; ! 1043: rtx insn; ! 1044: int max_regno; ! 1045: register int i; ! 1046: int min_labelno = FIRST_LABELNO (header); ! 1047: int max_labelno = LAST_LABELNO (header); ! 1048: int nargs; ! 1049: rtx local_return_label = 0; ! 1050: rtx loc; ! 1051: rtx temp; ! 1052: struct inline_remap *map; ! 1053: rtx cc0_insn = 0; ! 1054: rtvec arg_vector = ORIGINAL_ARG_VECTOR (header); ! 1055: ! 1056: /* Allow for equivalences of the pseudos we make for virtual fp and ap. */ ! 1057: max_regno = MAX_REGNUM (header) + 3; ! 1058: if (max_regno < FIRST_PSEUDO_REGISTER) ! 1059: abort (); ! 1060: ! 1061: nargs = list_length (DECL_ARGUMENTS (fndecl)); ! 1062: ! 1063: /* We expect PARMS to have the right length; don't crash if not. */ ! 1064: if (list_length (parms) != nargs) ! 1065: return (rtx)-1; ! 1066: /* Also check that the parms type match. Since the appropriate ! 1067: conversions or default promotions have already been applied, ! 1068: the machine modes should match exactly. */ ! 1069: for (formal = DECL_ARGUMENTS (fndecl), ! 1070: actual = parms; ! 1071: formal; ! 1072: formal = TREE_CHAIN (formal), ! 1073: actual = TREE_CHAIN (actual)) ! 1074: { ! 1075: tree arg = TREE_VALUE (actual); ! 1076: enum machine_mode mode = TYPE_MODE (DECL_ARG_TYPE (formal)); ! 1077: if (mode != TYPE_MODE (TREE_TYPE (arg))) ! 1078: return (rtx)-1; ! 1079: /* If they are block mode, the types should match exactly. ! 1080: They don't match exactly if TREE_TYPE (FORMAL) == ERROR_MARK_NODE, ! 1081: which could happen if the parameter has incomplete type. */ ! 1082: if (mode == BLKmode && TREE_TYPE (arg) != TREE_TYPE (formal)) ! 1083: return (rtx)-1; ! 1084: } ! 1085: ! 1086: /* Make a binding contour to keep inline cleanups called at ! 1087: outer function-scope level from looking like they are shadowing ! 1088: parameter declarations. */ ! 1089: pushlevel (0); ! 1090: ! 1091: /* Make a fresh binding contour that we can easily remove. */ ! 1092: pushlevel (0); ! 1093: expand_start_bindings (0); ! 1094: if (GET_CODE (parm_insns) == NOTE ! 1095: && NOTE_LINE_NUMBER (parm_insns) > 0) ! 1096: emit_note (NOTE_SOURCE_FILE (parm_insns), NOTE_LINE_NUMBER (parm_insns)); ! 1097: ! 1098: /* Expand the function arguments. Do this first so that any ! 1099: new registers get created before we allocate the maps. */ ! 1100: ! 1101: arg_vals = (rtx *) alloca (nargs * sizeof (rtx)); ! 1102: arg_trees = (tree *) alloca (nargs * sizeof (tree)); ! 1103: ! 1104: for (formal = DECL_ARGUMENTS (fndecl), actual = parms, i = 0; ! 1105: formal; ! 1106: formal = TREE_CHAIN (formal), actual = TREE_CHAIN (actual), i++) ! 1107: { ! 1108: /* Actual parameter, converted to the type of the argument within the ! 1109: function. */ ! 1110: tree arg = convert (TREE_TYPE (formal), TREE_VALUE (actual)); ! 1111: /* Mode of the variable used within the function. */ ! 1112: enum machine_mode mode = TYPE_MODE (TREE_TYPE (formal)); ! 1113: /* Where parameter is located in the function. */ ! 1114: rtx copy; ! 1115: ! 1116: emit_note (DECL_SOURCE_FILE (formal), DECL_SOURCE_LINE (formal)); ! 1117: ! 1118: arg_trees[i] = arg; ! 1119: loc = RTVEC_ELT (arg_vector, i); ! 1120: ! 1121: /* If this is an object passed by invisible reference, we copy the ! 1122: object into a stack slot and save its address. If this will go ! 1123: into memory, we do nothing now. Otherwise, we just expand the ! 1124: argument. */ ! 1125: if (GET_CODE (loc) == MEM && GET_CODE (XEXP (loc, 0)) == REG ! 1126: && REGNO (XEXP (loc, 0)) > LAST_VIRTUAL_REGISTER) ! 1127: { ! 1128: enum machine_mode mode = TYPE_MODE (TREE_TYPE (arg)); ! 1129: rtx stack_slot = assign_stack_temp (mode, int_size_in_bytes (TREE_TYPE (arg)), 1); ! 1130: ! 1131: store_expr (arg, stack_slot, 0); ! 1132: ! 1133: arg_vals[i] = XEXP (stack_slot, 0); ! 1134: } ! 1135: else if (GET_CODE (loc) != MEM) ! 1136: arg_vals[i] = expand_expr (arg, 0, mode, EXPAND_SUM); ! 1137: else ! 1138: arg_vals[i] = 0; ! 1139: ! 1140: if (arg_vals[i] != 0 ! 1141: && (! TREE_READONLY (formal) ! 1142: /* If the parameter is not read-only, copy our argument through ! 1143: a register. Also, we cannot use ARG_VALS[I] if it overlaps ! 1144: TARGET in any way. In the inline function, they will likely ! 1145: be two different pseudos, and `safe_from_p' will make all ! 1146: sorts of smart assumptions about their not conflicting. ! 1147: But if ARG_VALS[I] overlaps TARGET, these assumptions are ! 1148: wrong, so put ARG_VALS[I] into a fresh register. */ ! 1149: || (target != 0 ! 1150: && (GET_CODE (arg_vals[i]) == REG ! 1151: || GET_CODE (arg_vals[i]) == SUBREG ! 1152: || GET_CODE (arg_vals[i]) == MEM) ! 1153: && reg_overlap_mentioned_p (arg_vals[i], target)))) ! 1154: arg_vals[i] = copy_to_mode_reg (mode, arg_vals[i]); ! 1155: } ! 1156: ! 1157: /* Allocate the structures we use to remap things. */ ! 1158: ! 1159: map = (struct inline_remap *) alloca (sizeof (struct inline_remap)); ! 1160: map->fndecl = fndecl; ! 1161: ! 1162: map->reg_map = (rtx *) alloca (max_regno * sizeof (rtx)); ! 1163: bzero (map->reg_map, max_regno * sizeof (rtx)); ! 1164: ! 1165: map->label_map = (rtx *)alloca ((max_labelno - min_labelno) * sizeof (rtx)); ! 1166: map->label_map -= min_labelno; ! 1167: ! 1168: map->insn_map = (rtx *) alloca (INSN_UID (header) * sizeof (rtx)); ! 1169: bzero (map->insn_map, INSN_UID (header) * sizeof (rtx)); ! 1170: map->min_insnno = 0; ! 1171: map->max_insnno = INSN_UID (header); ! 1172: ! 1173: /* const_equiv_map maps pseudos in our routine to constants, so it needs to ! 1174: be large enough for all our pseudos. This is the number we are currently ! 1175: using plus the number in the called routine, plus 15 for each arg, ! 1176: five to compute the virtual frame pointer, and five for the return value. ! 1177: This should be enough for most cases. We do not reference entries ! 1178: outside the range of the map. ! 1179: ! 1180: ??? These numbers are quite arbitrary and were obtained by ! 1181: experimentation. At some point, we should try to allocate the ! 1182: table after all the parameters are set up so we an more accurately ! 1183: estimate the number of pseudos we will need. */ ! 1184: ! 1185: map->const_equiv_map_size ! 1186: = max_reg_num () + (max_regno - FIRST_PSEUDO_REGISTER) + 15 * nargs + 10; ! 1187: ! 1188: map->const_equiv_map ! 1189: = (rtx *)alloca (map->const_equiv_map_size * sizeof (rtx)); ! 1190: bzero (map->const_equiv_map, map->const_equiv_map_size * sizeof (rtx)); ! 1191: ! 1192: map->const_age_map ! 1193: = (unsigned *)alloca (map->const_equiv_map_size * sizeof (unsigned)); ! 1194: bzero (map->const_age_map, map->const_equiv_map_size * sizeof (unsigned)); ! 1195: map->const_age = 0; ! 1196: ! 1197: /* Record the current insn in case we have to set up pointers to frame ! 1198: and argument memory blocks. */ ! 1199: map->insns_at_start = get_last_insn (); ! 1200: ! 1201: /* Update the outgoing argument size to allow for those in the inlined ! 1202: function. */ ! 1203: if (OUTGOING_ARGS_SIZE (header) > current_function_outgoing_args_size) ! 1204: current_function_outgoing_args_size = OUTGOING_ARGS_SIZE (header); ! 1205: ! 1206: /* If the inline function needs to make PIC references, that means ! 1207: that this function's PIC offset table must be used. */ ! 1208: if (FUNCTION_FLAGS (header) & FUNCTION_FLAGS_USES_PIC_OFFSET_TABLE) ! 1209: current_function_uses_pic_offset_table = 1; ! 1210: ! 1211: /* Process each argument. For each, set up things so that the function's ! 1212: reference to the argument will refer to the argument being passed. ! 1213: We only replace REG with REG here. Any simplifications are done ! 1214: via const_equiv_map. ! 1215: ! 1216: We make two passes: In the first, we deal with parameters that will ! 1217: be placed into registers, since we need to ensure that the allocated ! 1218: register number fits in const_equiv_map. Then we store all non-register ! 1219: parameters into their memory location. */ ! 1220: ! 1221: for (i = 0; i < nargs; i++) ! 1222: { ! 1223: rtx copy = arg_vals[i]; ! 1224: ! 1225: loc = RTVEC_ELT (arg_vector, i); ! 1226: ! 1227: /* There are three cases, each handled separately. */ ! 1228: if (GET_CODE (loc) == MEM && GET_CODE (XEXP (loc, 0)) == REG ! 1229: && REGNO (XEXP (loc, 0)) > LAST_VIRTUAL_REGISTER) ! 1230: { ! 1231: /* This must be an object passed by invisible reference (it could ! 1232: also be a variable-sized object, but we forbid inlining functions ! 1233: with variable-sized arguments). COPY is the address of the ! 1234: actual value (this computation will cause it to be copied). We ! 1235: map that address for the register, noting the actual address as ! 1236: an equivalent in case it can be substituted into the insns. */ ! 1237: ! 1238: if (GET_CODE (copy) != REG) ! 1239: { ! 1240: temp = copy_addr_to_reg (copy); ! 1241: if (CONSTANT_P (copy) || FIXED_BASE_PLUS_P (copy)) ! 1242: { ! 1243: map->const_equiv_map[REGNO (temp)] = copy; ! 1244: map->const_age_map[REGNO (temp)] = CONST_AGE_PARM; ! 1245: } ! 1246: copy = temp; ! 1247: } ! 1248: map->reg_map[REGNO (XEXP (loc, 0))] = copy; ! 1249: } ! 1250: else if (GET_CODE (loc) == MEM) ! 1251: { ! 1252: /* This is the case of a parameter that lives in memory. ! 1253: It will live in the block we allocate in the called routine's ! 1254: frame that simulates the incoming argument area. Do nothing ! 1255: now; we will call store_expr later. */ ! 1256: ; ! 1257: } ! 1258: else if (GET_CODE (loc) == REG) ! 1259: { ! 1260: /* This is the good case where the parameter is in a register. ! 1261: If it is read-only and our argument is a constant, set up the ! 1262: constant equivalence. */ ! 1263: if (GET_CODE (copy) != REG && GET_CODE (copy) != SUBREG) ! 1264: { ! 1265: temp = copy_to_mode_reg (GET_MODE (loc), copy); ! 1266: if (CONSTANT_P (copy) || FIXED_BASE_PLUS_P (copy)) ! 1267: { ! 1268: map->const_equiv_map[REGNO (temp)] = copy; ! 1269: map->const_age_map[REGNO (temp)] = CONST_AGE_PARM; ! 1270: } ! 1271: copy = temp; ! 1272: } ! 1273: map->reg_map[REGNO (loc)] = copy; ! 1274: } ! 1275: else ! 1276: abort (); ! 1277: ! 1278: /* Free any temporaries we made setting up this parameter. */ ! 1279: free_temp_slots (); ! 1280: } ! 1281: ! 1282: /* Now do the parameters that will be placed in memory. */ ! 1283: ! 1284: for (formal = DECL_ARGUMENTS (fndecl), i = 0; ! 1285: formal; formal = TREE_CHAIN (formal), i++) ! 1286: { ! 1287: rtx copy = arg_vals[i]; ! 1288: ! 1289: loc = RTVEC_ELT (arg_vector, i); ! 1290: ! 1291: if (GET_CODE (loc) == MEM ! 1292: /* Exclude case handled above. */ ! 1293: && ! (GET_CODE (XEXP (loc, 0)) == REG ! 1294: && REGNO (XEXP (loc, 0)) > LAST_VIRTUAL_REGISTER)) ! 1295: { ! 1296: emit_note (DECL_SOURCE_FILE (formal), DECL_SOURCE_LINE (formal)); ! 1297: ! 1298: /* Compute the address in the area we reserved and store the ! 1299: value there. */ ! 1300: temp = copy_rtx_and_substitute (loc, map); ! 1301: subst_constants (&temp, 0, map); ! 1302: apply_change_group (); ! 1303: if (! memory_address_p (GET_MODE (temp), XEXP (temp, 0))) ! 1304: temp = change_address (temp, VOIDmode, XEXP (temp, 0)); ! 1305: store_expr (arg_trees[i], temp, 0); ! 1306: ! 1307: /* Free any temporaries we made setting up this parameter. */ ! 1308: free_temp_slots (); ! 1309: } ! 1310: } ! 1311: ! 1312: /* Deal with the places that the function puts its result. ! 1313: We are driven by what is placed into DECL_RESULT. ! 1314: ! 1315: Initially, we assume that we don't have anything special handling for ! 1316: REG_FUNCTION_RETURN_VALUE_P. */ ! 1317: ! 1318: map->inline_target = 0; ! 1319: loc = DECL_RTL (DECL_RESULT (fndecl)); ! 1320: if (TYPE_MODE (type) == VOIDmode) ! 1321: /* There is no return value to worry about. */ ! 1322: ; ! 1323: else if (GET_CODE (loc) == MEM) ! 1324: { ! 1325: if (! structure_value_addr || ! aggregate_value_p (DECL_RESULT (fndecl))) ! 1326: abort (); ! 1327: ! 1328: /* Pass the function the address in which to return a structure value. ! 1329: Note that a constructor can cause someone to call us with ! 1330: STRUCTURE_VALUE_ADDR, but the initialization takes place ! 1331: via the first parameter, rather than the struct return address. ! 1332: ! 1333: We have two cases: If the address is a simple register indirect, ! 1334: use the mapping mechanism to point that register to our structure ! 1335: return address. Otherwise, store the structure return value into ! 1336: the place that it will be referenced from. */ ! 1337: ! 1338: if (GET_CODE (XEXP (loc, 0)) == REG) ! 1339: { ! 1340: temp = force_reg (Pmode, structure_value_addr); ! 1341: map->reg_map[REGNO (XEXP (loc, 0))] = temp; ! 1342: if (CONSTANT_P (structure_value_addr) ! 1343: || (GET_CODE (structure_value_addr) == PLUS ! 1344: && XEXP (structure_value_addr, 0) == virtual_stack_vars_rtx ! 1345: && GET_CODE (XEXP (structure_value_addr, 1)) == CONST_INT)) ! 1346: { ! 1347: map->const_equiv_map[REGNO (temp)] = structure_value_addr; ! 1348: map->const_age_map[REGNO (temp)] = CONST_AGE_PARM; ! 1349: } ! 1350: } ! 1351: else ! 1352: { ! 1353: temp = copy_rtx_and_substitute (loc, map); ! 1354: subst_constants (&temp, 0, map); ! 1355: apply_change_group (); ! 1356: emit_move_insn (temp, structure_value_addr); ! 1357: } ! 1358: } ! 1359: else if (ignore) ! 1360: /* We will ignore the result value, so don't look at its structure. ! 1361: Note that preparations for an aggregate return value ! 1362: do need to be made (above) even if it will be ignored. */ ! 1363: ; ! 1364: else if (GET_CODE (loc) == REG) ! 1365: { ! 1366: /* The function returns an object in a register and we use the return ! 1367: value. Set up our target for remapping. */ ! 1368: ! 1369: /* Machine mode function was declared to return. */ ! 1370: enum machine_mode departing_mode = TYPE_MODE (type); ! 1371: /* (Possibly wider) machine mode it actually computes ! 1372: (for the sake of callers that fail to declare it right). */ ! 1373: enum machine_mode arriving_mode ! 1374: = TYPE_MODE (TREE_TYPE (DECL_RESULT (fndecl))); ! 1375: rtx reg_to_map; ! 1376: ! 1377: /* Don't use MEMs as direct targets because on some machines ! 1378: substituting a MEM for a REG makes invalid insns. ! 1379: Let the combiner substitute the MEM if that is valid. */ ! 1380: if (target == 0 || GET_CODE (target) != REG ! 1381: || GET_MODE (target) != departing_mode) ! 1382: target = gen_reg_rtx (departing_mode); ! 1383: ! 1384: /* If function's value was promoted before return, ! 1385: avoid machine mode mismatch when we substitute INLINE_TARGET. ! 1386: But TARGET is what we will return to the caller. */ ! 1387: if (arriving_mode != departing_mode) ! 1388: reg_to_map = gen_rtx (SUBREG, arriving_mode, target, 0); ! 1389: else ! 1390: reg_to_map = target; ! 1391: ! 1392: /* Usually, the result value is the machine's return register. ! 1393: Sometimes it may be a pseudo. Handle both cases. */ ! 1394: if (REG_FUNCTION_VALUE_P (loc)) ! 1395: map->inline_target = reg_to_map; ! 1396: else ! 1397: map->reg_map[REGNO (loc)] = reg_to_map; ! 1398: } ! 1399: ! 1400: /* Make new label equivalences for the labels in the called function. */ ! 1401: for (i = min_labelno; i < max_labelno; i++) ! 1402: map->label_map[i] = gen_label_rtx (); ! 1403: ! 1404: /* Perform postincrements before actually calling the function. */ ! 1405: emit_queue (); ! 1406: ! 1407: /* Clean up stack so that variables might have smaller offsets. */ ! 1408: do_pending_stack_adjust (); ! 1409: ! 1410: /* Save a copy of the location of const_equiv_map for mark_stores, called ! 1411: via note_stores. */ ! 1412: global_const_equiv_map = map->const_equiv_map; ! 1413: ! 1414: /* Now copy the insns one by one. Do this in two passes, first the insns and ! 1415: then their REG_NOTES, just like save_for_inline. */ ! 1416: ! 1417: /* This loop is very similar to the loop in copy_loop_body in unroll.c. */ ! 1418: ! 1419: for (insn = insns; insn; insn = NEXT_INSN (insn)) ! 1420: { ! 1421: rtx copy, pattern; ! 1422: ! 1423: map->orig_asm_operands_vector = 0; ! 1424: ! 1425: switch (GET_CODE (insn)) ! 1426: { ! 1427: case INSN: ! 1428: pattern = PATTERN (insn); ! 1429: copy = 0; ! 1430: if (GET_CODE (pattern) == USE ! 1431: && GET_CODE (XEXP (pattern, 0)) == REG ! 1432: && REG_FUNCTION_VALUE_P (XEXP (pattern, 0))) ! 1433: /* The (USE (REG n)) at return from the function should ! 1434: be ignored since we are changing (REG n) into ! 1435: inline_target. */ ! 1436: break; ! 1437: ! 1438: /* Ignore setting a function value that we don't want to use. */ ! 1439: if (map->inline_target == 0 ! 1440: && GET_CODE (pattern) == SET ! 1441: && GET_CODE (SET_DEST (pattern)) == REG ! 1442: && REG_FUNCTION_VALUE_P (SET_DEST (pattern))) ! 1443: break; ! 1444: ! 1445: copy = emit_insn (copy_rtx_and_substitute (pattern, map)); ! 1446: /* REG_NOTES will be copied later. */ ! 1447: ! 1448: #ifdef HAVE_cc0 ! 1449: /* If this insn is setting CC0, it may need to look at ! 1450: the insn that uses CC0 to see what type of insn it is. ! 1451: In that case, the call to recog via validate_change will ! 1452: fail. So don't substitute constants here. Instead, ! 1453: do it when we emit the following insn. ! 1454: ! 1455: For example, see the pyr.md file. That machine has signed and ! 1456: unsigned compares. The compare patterns must check the ! 1457: following branch insn to see which what kind of compare to ! 1458: emit. ! 1459: ! 1460: If the previous insn set CC0, substitute constants on it as ! 1461: well. */ ! 1462: if (sets_cc0_p (PATTERN (copy)) != 0) ! 1463: cc0_insn = copy; ! 1464: else ! 1465: { ! 1466: if (cc0_insn) ! 1467: try_constants (cc0_insn, map); ! 1468: cc0_insn = 0; ! 1469: try_constants (copy, map); ! 1470: } ! 1471: #else ! 1472: try_constants (copy, map); ! 1473: #endif ! 1474: break; ! 1475: ! 1476: case JUMP_INSN: ! 1477: if (GET_CODE (PATTERN (insn)) == RETURN) ! 1478: { ! 1479: if (local_return_label == 0) ! 1480: local_return_label = gen_label_rtx (); ! 1481: pattern = gen_jump (local_return_label); ! 1482: } ! 1483: else ! 1484: pattern = copy_rtx_and_substitute (PATTERN (insn), map); ! 1485: ! 1486: copy = emit_jump_insn (pattern); ! 1487: ! 1488: #ifdef HAVE_cc0 ! 1489: if (cc0_insn) ! 1490: try_constants (cc0_insn, map); ! 1491: cc0_insn = 0; ! 1492: #endif ! 1493: try_constants (copy, map); ! 1494: ! 1495: /* If this used to be a conditional jump insn but whose branch ! 1496: direction is now know, we must do something special. */ ! 1497: if (condjump_p (insn) && ! simplejump_p (insn) && map->last_pc_value) ! 1498: { ! 1499: #ifdef HAVE_cc0 ! 1500: /* The previous insn set cc0 for us. So delete it. */ ! 1501: delete_insn (PREV_INSN (copy)); ! 1502: #endif ! 1503: ! 1504: /* If this is now a no-op, delete it. */ ! 1505: if (map->last_pc_value == pc_rtx) ! 1506: { ! 1507: delete_insn (copy); ! 1508: copy = 0; ! 1509: } ! 1510: else ! 1511: /* Otherwise, this is unconditional jump so we must put a ! 1512: BARRIER after it. We could do some dead code elimination ! 1513: here, but jump.c will do it just as well. */ ! 1514: emit_barrier (); ! 1515: } ! 1516: break; ! 1517: ! 1518: case CALL_INSN: ! 1519: pattern = copy_rtx_and_substitute (PATTERN (insn), map); ! 1520: copy = emit_call_insn (pattern); ! 1521: ! 1522: #ifdef HAVE_cc0 ! 1523: if (cc0_insn) ! 1524: try_constants (cc0_insn, map); ! 1525: cc0_insn = 0; ! 1526: #endif ! 1527: try_constants (copy, map); ! 1528: ! 1529: /* Be lazy and assume CALL_INSNs clobber all hard registers. */ ! 1530: for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) ! 1531: map->const_equiv_map[i] = 0; ! 1532: break; ! 1533: ! 1534: case CODE_LABEL: ! 1535: copy = emit_label (map->label_map[CODE_LABEL_NUMBER (insn)]); ! 1536: map->const_age++; ! 1537: break; ! 1538: ! 1539: case BARRIER: ! 1540: copy = emit_barrier (); ! 1541: break; ! 1542: ! 1543: case NOTE: ! 1544: /* It is important to discard function-end and function-beg notes, ! 1545: so we have only one of each in the current function. ! 1546: Also, NOTE_INSN_DELETED notes aren't useful (save_for_inline ! 1547: deleted these in the copy used for continuing compilation, ! 1548: not the copy used for inlining). */ ! 1549: if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_END ! 1550: && NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_BEG ! 1551: && NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED) ! 1552: copy = emit_note (NOTE_SOURCE_FILE (insn), NOTE_LINE_NUMBER (insn)); ! 1553: else ! 1554: copy = 0; ! 1555: break; ! 1556: ! 1557: default: ! 1558: abort (); ! 1559: break; ! 1560: } ! 1561: ! 1562: if (copy) ! 1563: RTX_INTEGRATED_P (copy) = 1; ! 1564: ! 1565: map->insn_map[INSN_UID (insn)] = copy; ! 1566: } ! 1567: ! 1568: /* Now copy the REG_NOTES. */ ! 1569: for (insn = insns; insn; insn = NEXT_INSN (insn)) ! 1570: if (GET_RTX_CLASS (GET_CODE (insn)) == 'i' ! 1571: && map->insn_map[INSN_UID (insn)]) ! 1572: REG_NOTES (map->insn_map[INSN_UID (insn)]) ! 1573: = copy_rtx_and_substitute (REG_NOTES (insn), map); ! 1574: ! 1575: if (local_return_label) ! 1576: emit_label (local_return_label); ! 1577: ! 1578: /* Make copies of the decls of the symbols in the inline function, so that ! 1579: the copies of the variables get declared in the current function. Set ! 1580: up things so that lookup_static_chain knows that to interpret registers ! 1581: in SAVE_EXPRs for TYPE_SIZEs as local. */ ! 1582: ! 1583: inline_function_decl = fndecl; ! 1584: integrate_decl_tree ((tree) ORIGINAL_DECL_INITIAL (header), 0, map, 0); ! 1585: integrate_parm_decls (DECL_ARGUMENTS (fndecl), map, arg_vector); ! 1586: inline_function_decl = 0; ! 1587: ! 1588: /* End the scope containing the copied formal parameter variables. */ ! 1589: ! 1590: expand_end_bindings (getdecls (), 1, 1); ! 1591: poplevel (1, 1, 0); ! 1592: poplevel (0, 0, 0); ! 1593: emit_line_note (input_filename, lineno); ! 1594: ! 1595: if (structure_value_addr) ! 1596: return gen_rtx (MEM, TYPE_MODE (type), ! 1597: memory_address (TYPE_MODE (type), structure_value_addr)); ! 1598: return target; ! 1599: } ! 1600: ! 1601: /* Given a chain of PARM_DECLs, ARGS, copy each decl into a VAR_DECL, ! 1602: push all of those decls and give each one the corresponding home. */ ! 1603: ! 1604: static void ! 1605: integrate_parm_decls (args, map, arg_vector) ! 1606: tree args; ! 1607: struct inline_remap *map; ! 1608: rtvec arg_vector; ! 1609: { ! 1610: register tree tail; ! 1611: register int i; ! 1612: ! 1613: for (tail = args, i = 0; tail; tail = TREE_CHAIN (tail), i++) ! 1614: { ! 1615: register tree decl = build_decl (VAR_DECL, DECL_NAME (tail), ! 1616: TREE_TYPE (tail)); ! 1617: rtx new_decl_rtl ! 1618: = copy_rtx_and_substitute (RTVEC_ELT (arg_vector, i), map); ! 1619: ! 1620: /* These args would always appear unused, if not for this. */ ! 1621: TREE_USED (decl) = 1; ! 1622: /* Prevent warning for shadowing with these. */ ! 1623: DECL_FROM_INLINE (decl) = 1; ! 1624: pushdecl (decl); ! 1625: /* Fully instantiate the address with the equivalent form so that the ! 1626: debugging information contains the actual register, instead of the ! 1627: virtual register. Do this by not passing an insn to ! 1628: subst_constants. */ ! 1629: subst_constants (&new_decl_rtl, 0, map); ! 1630: apply_change_group (); ! 1631: DECL_RTL (decl) = new_decl_rtl; ! 1632: } ! 1633: } ! 1634: ! 1635: /* Given a BLOCK node LET, push decls and levels so as to construct in the ! 1636: current function a tree of contexts isomorphic to the one that is given. ! 1637: ! 1638: LEVEL indicates how far down into the BLOCK tree is the node we are ! 1639: currently traversing. It is always zero for the initial call. ! 1640: ! 1641: MAP, if nonzero, is a pointer to a inline_remap map which indicates how ! 1642: registers used in the DECL_RTL field should be remapped. If it is zero, ! 1643: no mapping is necessary. ! 1644: ! 1645: FUNCTIONBODY indicates whether the top level block tree corresponds to ! 1646: a function body. This is identical in meaning to the functionbody ! 1647: argument of poplevel. */ ! 1648: ! 1649: static void ! 1650: integrate_decl_tree (let, level, map, functionbody) ! 1651: tree let; ! 1652: int level; ! 1653: struct inline_remap *map; ! 1654: int functionbody; ! 1655: { ! 1656: tree t, node; ! 1657: ! 1658: pushlevel (0); ! 1659: ! 1660: for (t = BLOCK_VARS (let); t; t = TREE_CHAIN (t)) ! 1661: { ! 1662: tree d = build_decl (TREE_CODE (t), DECL_NAME (t), TREE_TYPE (t)); ! 1663: DECL_SOURCE_LINE (d) = DECL_SOURCE_LINE (t); ! 1664: DECL_SOURCE_FILE (d) = DECL_SOURCE_FILE (t); ! 1665: if (! functionbody && DECL_RTL (t) != 0) ! 1666: { ! 1667: DECL_RTL (d) = copy_rtx_and_substitute (DECL_RTL (t), map); ! 1668: /* Fully instantiate the address with the equivalent form so that the ! 1669: debugging information contains the actual register, instead of the ! 1670: virtual register. Do this by not passing an insn to ! 1671: subst_constants. */ ! 1672: subst_constants (&DECL_RTL (d), 0, map); ! 1673: apply_change_group (); ! 1674: } ! 1675: else if (DECL_RTL (t)) ! 1676: DECL_RTL (d) = copy_rtx (DECL_RTL (t)); ! 1677: TREE_EXTERNAL (d) = TREE_EXTERNAL (t); ! 1678: TREE_STATIC (d) = TREE_STATIC (t); ! 1679: TREE_PUBLIC (d) = TREE_PUBLIC (t); ! 1680: TREE_CONSTANT (d) = TREE_CONSTANT (t); ! 1681: TREE_ADDRESSABLE (d) = TREE_ADDRESSABLE (t); ! 1682: TREE_READONLY (d) = TREE_READONLY (t); ! 1683: TREE_SIDE_EFFECTS (d) = TREE_SIDE_EFFECTS (t); ! 1684: /* These args would always appear unused, if not for this. */ ! 1685: TREE_USED (d) = 1; ! 1686: /* Prevent warning for shadowing with these. */ ! 1687: DECL_FROM_INLINE (d) = 1; ! 1688: pushdecl (d); ! 1689: } ! 1690: ! 1691: for (t = BLOCK_SUBBLOCKS (let); t; t = TREE_CHAIN (t)) ! 1692: integrate_decl_tree (t, level + 1, map, functionbody); ! 1693: ! 1694: node = poplevel (level > 0, 0, level == 0 && functionbody); ! 1695: if (node) ! 1696: TREE_USED (node) = TREE_USED (let); ! 1697: } ! 1698: ! 1699: /* Create a new copy of an rtx. ! 1700: Recursively copies the operands of the rtx, ! 1701: except for those few rtx codes that are sharable. ! 1702: ! 1703: We always return an rtx that is similar to that incoming rtx, with the ! 1704: exception of possibly changing a REG to a SUBREG or vice versa. No ! 1705: rtl is ever emitted. ! 1706: ! 1707: Handle constants that need to be placed in the constant pool by ! 1708: calling `force_const_mem'. */ ! 1709: ! 1710: rtx ! 1711: copy_rtx_and_substitute (orig, map) ! 1712: register rtx orig; ! 1713: struct inline_remap *map; ! 1714: { ! 1715: register rtx copy, temp; ! 1716: register int i, j; ! 1717: register RTX_CODE code; ! 1718: register enum machine_mode mode; ! 1719: register char *format_ptr; ! 1720: int regno; ! 1721: ! 1722: if (orig == 0) ! 1723: return 0; ! 1724: ! 1725: code = GET_CODE (orig); ! 1726: mode = GET_MODE (orig); ! 1727: ! 1728: switch (code) ! 1729: { ! 1730: case REG: ! 1731: /* If the stack pointer register shows up, it must be part of ! 1732: stack-adjustments (*not* because we eliminated the frame pointer!). ! 1733: Small hard registers are returned as-is. Pseudo-registers ! 1734: go through their `reg_map'. */ ! 1735: regno = REGNO (orig); ! 1736: if (regno <= LAST_VIRTUAL_REGISTER) ! 1737: { ! 1738: /* Some hard registers are also mapped, ! 1739: but others are not translated. */ ! 1740: if (map->reg_map[regno] != 0) ! 1741: return map->reg_map[regno]; ! 1742: ! 1743: /* If this is the virtual frame pointer, make space in current ! 1744: function's stack frame for the stack frame of the inline function. ! 1745: ! 1746: Copy the address of this area into a pseudo. Map ! 1747: virtual_stack_vars_rtx to this pseudo and set up a constant ! 1748: equivalence for it to be the address. This will substitute the ! 1749: address into insns where it can be substituted and use the new ! 1750: pseudo where it can't. */ ! 1751: if (regno == VIRTUAL_STACK_VARS_REGNUM) ! 1752: { ! 1753: rtx loc, seq; ! 1754: int size = DECL_FRAME_SIZE (map->fndecl); ! 1755: int rounded; ! 1756: ! 1757: start_sequence (); ! 1758: loc = assign_stack_temp (BLKmode, size, 1); ! 1759: loc = XEXP (loc, 0); ! 1760: #ifdef FRAME_GROWS_DOWNWARD ! 1761: /* In this case, virtual_stack_vars_rtx points to one byte ! 1762: higher than the top of the frame area. So compute the offset ! 1763: to one byte higher than our substitute frame. ! 1764: Keep the fake frame pointer aligned like a real one. */ ! 1765: rounded = CEIL_ROUND (size, BIGGEST_ALIGNMENT / BITS_PER_UNIT); ! 1766: loc = plus_constant (loc, rounded); ! 1767: #endif ! 1768: map->reg_map[regno] = force_operand (loc, 0); ! 1769: map->const_equiv_map[regno] = loc; ! 1770: map->const_age_map[regno] = CONST_AGE_PARM; ! 1771: ! 1772: seq = gen_sequence (); ! 1773: end_sequence (); ! 1774: emit_insn_after (seq, map->insns_at_start); ! 1775: return map->reg_map[regno]; ! 1776: } ! 1777: else if (regno == VIRTUAL_INCOMING_ARGS_REGNUM) ! 1778: { ! 1779: /* Do the same for a block to contain any arguments referenced ! 1780: in memory. */ ! 1781: rtx loc, seq; ! 1782: int size = FUNCTION_ARGS_SIZE (DECL_SAVED_INSNS (map->fndecl)); ! 1783: ! 1784: start_sequence (); ! 1785: loc = assign_stack_temp (BLKmode, size, 1); ! 1786: loc = XEXP (loc, 0); ! 1787: map->reg_map[regno] = force_operand (loc, 0); ! 1788: map->const_equiv_map[regno] = loc; ! 1789: map->const_age_map[regno] = CONST_AGE_PARM; ! 1790: ! 1791: seq = gen_sequence (); ! 1792: end_sequence (); ! 1793: emit_insn_after (seq, map->insns_at_start); ! 1794: return map->reg_map[regno]; ! 1795: } ! 1796: else if (REG_FUNCTION_VALUE_P (orig)) ! 1797: { ! 1798: /* This is a reference to the function return value. If ! 1799: the function doesn't have a return value, error. If the ! 1800: mode doesn't agree, make a SUBREG. */ ! 1801: if (map->inline_target == 0) ! 1802: /* Must be unrolling loops or replicating code if we ! 1803: reach here, so return the register unchanged. */ ! 1804: return orig; ! 1805: else if (mode != GET_MODE (map->inline_target)) ! 1806: return gen_rtx (SUBREG, mode, map->inline_target, 0); ! 1807: else ! 1808: return map->inline_target; ! 1809: } ! 1810: return orig; ! 1811: } ! 1812: if (map->reg_map[regno] == NULL) ! 1813: { ! 1814: map->reg_map[regno] = gen_reg_rtx (mode); ! 1815: REG_USERVAR_P (map->reg_map[regno]) = REG_USERVAR_P (orig); ! 1816: REG_LOOP_TEST_P (map->reg_map[regno]) = REG_LOOP_TEST_P (orig); ! 1817: RTX_UNCHANGING_P (map->reg_map[regno]) = RTX_UNCHANGING_P (orig); ! 1818: /* A reg with REG_FUNCTION_VALUE_P true will never reach here. */ ! 1819: } ! 1820: return map->reg_map[regno]; ! 1821: ! 1822: case SUBREG: ! 1823: copy = copy_rtx_and_substitute (SUBREG_REG (orig), map); ! 1824: /* SUBREG is ordinary, but don't make nested SUBREGs. */ ! 1825: if (GET_CODE (copy) == SUBREG) ! 1826: return gen_rtx (SUBREG, GET_MODE (orig), SUBREG_REG (copy), ! 1827: SUBREG_WORD (orig) + SUBREG_WORD (copy)); ! 1828: else ! 1829: return gen_rtx (SUBREG, GET_MODE (orig), copy, ! 1830: SUBREG_WORD (orig)); ! 1831: ! 1832: case USE: ! 1833: case CLOBBER: ! 1834: /* USE and CLOBBER are ordinary, but we convert (use (subreg foo)) ! 1835: to (use foo). */ ! 1836: copy = copy_rtx_and_substitute (XEXP (orig, 0), map); ! 1837: if (GET_CODE (copy) == SUBREG) ! 1838: copy = SUBREG_REG (copy); ! 1839: return gen_rtx (code, VOIDmode, copy); ! 1840: ! 1841: case CODE_LABEL: ! 1842: LABEL_PRESERVE_P (map->label_map[CODE_LABEL_NUMBER (orig)]) ! 1843: = LABEL_PRESERVE_P (orig); ! 1844: return map->label_map[CODE_LABEL_NUMBER (orig)]; ! 1845: ! 1846: case LABEL_REF: ! 1847: copy = rtx_alloc (LABEL_REF); ! 1848: PUT_MODE (copy, mode); ! 1849: XEXP (copy, 0) = map->label_map[CODE_LABEL_NUMBER (XEXP (orig, 0))]; ! 1850: LABEL_OUTSIDE_LOOP_P (copy) = LABEL_OUTSIDE_LOOP_P (orig); ! 1851: return copy; ! 1852: ! 1853: case PC: ! 1854: case CC0: ! 1855: case CONST_INT: ! 1856: case SYMBOL_REF: ! 1857: return orig; ! 1858: ! 1859: case CONST_DOUBLE: ! 1860: /* We have to make a new copy of this CONST_DOUBLE because don't want ! 1861: to use the old value of CONST_DOUBLE_MEM. Also, this may be a ! 1862: duplicate of a CONST_DOUBLE we have already seen. */ ! 1863: if (GET_MODE_CLASS (GET_MODE (orig)) == MODE_FLOAT) ! 1864: { ! 1865: REAL_VALUE_TYPE d; ! 1866: ! 1867: REAL_VALUE_FROM_CONST_DOUBLE (d, orig); ! 1868: return immed_real_const_1 (d, GET_MODE (orig)); ! 1869: } ! 1870: else ! 1871: return immed_double_const (CONST_DOUBLE_LOW (orig), ! 1872: CONST_DOUBLE_HIGH (orig), VOIDmode); ! 1873: ! 1874: case CONST: ! 1875: /* Make new constant pool entry for a constant ! 1876: that was in the pool of the inline function. */ ! 1877: if (RTX_INTEGRATED_P (orig)) ! 1878: { ! 1879: /* If this was an address of a constant pool entry that itself ! 1880: had to be placed in the constant pool, it might not be a ! 1881: valid address. So the recursive call below might turn it ! 1882: into a register. In that case, it isn't a constant any ! 1883: more, so return it. This has the potential of changing a ! 1884: MEM into a REG, but we'll assume that it safe. */ ! 1885: temp = copy_rtx_and_substitute (XEXP (orig, 0), map); ! 1886: if (! CONSTANT_P (temp)) ! 1887: return temp; ! 1888: return validize_mem (force_const_mem (GET_MODE (orig), temp)); ! 1889: } ! 1890: break; ! 1891: ! 1892: case ADDRESS: ! 1893: /* If from constant pool address, make new constant pool entry and ! 1894: return its address. */ ! 1895: if (! RTX_INTEGRATED_P (orig)) ! 1896: abort (); ! 1897: ! 1898: temp = force_const_mem (GET_MODE (orig), ! 1899: copy_rtx_and_substitute (XEXP (orig, 0), map)); ! 1900: ! 1901: #if 0 ! 1902: /* Legitimizing the address here is incorrect. ! 1903: ! 1904: The only ADDRESS rtx's that can reach here are ones created by ! 1905: save_constants. Hence the operand of the ADDRESS is always legal ! 1906: in this position of the instruction, since the original rtx without ! 1907: the ADDRESS was legal. ! 1908: ! 1909: The reason we don't legitimize the address here is that on the ! 1910: Sparc, the caller may have a (high ...) surrounding this ADDRESS. ! 1911: This code forces the operand of the address to a register, which ! 1912: fails because we can not take the HIGH part of a register. ! 1913: ! 1914: Also, change_address may create new registers. These registers ! 1915: will not have valid reg_map entries. This can cause try_constants() ! 1916: to fail because assumes that all registers in the rtx have valid ! 1917: reg_map entries, and it may end up replacing one of these new ! 1918: registers with junk. */ ! 1919: ! 1920: if (! memory_address_p (GET_MODE (temp), XEXP (temp, 0))) ! 1921: temp = change_address (temp, GET_MODE (temp), XEXP (temp, 0)); ! 1922: #endif ! 1923: ! 1924: return XEXP (temp, 0); ! 1925: ! 1926: case ASM_OPERANDS: ! 1927: /* If a single asm insn contains multiple output operands ! 1928: then it contains multiple ASM_OPERANDS rtx's that share operand 3. ! 1929: We must make sure that the copied insn continues to share it. */ ! 1930: if (map->orig_asm_operands_vector == XVEC (orig, 3)) ! 1931: { ! 1932: copy = rtx_alloc (ASM_OPERANDS); ! 1933: XSTR (copy, 0) = XSTR (orig, 0); ! 1934: XSTR (copy, 1) = XSTR (orig, 1); ! 1935: XINT (copy, 2) = XINT (orig, 2); ! 1936: XVEC (copy, 3) = map->copy_asm_operands_vector; ! 1937: XVEC (copy, 4) = map->copy_asm_constraints_vector; ! 1938: XSTR (copy, 5) = XSTR (orig, 5); ! 1939: XINT (copy, 6) = XINT (orig, 6); ! 1940: return copy; ! 1941: } ! 1942: break; ! 1943: ! 1944: case CALL: ! 1945: /* This is given special treatment because the first ! 1946: operand of a CALL is a (MEM ...) which may get ! 1947: forced into a register for cse. This is undesirable ! 1948: if function-address cse isn't wanted or if we won't do cse. */ ! 1949: #ifndef NO_FUNCTION_CSE ! 1950: if (! (optimize && ! flag_no_function_cse)) ! 1951: #endif ! 1952: return gen_rtx (CALL, GET_MODE (orig), ! 1953: gen_rtx (MEM, GET_MODE (XEXP (orig, 0)), ! 1954: copy_rtx_and_substitute (XEXP (XEXP (orig, 0), 0), map)), ! 1955: copy_rtx_and_substitute (XEXP (orig, 1), map)); ! 1956: break; ! 1957: ! 1958: #if 0 ! 1959: /* Must be ifdefed out for loop unrolling to work. */ ! 1960: case RETURN: ! 1961: abort (); ! 1962: #endif ! 1963: ! 1964: case SET: ! 1965: /* If this is setting fp or ap, it means that we have a nonlocal goto. ! 1966: Don't alter that. ! 1967: If the nonlocal goto is into the current function, ! 1968: this will result in unnecessarily bad code, but should work. */ ! 1969: if (SET_DEST (orig) == virtual_stack_vars_rtx ! 1970: || SET_DEST (orig) == virtual_incoming_args_rtx) ! 1971: return gen_rtx (SET, VOIDmode, SET_DEST (orig), ! 1972: copy_rtx_and_substitute (SET_SRC (orig), map)); ! 1973: break; ! 1974: ! 1975: case MEM: ! 1976: copy = rtx_alloc (MEM); ! 1977: PUT_MODE (copy, mode); ! 1978: XEXP (copy, 0) = copy_rtx_and_substitute (XEXP (orig, 0), map); ! 1979: MEM_IN_STRUCT_P (copy) = MEM_IN_STRUCT_P (orig); ! 1980: MEM_VOLATILE_P (copy) = MEM_VOLATILE_P (orig); ! 1981: RTX_UNCHANGING_P (copy) = RTX_UNCHANGING_P (orig); ! 1982: return copy; ! 1983: } ! 1984: ! 1985: copy = rtx_alloc (code); ! 1986: PUT_MODE (copy, mode); ! 1987: copy->in_struct = orig->in_struct; ! 1988: copy->volatil = orig->volatil; ! 1989: copy->unchanging = orig->unchanging; ! 1990: ! 1991: format_ptr = GET_RTX_FORMAT (GET_CODE (copy)); ! 1992: ! 1993: for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++) ! 1994: { ! 1995: switch (*format_ptr++) ! 1996: { ! 1997: case '0': ! 1998: break; ! 1999: ! 2000: case 'e': ! 2001: XEXP (copy, i) = copy_rtx_and_substitute (XEXP (orig, i), map); ! 2002: break; ! 2003: ! 2004: case 'u': ! 2005: /* Change any references to old-insns to point to the ! 2006: corresponding copied insns. */ ! 2007: XEXP (copy, i) = map->insn_map[INSN_UID (XEXP (orig, i))]; ! 2008: break; ! 2009: ! 2010: case 'E': ! 2011: XVEC (copy, i) = XVEC (orig, i); ! 2012: if (XVEC (orig, i) != NULL && XVECLEN (orig, i) != 0) ! 2013: { ! 2014: XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i)); ! 2015: for (j = 0; j < XVECLEN (copy, i); j++) ! 2016: XVECEXP (copy, i, j) ! 2017: = copy_rtx_and_substitute (XVECEXP (orig, i, j), map); ! 2018: } ! 2019: break; ! 2020: ! 2021: case 'i': ! 2022: XINT (copy, i) = XINT (orig, i); ! 2023: break; ! 2024: ! 2025: case 's': ! 2026: XSTR (copy, i) = XSTR (orig, i); ! 2027: break; ! 2028: ! 2029: default: ! 2030: abort (); ! 2031: } ! 2032: } ! 2033: ! 2034: if (code == ASM_OPERANDS && map->orig_asm_operands_vector == 0) ! 2035: { ! 2036: map->orig_asm_operands_vector = XVEC (orig, 3); ! 2037: map->copy_asm_operands_vector = XVEC (copy, 3); ! 2038: map->copy_asm_constraints_vector = XVEC (copy, 4); ! 2039: } ! 2040: ! 2041: return copy; ! 2042: } ! 2043: ! 2044: /* Substitute known constant values into INSN, if that is valid. */ ! 2045: ! 2046: void ! 2047: try_constants (insn, map) ! 2048: rtx insn; ! 2049: struct inline_remap *map; ! 2050: { ! 2051: int i; ! 2052: ! 2053: map->num_sets = 0; ! 2054: subst_constants (&PATTERN (insn), insn, map); ! 2055: ! 2056: /* Apply the changes if they are valid; otherwise discard them. */ ! 2057: apply_change_group (); ! 2058: ! 2059: /* Show we don't know the value of anything stored or clobbered. */ ! 2060: note_stores (PATTERN (insn), mark_stores); ! 2061: map->last_pc_value = 0; ! 2062: #ifdef HAVE_cc0 ! 2063: map->last_cc0_value = 0; ! 2064: #endif ! 2065: ! 2066: /* Set up any constant equivalences made in this insn. */ ! 2067: for (i = 0; i < map->num_sets; i++) ! 2068: { ! 2069: if (GET_CODE (map->equiv_sets[i].dest) == REG) ! 2070: { ! 2071: int regno = REGNO (map->equiv_sets[i].dest); ! 2072: ! 2073: if (map->const_equiv_map[regno] == 0 ! 2074: /* Following clause is a hack to make case work where GNU C++ ! 2075: reassigns a variable to make cse work right. */ ! 2076: || ! rtx_equal_p (map->const_equiv_map[regno], ! 2077: map->equiv_sets[i].equiv)) ! 2078: { ! 2079: map->const_equiv_map[regno] = map->equiv_sets[i].equiv; ! 2080: map->const_age_map[regno] = map->const_age; ! 2081: } ! 2082: } ! 2083: else if (map->equiv_sets[i].dest == pc_rtx) ! 2084: map->last_pc_value = map->equiv_sets[i].equiv; ! 2085: #ifdef HAVE_cc0 ! 2086: else if (map->equiv_sets[i].dest == cc0_rtx) ! 2087: map->last_cc0_value = map->equiv_sets[i].equiv; ! 2088: #endif ! 2089: } ! 2090: } ! 2091: ! 2092: /* Substitute known constants for pseudo regs in the contents of LOC, ! 2093: which are part of INSN. ! 2094: If INSN is zero, the substition should always be done (this is used to ! 2095: update DECL_RTL). ! 2096: These changes are taken out by try_constants if the result is not valid. ! 2097: ! 2098: Note that we are more concerned with determining when the result of a SET ! 2099: is a constant, for further propagation, than actually inserting constants ! 2100: into insns; cse will do the latter task better. ! 2101: ! 2102: This function is also used to adjust address of items previously addressed ! 2103: via the virtual stack variable or virtual incoming arguments registers. */ ! 2104: ! 2105: static void ! 2106: subst_constants (loc, insn, map) ! 2107: rtx *loc; ! 2108: rtx insn; ! 2109: struct inline_remap *map; ! 2110: { ! 2111: rtx x = *loc; ! 2112: register int i; ! 2113: register enum rtx_code code; ! 2114: register char *format_ptr; ! 2115: int num_changes = num_validated_changes (); ! 2116: rtx new = 0; ! 2117: enum machine_mode op0_mode; ! 2118: ! 2119: code = GET_CODE (x); ! 2120: ! 2121: switch (code) ! 2122: { ! 2123: case PC: ! 2124: case CONST_INT: ! 2125: case CONST_DOUBLE: ! 2126: case SYMBOL_REF: ! 2127: case CONST: ! 2128: case LABEL_REF: ! 2129: case ADDRESS: ! 2130: return; ! 2131: ! 2132: #ifdef HAVE_cc0 ! 2133: case CC0: ! 2134: validate_change (insn, loc, map->last_cc0_value, 1); ! 2135: return; ! 2136: #endif ! 2137: ! 2138: case USE: ! 2139: case CLOBBER: ! 2140: /* The only thing we can do with a USE or CLOBBER is possibly do ! 2141: some substitutions in a MEM within it. */ ! 2142: if (GET_CODE (XEXP (x, 0)) == MEM) ! 2143: subst_constants (&XEXP (XEXP (x, 0), 0), insn, map); ! 2144: return; ! 2145: ! 2146: case REG: ! 2147: /* Substitute for parms and known constants. Don't replace ! 2148: hard regs used as user variables with constants. */ ! 2149: { ! 2150: int regno = REGNO (x); ! 2151: ! 2152: if (! (regno < FIRST_PSEUDO_REGISTER && REG_USERVAR_P (x)) ! 2153: && regno < map->const_equiv_map_size ! 2154: && map->const_equiv_map[regno] != 0 ! 2155: && map->const_age_map[regno] >= map->const_age) ! 2156: validate_change (insn, loc, map->const_equiv_map[regno], 1); ! 2157: return; ! 2158: } ! 2159: ! 2160: case SUBREG: ! 2161: /* SUBREG is ordinary, but don't make nested SUBREGs and try to simplify ! 2162: constants. */ ! 2163: { ! 2164: rtx inner = SUBREG_REG (x); ! 2165: rtx new = 0; ! 2166: ! 2167: /* We can't call subst_constants on &SUBREG_REG (x) because any ! 2168: constant or SUBREG wouldn't be valid inside our SUBEG. Instead, ! 2169: see what is inside, try to form the new SUBREG and see if that is ! 2170: valid. We handle two cases: extracting a full word in an ! 2171: integral mode and extracting the low part. */ ! 2172: subst_constants (&inner, 0, map); ! 2173: ! 2174: if (GET_MODE_CLASS (GET_MODE (x)) == MODE_INT ! 2175: && GET_MODE_SIZE (GET_MODE (x)) == UNITS_PER_WORD ! 2176: && GET_MODE (SUBREG_REG (x)) != VOIDmode) ! 2177: new = operand_subword (inner, SUBREG_WORD (x), 0, ! 2178: GET_MODE (SUBREG_REG (x))); ! 2179: ! 2180: if (new == 0 && subreg_lowpart_p (x)) ! 2181: new = gen_lowpart_common (GET_MODE (x), inner); ! 2182: ! 2183: if (new) ! 2184: validate_change (insn, loc, new, 1); ! 2185: ! 2186: return; ! 2187: } ! 2188: ! 2189: case MEM: ! 2190: subst_constants (&XEXP (x, 0), insn, map); ! 2191: ! 2192: /* If a memory address got spoiled, change it back. */ ! 2193: if (insn != 0 && num_validated_changes () != num_changes ! 2194: && !memory_address_p (GET_MODE (x), XEXP (x, 0))) ! 2195: cancel_changes (num_changes); ! 2196: return; ! 2197: ! 2198: case SET: ! 2199: { ! 2200: /* Substitute constants in our source, and in any arguments to a ! 2201: complex (e..g, ZERO_EXTRACT) destination, but not in the destination ! 2202: itself. */ ! 2203: rtx *dest_loc = &SET_DEST (x); ! 2204: rtx dest = *dest_loc; ! 2205: rtx src, tem; ! 2206: ! 2207: subst_constants (&SET_SRC (x), insn, map); ! 2208: src = SET_SRC (x); ! 2209: ! 2210: while (GET_CODE (*dest_loc) == ZERO_EXTRACT ! 2211: || GET_CODE (*dest_loc) == SIGN_EXTRACT ! 2212: || GET_CODE (*dest_loc) == SUBREG ! 2213: || GET_CODE (*dest_loc) == STRICT_LOW_PART) ! 2214: { ! 2215: if (GET_CODE (*dest_loc) == ZERO_EXTRACT) ! 2216: { ! 2217: subst_constants (&XEXP (*dest_loc, 1), insn, map); ! 2218: subst_constants (&XEXP (*dest_loc, 2), insn, map); ! 2219: } ! 2220: dest_loc = &XEXP (*dest_loc, 0); ! 2221: } ! 2222: ! 2223: /* Check for the case of DEST a SUBREG, both it and the underlying ! 2224: register are less than one word, and the SUBREG has the wider mode. ! 2225: In the case, we are really setting the underlying register to the ! 2226: source converted to the mode of DEST. So indicate that. */ ! 2227: if (GET_CODE (dest) == SUBREG ! 2228: && GET_MODE_SIZE (GET_MODE (dest)) <= UNITS_PER_WORD ! 2229: && GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest))) <= UNITS_PER_WORD ! 2230: && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest))) ! 2231: <= GET_MODE_SIZE (GET_MODE (dest))) ! 2232: && (tem = gen_lowpart_if_possible (GET_MODE (dest), src))) ! 2233: src = tem, dest = SUBREG_REG (dest); ! 2234: ! 2235: /* If storing a recognizable value save it for later recording. */ ! 2236: if ((map->num_sets < MAX_RECOG_OPERANDS) ! 2237: && (CONSTANT_P (src) ! 2238: || (GET_CODE (src) == PLUS ! 2239: && GET_CODE (XEXP (src, 0)) == REG ! 2240: && REGNO (XEXP (src, 0)) >= FIRST_VIRTUAL_REGISTER ! 2241: && REGNO (XEXP (src, 0)) <= LAST_VIRTUAL_REGISTER ! 2242: && CONSTANT_P (XEXP (src, 1))) ! 2243: || GET_CODE (src) == COMPARE ! 2244: #ifdef HAVE_cc0 ! 2245: || dest == cc0_rtx ! 2246: #endif ! 2247: || (dest == pc_rtx ! 2248: && (src == pc_rtx || GET_CODE (src) == RETURN ! 2249: || GET_CODE (src) == LABEL_REF)))) ! 2250: { ! 2251: /* Normally, this copy won't do anything. But, if SRC is a COMPARE ! 2252: it will cause us to save the COMPARE with any constants ! 2253: substituted, which is what we want for later. */ ! 2254: map->equiv_sets[map->num_sets].equiv = copy_rtx (src); ! 2255: map->equiv_sets[map->num_sets++].dest = dest; ! 2256: } ! 2257: ! 2258: return; ! 2259: } ! 2260: } ! 2261: ! 2262: format_ptr = GET_RTX_FORMAT (code); ! 2263: ! 2264: /* If the first operand is an expression, save its mode for later. */ ! 2265: if (*format_ptr == 'e') ! 2266: op0_mode = GET_MODE (XEXP (x, 0)); ! 2267: ! 2268: for (i = 0; i < GET_RTX_LENGTH (code); i++) ! 2269: { ! 2270: switch (*format_ptr++) ! 2271: { ! 2272: case '0': ! 2273: break; ! 2274: ! 2275: case 'e': ! 2276: if (XEXP (x, i)) ! 2277: subst_constants (&XEXP (x, i), insn, map); ! 2278: break; ! 2279: ! 2280: case 'u': ! 2281: case 'i': ! 2282: case 's': ! 2283: break; ! 2284: ! 2285: case 'E': ! 2286: if (XVEC (x, i) != NULL && XVECLEN (x, i) != 0) ! 2287: { ! 2288: int j; ! 2289: for (j = 0; j < XVECLEN (x, i); j++) ! 2290: subst_constants (&XVECEXP (x, i, j), insn, map); ! 2291: } ! 2292: break; ! 2293: ! 2294: default: ! 2295: abort (); ! 2296: } ! 2297: } ! 2298: ! 2299: /* If this is a commutative operation, move a constant to the second ! 2300: operand unless the second operand is already a CONST_INT. */ ! 2301: if ((GET_RTX_CLASS (code) == 'c' || code == NE || code == EQ) ! 2302: && CONSTANT_P (XEXP (x, 0)) && GET_CODE (XEXP (x, 1)) != CONST_INT) ! 2303: { ! 2304: rtx tem = XEXP (x, 0); ! 2305: validate_change (insn, &XEXP (x, 0), XEXP (x, 1), 1); ! 2306: validate_change (insn, &XEXP (x, 1), tem, 1); ! 2307: } ! 2308: ! 2309: /* Simplify the expression in case we put in some constants. */ ! 2310: switch (GET_RTX_CLASS (code)) ! 2311: { ! 2312: case '1': ! 2313: new = simplify_unary_operation (code, GET_MODE (x), ! 2314: XEXP (x, 0), op0_mode); ! 2315: break; ! 2316: ! 2317: case '<': ! 2318: { ! 2319: enum machine_mode op_mode = GET_MODE (XEXP (x, 0)); ! 2320: if (op_mode == VOIDmode) ! 2321: op_mode = GET_MODE (XEXP (x, 1)); ! 2322: new = simplify_relational_operation (code, op_mode, ! 2323: XEXP (x, 0), XEXP (x, 1)); ! 2324: break; ! 2325: } ! 2326: ! 2327: case '2': ! 2328: case 'c': ! 2329: new = simplify_binary_operation (code, GET_MODE (x), ! 2330: XEXP (x, 0), XEXP (x, 1)); ! 2331: break; ! 2332: ! 2333: case 'b': ! 2334: case '3': ! 2335: new = simplify_ternary_operation (code, GET_MODE (x), op0_mode, ! 2336: XEXP (x, 0), XEXP (x, 1), XEXP (x, 2)); ! 2337: break; ! 2338: } ! 2339: ! 2340: if (new) ! 2341: validate_change (insn, loc, new, 1); ! 2342: } ! 2343: ! 2344: /* Show that register modified no longer contain known constants. We are ! 2345: called from note_stores with parts of the new insn. */ ! 2346: ! 2347: void ! 2348: mark_stores (dest, x) ! 2349: rtx dest; ! 2350: rtx x; ! 2351: { ! 2352: if (GET_CODE (dest) == SUBREG) ! 2353: dest = SUBREG_REG (dest); ! 2354: ! 2355: if (GET_CODE (dest) == REG) ! 2356: global_const_equiv_map[REGNO (dest)] = 0; ! 2357: } ! 2358: ! 2359: /* If any CONST expressions with RTX_INTEGRATED_P are present in the rtx ! 2360: pointed to by PX, they represent constants in the constant pool. ! 2361: Replace these with a new memory reference obtained from force_const_mem. ! 2362: Similarly, ADDRESS expressions with RTX_INTEGRATED_P represent the ! 2363: address of a constant pool entry. Replace them with the address of ! 2364: a new constant pool entry obtained from force_const_mem. */ ! 2365: ! 2366: static void ! 2367: restore_constants (px) ! 2368: rtx *px; ! 2369: { ! 2370: rtx x = *px; ! 2371: int i, j; ! 2372: char *fmt; ! 2373: ! 2374: if (x == 0) ! 2375: return; ! 2376: ! 2377: if (GET_CODE (x) == CONST_DOUBLE) ! 2378: { ! 2379: /* We have to make a new CONST_DOUBLE to ensure that we account for ! 2380: it correctly. Using the old CONST_DOUBLE_MEM data is wrong. */ ! 2381: if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT) ! 2382: { ! 2383: REAL_VALUE_TYPE d; ! 2384: ! 2385: REAL_VALUE_FROM_CONST_DOUBLE (d, x); ! 2386: *px = immed_real_const_1 (d, GET_MODE (x)); ! 2387: } ! 2388: else ! 2389: *px = immed_double_const (CONST_DOUBLE_LOW (x), CONST_DOUBLE_HIGH (x), ! 2390: VOIDmode); ! 2391: } ! 2392: ! 2393: else if (RTX_INTEGRATED_P (x) && GET_CODE (x) == CONST) ! 2394: { ! 2395: restore_constants (&XEXP (x, 0)); ! 2396: *px = validize_mem (force_const_mem (GET_MODE (x), XEXP (x, 0))); ! 2397: } ! 2398: else if (RTX_INTEGRATED_P (x) && GET_CODE (x) == SUBREG) ! 2399: { ! 2400: /* This must be (subreg/i:M1 (const/i:M2 ...) 0). */ ! 2401: rtx new = XEXP (SUBREG_REG (x), 0); ! 2402: ! 2403: restore_constants (&new); ! 2404: new = force_const_mem (GET_MODE (SUBREG_REG (x)), new); ! 2405: PUT_MODE (new, GET_MODE (x)); ! 2406: *px = validize_mem (new); ! 2407: } ! 2408: else if (RTX_INTEGRATED_P (x) && GET_CODE (x) == ADDRESS) ! 2409: { ! 2410: restore_constants (&XEXP (x, 0)); ! 2411: *px = XEXP (force_const_mem (GET_MODE (x), XEXP (x, 0)), 0); ! 2412: } ! 2413: else ! 2414: { ! 2415: fmt = GET_RTX_FORMAT (GET_CODE (x)); ! 2416: for (i = 0; i < GET_RTX_LENGTH (GET_CODE (x)); i++) ! 2417: { ! 2418: switch (*fmt++) ! 2419: { ! 2420: case 'E': ! 2421: for (j = 0; j < XVECLEN (x, i); j++) ! 2422: restore_constants (&XVECEXP (x, i, j)); ! 2423: break; ! 2424: ! 2425: case 'e': ! 2426: restore_constants (&XEXP (x, i)); ! 2427: break; ! 2428: } ! 2429: } ! 2430: } ! 2431: } ! 2432: ! 2433: /* Output the assembly language code for the function FNDECL ! 2434: from its DECL_SAVED_INSNS. Used for inline functions that are output ! 2435: at end of compilation instead of where they came in the source. */ ! 2436: ! 2437: void ! 2438: output_inline_function (fndecl) ! 2439: tree fndecl; ! 2440: { ! 2441: rtx head = DECL_SAVED_INSNS (fndecl); ! 2442: rtx last; ! 2443: ! 2444: temporary_allocation (); ! 2445: ! 2446: current_function_decl = fndecl; ! 2447: ! 2448: /* This call is only used to initialize global variables. */ ! 2449: init_function_start (fndecl, "lossage", 1); ! 2450: ! 2451: /* Redo parameter determinations in case the FUNCTION_... ! 2452: macros took machine-specific actions that need to be redone. */ ! 2453: assign_parms (fndecl, 1); ! 2454: ! 2455: /* Set stack frame size. */ ! 2456: assign_stack_local (BLKmode, DECL_FRAME_SIZE (fndecl), 0); ! 2457: ! 2458: restore_reg_data (FIRST_PARM_INSN (head)); ! 2459: ! 2460: stack_slot_list = STACK_SLOT_LIST (head); ! 2461: ! 2462: if (FUNCTION_FLAGS (head) & FUNCTION_FLAGS_CALLS_ALLOCA) ! 2463: current_function_calls_alloca = 1; ! 2464: ! 2465: if (FUNCTION_FLAGS (head) & FUNCTION_FLAGS_CALLS_SETJMP) ! 2466: current_function_calls_setjmp = 1; ! 2467: ! 2468: if (FUNCTION_FLAGS (head) & FUNCTION_FLAGS_CALLS_LONGJMP) ! 2469: current_function_calls_longjmp = 1; ! 2470: ! 2471: if (FUNCTION_FLAGS (head) & FUNCTION_FLAGS_RETURNS_STRUCT) ! 2472: current_function_returns_struct = 1; ! 2473: ! 2474: if (FUNCTION_FLAGS (head) & FUNCTION_FLAGS_RETURNS_PCC_STRUCT) ! 2475: current_function_returns_pcc_struct = 1; ! 2476: ! 2477: if (FUNCTION_FLAGS (head) & FUNCTION_FLAGS_NEEDS_CONTEXT) ! 2478: current_function_needs_context = 1; ! 2479: ! 2480: if (FUNCTION_FLAGS (head) & FUNCTION_FLAGS_HAS_NONLOCAL_LABEL) ! 2481: current_function_has_nonlocal_label = 1; ! 2482: ! 2483: if (FUNCTION_FLAGS (head) & FUNCTION_FLAGS_RETURNS_POINTER) ! 2484: current_function_returns_pointer = 1; ! 2485: ! 2486: if (FUNCTION_FLAGS (head) & FUNCTION_FLAGS_USES_CONST_POOL) ! 2487: current_function_uses_const_pool = 1; ! 2488: ! 2489: if (FUNCTION_FLAGS (head) & FUNCTION_FLAGS_USES_PIC_OFFSET_TABLE) ! 2490: current_function_uses_pic_offset_table = 1; ! 2491: ! 2492: current_function_outgoing_args_size = OUTGOING_ARGS_SIZE (head); ! 2493: current_function_pops_args = POPS_ARGS (head); ! 2494: ! 2495: /* There is no need to output a return label again. */ ! 2496: return_label = 0; ! 2497: ! 2498: expand_function_end (DECL_SOURCE_FILE (fndecl), DECL_SOURCE_LINE (fndecl)); ! 2499: ! 2500: /* Find last insn and rebuild the constant pool. */ ! 2501: for (last = FIRST_PARM_INSN (head); ! 2502: NEXT_INSN (last); last = NEXT_INSN (last)) ! 2503: { ! 2504: if (GET_RTX_CLASS (GET_CODE (last)) == 'i') ! 2505: { ! 2506: restore_constants (&PATTERN (last)); ! 2507: restore_constants (®_NOTES (last)); ! 2508: } ! 2509: } ! 2510: ! 2511: set_new_first_and_last_insn (FIRST_PARM_INSN (head), last); ! 2512: set_new_first_and_last_label_num (FIRST_LABELNO (head), LAST_LABELNO (head)); ! 2513: ! 2514: /* Compile this function all the way down to assembly code. */ ! 2515: rest_of_compilation (fndecl); ! 2516: ! 2517: current_function_decl = 0; ! 2518: ! 2519: permanent_allocation (); ! 2520: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.