integrate.c
来自「GCC编译器源代码」· C语言 代码 · 共 1,907 行 · 第 1/5 页
C
1,907 行
/* Procedure integration for GNU CC. Copyright (C) 1988, 91, 93, 94, 95, 96, 1997 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 "config.h"#include <stdio.h>#include "rtl.h"#include "tree.h"#include "regs.h"#include "flags.h"#include "insn-config.h"#include "insn-flags.h"#include "expr.h"#include "output.h"#include "recog.h"#include "integrate.h"#include "real.h"#include "except.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 save_constants_in_decl_trees PROTO ((tree));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; rtx result; /* 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 /* 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"; /* This is a hack, until the inliner is taught about eh regions at the start of the function. */ for (insn = get_insns (); insn && ! (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG); insn = NEXT_INSN (insn)) { if (insn && GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG) return "function with complex parameters cannot be inline"; } /* We can't inline functions that return a PARALLEL rtx. */ result = DECL_RTL (DECL_RESULT (fndecl)); if (result && GET_CODE (result) == PARALLEL) return "inline functions not supported for this return value type"; 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. */extern int max_parm_reg;extern rtx *parm_reg_stack_loc;/* 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 we have (mem (addressof (mem ...))), use the inner MEM since otherwise the copy_rtx call below will not unshare the MEM since it shares ADDRESSOF. */ if (GET_CODE (p) == MEM && GET_CODE (XEXP (p, 0)) == ADDRESSOF && GET_CODE (XEXP (XEXP (p, 0), 0)) == MEM) p = XEXP (XEXP (p, 0), 0); 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, the labels that are forced to exist, some flags that are used to restore compiler globals, the value of current_function_outgoing_args_size, the original argument vector, the original DECL_INITIAL, and pointers to the table of pseudo regs, pointer flags, and alignment. */ 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), (rtvec) regno_reg_rtx, regno_pointer_flag, regno_pointer_align, (rtvec) parm_reg_stack_loc);}/* 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;{ FIRST_FUNCTION_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;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?