⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 integrate.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 5 页
字号:
/* Procedure integration for GNU CC.   Copyright (C) 1988, 1991 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, 675 Mass Ave, Cambridge, MA 02139, 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 "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))))#endif/* Save any constant pool constants in an insn.  */static void save_constants ();/* Note when parameter registers are the destination of a SET.  */static void note_modified_parmregs ();/* Copy an rtx for save_for_inline_copying.  */static rtx copy_for_inline ();/* Make copies of MEMs in DECL_RTLs.  */static void copy_decl_rtls ();static tree copy_decl_tree ();static tree copy_decl_list ();/* Return the constant equivalent of a given rtx, or 0 if none.  */static rtx const_equiv ();static void integrate_parm_decls ();static void integrate_decl_tree ();static void subst_constants ();static rtx fold_out_const_cc0 ();/* 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)      || (DECL_ARGUMENTS (fndecl) && DECL_NAME (DECL_ARGUMENTS (fndecl))	  && ! strcmp (IDENTIFIER_POINTER (DECL_NAME (DECL_ARGUMENTS (fndecl))),		       "__builtin_va_alist")))    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";  /* This restriction may be eliminated sometime soon.  But for now, don't     worry about remapping the static chain.  */  if (current_function_needs_context)    return "nested function 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 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.  */  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";  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";  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 (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;      /* 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, 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 ();  DECL_INLINE (fndecl) = 1;}/* 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.  */voidsave_for_inline_copying (fndecl)     tree fndecl;{  rtx first_insn, last_insn, insn;  rtx head, copy;  int max_labelno, min_labelno, i, len;  int max_reg;  int max_uid;  rtx first_nonparm_insn;  /* Make and emit a return-label if we have not already done so.      Do this before recording the bounds on label numbers. */  if (return_label == 0)    {      return_label = gen_label_rtx ();      emit_label (return_label);    }  /* Get some bounds on the labels and registers used.  */  max_labelno = max_label_num ();  min_labelno = get_first_label_num ();  max_reg = max_reg_num ();

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -