📄 integrate.c
字号:
/* Procedure integration for GNU CC. Copyright (C) 1988, 1991, 1993, 1994, 1995 Free Software Foundation, Inc. Contributed by Michael Tiemann (tiemann@cygnus.com)This file is part of GNU CC.GNU CC is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2, or (at your option)any later version.GNU CC is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU CC; see the file COPYING. If not, write tothe Free Software Foundation, 59 Temple Place - Suite 330,Boston, MA 02111-1307, USA. */#include <stdio.h>#include "config.h"#include "rtl.h"#include "tree.h"#include "flags.h"#include "insn-config.h"#include "insn-flags.h"#include "expr.h"#include "output.h"#include "integrate.h"#include "real.h"#include "function.h"#include "bytecode.h"#include "obstack.h"#define obstack_chunk_alloc xmalloc#define obstack_chunk_free freeextern struct obstack *function_maybepermanent_obstack;extern tree pushdecl ();extern tree poplevel ();/* Similar, but round to the next highest integer that meets the alignment. */#define CEIL_ROUND(VALUE,ALIGN) (((VALUE) + (ALIGN) - 1) & ~((ALIGN)- 1))/* Default max number of insns a function can have and still be inline. This is overridden on RISC machines. */#ifndef INTEGRATE_THRESHOLD#define INTEGRATE_THRESHOLD(DECL) \ (8 * (8 + list_length (DECL_ARGUMENTS (DECL))))#endifstatic rtx initialize_for_inline PROTO((tree, int, int, int, int));static void finish_inline PROTO((tree, rtx));static void adjust_copied_decl_tree PROTO((tree));static tree copy_decl_list PROTO((tree));static tree copy_decl_tree PROTO((tree));static void copy_decl_rtls PROTO((tree));static void save_constants PROTO((rtx *));static void note_modified_parmregs PROTO((rtx, rtx));static rtx copy_for_inline PROTO((rtx));static void integrate_parm_decls PROTO((tree, struct inline_remap *, rtvec));static void integrate_decl_tree PROTO((tree, int, struct inline_remap *));static void subst_constants PROTO((rtx *, rtx, struct inline_remap *));static void restore_constants PROTO((rtx *));static void set_block_origin_self PROTO((tree));static void set_decl_origin_self PROTO((tree));static void set_block_abstract_flags PROTO((tree, int));void set_decl_abstract_flags PROTO((tree, int));/* Zero if the current function (whose FUNCTION_DECL is FNDECL) is safe and reasonable to integrate into other functions. Nonzero means value is a warning message with a single %s for the function's name. */char *function_cannot_inline_p (fndecl) register tree fndecl;{ register rtx insn; tree last = tree_last (TYPE_ARG_TYPES (TREE_TYPE (fndecl))); int max_insns = INTEGRATE_THRESHOLD (fndecl); register int ninsns = 0; register tree parms; /* No inlines with varargs. `grokdeclarator' gives a warning message about that if `inline' is specified. This code it put in to catch the volunteers. */ if ((last && TREE_VALUE (last) != void_type_node) || current_function_varargs) return "varargs function cannot be inline"; if (current_function_calls_alloca) return "function using alloca cannot be inline"; if (current_function_contains_functions) return "function with nested functions cannot be inline"; /* If its not even close, don't even look. */ if (!DECL_INLINE (fndecl) && get_max_uid () > 3 * max_insns) return "function too large to be inline";#if 0 /* Large stacks are OK now that inlined functions can share them. */ /* Don't inline functions with large stack usage, since they can make other recursive functions burn up stack. */ if (!DECL_INLINE (fndecl) && get_frame_size () > 100) return "function stack frame for inlining";#endif#if 0 /* Don't inline functions which do not specify a function prototype and have BLKmode argument or take the address of a parameter. */ for (parms = DECL_ARGUMENTS (fndecl); parms; parms = TREE_CHAIN (parms)) { if (TYPE_MODE (TREE_TYPE (parms)) == BLKmode) TREE_ADDRESSABLE (parms) = 1; if (last == NULL_TREE && TREE_ADDRESSABLE (parms)) return "no prototype, and parameter address used; cannot be inline"; }#endif /* We can't inline functions that return structures the old-fashioned PCC way, copying into a static block. */ if (current_function_returns_pcc_struct) return "inline functions not supported for this return value type"; /* We can't inline functions that return BLKmode structures in registers. */ if (TYPE_MODE (TREE_TYPE (TREE_TYPE (fndecl))) == BLKmode && ! aggregate_value_p (TREE_TYPE (TREE_TYPE (fndecl)))) return "inline functions not supported for this return value type"; /* We can't inline functions that return structures of varying size. */ if (int_size_in_bytes (TREE_TYPE (TREE_TYPE (fndecl))) < 0) return "function with varying-size return value cannot be inline"; /* Cannot inline a function with a varying size argument or one that receives a transparent union. */ for (parms = DECL_ARGUMENTS (fndecl); parms; parms = TREE_CHAIN (parms)) { if (int_size_in_bytes (TREE_TYPE (parms)) < 0) return "function with varying-size parameter cannot be inline"; else if (TYPE_TRANSPARENT_UNION (TREE_TYPE (parms))) return "function with transparent unit parameter cannot be inline"; } if (!DECL_INLINE (fndecl) && get_max_uid () > max_insns) { for (ninsns = 0, insn = get_first_nonparm_insn (); insn && ninsns < max_insns; insn = NEXT_INSN (insn)) { if (GET_RTX_CLASS (GET_CODE (insn)) == 'i') ninsns++; } if (ninsns >= max_insns) return "function too large to be inline"; } /* We cannot inline this function if forced_labels is non-zero. This implies that a label in this function was used as an initializer. Because labels can not be duplicated, all labels in the function will be renamed when it is inlined. However, there is no way to find and fix all variables initialized with addresses of labels in this function, hence inlining is impossible. */ if (forced_labels) return "function with label addresses used in initializers cannot inline"; /* We cannot inline a nested function that jumps to a nonlocal label. */ if (current_function_has_nonlocal_goto) return "function with nonlocal goto cannot be inline"; return 0;}/* Variables used within save_for_inline. *//* Mapping from old pseudo-register to new pseudo-registers. The first element of this map is reg_map[FIRST_PSEUDO_REGISTER]. It is allocated in `save_for_inline' and `expand_inline_function', and deallocated on exit from each of those routines. */static rtx *reg_map;/* Mapping from old code-labels to new code-labels. The first element of this map is label_map[min_labelno]. It is allocated in `save_for_inline' and `expand_inline_function', and deallocated on exit from each of those routines. */static rtx *label_map;/* Mapping from old insn uid's to copied insns. It is allocated in `save_for_inline' and `expand_inline_function', and deallocated on exit from each of those routines. */static rtx *insn_map;/* Map pseudo reg number into the PARM_DECL for the parm living in the reg. Zero for a reg that isn't a parm's home. Only reg numbers less than max_parm_reg are mapped here. */static tree *parmdecl_map;/* Keep track of first pseudo-register beyond those that are parms. */static int max_parm_reg;/* When an insn is being copied by copy_for_inline, this is nonzero if we have copied an ASM_OPERANDS. In that case, it is the original input-operand vector. */static rtvec orig_asm_operands_vector;/* When an insn is being copied by copy_for_inline, this is nonzero if we have copied an ASM_OPERANDS. In that case, it is the copied input-operand vector. */static rtvec copy_asm_operands_vector;/* Likewise, this is the copied constraints vector. */static rtvec copy_asm_constraints_vector;/* In save_for_inline, nonzero if past the parm-initialization insns. */static int in_nonparm_insns;/* Subroutine for `save_for_inline{copying,nocopy}'. Performs initialization needed to save FNDECL's insns and info for future inline expansion. */ static rtxinitialize_for_inline (fndecl, min_labelno, max_labelno, max_reg, copy) tree fndecl; int min_labelno; int max_labelno; int max_reg; int copy;{ int function_flags, i; rtvec arg_vector; tree parms; /* Compute the values of any flags we must restore when inlining this. */ function_flags = (current_function_calls_alloca * FUNCTION_FLAGS_CALLS_ALLOCA + current_function_calls_setjmp * FUNCTION_FLAGS_CALLS_SETJMP + current_function_calls_longjmp * FUNCTION_FLAGS_CALLS_LONGJMP + current_function_returns_struct * FUNCTION_FLAGS_RETURNS_STRUCT + current_function_returns_pcc_struct * FUNCTION_FLAGS_RETURNS_PCC_STRUCT + current_function_needs_context * FUNCTION_FLAGS_NEEDS_CONTEXT + current_function_has_nonlocal_label * FUNCTION_FLAGS_HAS_NONLOCAL_LABEL + current_function_returns_pointer * FUNCTION_FLAGS_RETURNS_POINTER + current_function_uses_const_pool * FUNCTION_FLAGS_USES_CONST_POOL + current_function_uses_pic_offset_table * FUNCTION_FLAGS_USES_PIC_OFFSET_TABLE); /* Clear out PARMDECL_MAP. It was allocated in the caller's frame. */ bzero ((char *) parmdecl_map, max_parm_reg * sizeof (tree)); arg_vector = rtvec_alloc (list_length (DECL_ARGUMENTS (fndecl))); for (parms = DECL_ARGUMENTS (fndecl), i = 0; parms; parms = TREE_CHAIN (parms), i++) { rtx p = DECL_RTL (parms); if (GET_CODE (p) == MEM && copy) { /* Copy the rtl so that modifications of the addresses later in compilation won't affect this arg_vector. Virtual register instantiation can screw the address of the rtl. */ rtx new = copy_rtx (p); /* Don't leave the old copy anywhere in this decl. */ if (DECL_RTL (parms) == DECL_INCOMING_RTL (parms) || (GET_CODE (DECL_RTL (parms)) == MEM && GET_CODE (DECL_INCOMING_RTL (parms)) == MEM && (XEXP (DECL_RTL (parms), 0) == XEXP (DECL_INCOMING_RTL (parms), 0)))) DECL_INCOMING_RTL (parms) = new; DECL_RTL (parms) = new; } RTVEC_ELT (arg_vector, i) = p; if (GET_CODE (p) == REG) parmdecl_map[REGNO (p)] = parms; else if (GET_CODE (p) == CONCAT) { rtx preal = gen_realpart (GET_MODE (XEXP (p, 0)), p); rtx pimag = gen_imagpart (GET_MODE (preal), p); if (GET_CODE (preal) == REG) parmdecl_map[REGNO (preal)] = parms; if (GET_CODE (pimag) == REG) parmdecl_map[REGNO (pimag)] = parms; } /* This flag is cleared later if the function ever modifies the value of the parm. */ TREE_READONLY (parms) = 1; } /* Assume we start out in the insns that set up the parameters. */ in_nonparm_insns = 0; /* The list of DECL_SAVED_INSNS, starts off with a header which contains the following information: the first insn of the function (not including the insns that copy parameters into registers). the first parameter insn of the function, the first label used by that function, the last label used by that function, the highest register number used for parameters, the total number of registers used, the size of the incoming stack area for parameters, the number of bytes popped on return, the stack slot list, some flags that are used to restore compiler globals, the value of current_function_outgoing_args_size, the original argument vector, and the original DECL_INITIAL. */ return gen_inline_header_rtx (NULL_RTX, NULL_RTX, min_labelno, max_labelno, max_parm_reg, max_reg, current_function_args_size, current_function_pops_args, stack_slot_list, forced_labels, function_flags, current_function_outgoing_args_size, arg_vector, (rtx) DECL_INITIAL (fndecl));}/* Subroutine for `save_for_inline{copying,nocopy}'. Finishes up the things that must be done to make FNDECL expandable as an inline function. HEAD contains the chain of insns to which FNDECL will expand. */ static voidfinish_inline (fndecl, head) tree fndecl; rtx head;{ NEXT_INSN (head) = get_first_nonparm_insn (); FIRST_PARM_INSN (head) = get_insns (); DECL_SAVED_INSNS (fndecl) = head; DECL_FRAME_SIZE (fndecl) = get_frame_size ();}/* Adjust the BLOCK_END_NOTE pointers in a given copied DECL tree so that they all point to the new (copied) rtxs. */static voidadjust_copied_decl_tree (block) register tree block;{ register tree subblock; register rtx original_end; original_end = BLOCK_END_NOTE (block); if (original_end) { BLOCK_END_NOTE (block) = (rtx) NOTE_SOURCE_FILE (original_end); NOTE_SOURCE_FILE (original_end) = 0; } /* Process all subblocks. */ for (subblock = BLOCK_SUBBLOCKS (block); subblock; subblock = TREE_CHAIN (subblock)) adjust_copied_decl_tree (subblock);}/* Make the insns and PARM_DECLs of the current function permanent and record other information in DECL_SAVED_INSNS to allow inlining of this function in subsequent calls. This function is called when we are going to immediately compile the insns for FNDECL. The insns in maybepermanent_obstack cannot be modified by the compilation process, so we copy all of them to new storage and consider the new insns to be the insn chain to be compiled. Our caller (rest_of_compilation) saves the original DECL_INITIAL and DECL_ARGUMENTS; here we copy them. *//* ??? The nonlocal_label list should be adjusted also. However, since a function that contains a nested function never gets inlined currently, the nonlocal_label list will always be empty, so we don't worry about it for now. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -