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

📄 integrate.c

📁 这是完整的gcc源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* Procedure integration for GNU CC.   Copyright (C) 1988 Free Software Foundation, Inc.   Contributed by Michael Tiemann (tiemann@mcc.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 1, 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-flags.h"#include "expr.h"#include "obstack.h"#define	obstack_chunk_alloc	xmalloc#define	obstack_chunk_free	freeextern int xmalloc ();extern void free ();extern struct obstack permanent_obstack, maybepermanent_obstack;extern struct obstack *rtl_obstack, *saveable_obstack, *current_obstack;extern rtx stack_slot_list;#define MIN(x,y) ((x < y) ? x : y)extern tree pushdecl ();extern tree poplevel ();/* 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/* This is the target of the inline function being expanded,   or NULL if there is none.  */static rtx inline_target;/* We must take special care not to disrupt life too severely   when performing procedure integration.  One thing that that   involves is not creating illegitimate address which reload   cannot fix.  Since we don't know what the frame pointer is   not capable of (in a machine independent way), we create   a pseudo-frame pointer which will have to do for now.  */static rtx inline_fp_rtx;/* Convert old frame-pointer offsets to new.  Parameters which only   produce values (no addresses, and are never assigned), map directly   to the pseudo-reg of the incoming value.  Parameters that are   assigned to but do not have their address taken are given a fresh   pseudo-register.  Parameters that have their address take are   given a fresh stack-slot.  */static rtx *parm_map;/* This is used to prevent looking beyond parm_map.  */static int parm_map_size;/* ?? Should this be done here??  It is not right now.   Keep track of whether a given pseudo-register is the sum   of the frame pointer and a const_int (or zero).  */static char *fp_addr_p;/* For the local variables of the procdure being integrated that live   on the frame, FRAME_POINTER_DELTA says how much to change their   offsets by, so that they now live in the correct place on the   frame of the function being compiled.  */static int fp_delta;/* When an insn is being copied by copy_rtx_and_substitute,   this is nonzero if we have copied an ASM_OPERANDS.   In that case, it is the original input-operand vector.   Likewise in copy_for_inline.  */static rtvec orig_asm_operands_vector;/* When an insn is being copied by copy_rtx_and_substitute,   this is nonzero if we have copied an ASM_OPERANDS.   In that case, it is the copied input-operand vector.   Likewise in copy_for_inline.  */static rtvec copy_asm_operands_vector;/* Likewise, this is the copied constraints vector.  */static rtvec copy_asm_constraints_vector;/* Return a copy of an rtx (as needed), substituting pseudo-register,   labels, and frame-pointer offsets as necessary.  */static rtx copy_rtx_and_substitute ();/* Variant, used for memory addresses that are not memory_address_p.  */static rtx copy_address ();/* Return the rtx corresponding to a given index in the stack arguments.  */static rtx access_parm_map ();static void copy_parm_decls ();static void copy_decl_tree ();static int frame_pointer_sum_p ();static rtx try_fold_cc0 ();/* We do some simple constant folding optimization.  This optimization   really exists primarily to save time inlining a function.  It   also helps users who ask for inline functions without -O.  */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)    return "varargs function cannot be inline";  if (current_function_calls_alloca)    return "function using alloca cannot be inline";  /* If its not even close, don't even look.  */  if (!TREE_INLINE (fndecl) && get_max_uid () > 3 * max_insns)    return "function too large to be inline";  /* We can't inline functions that return structures     the old-fashioned PCC way, copying into a static block.  */#ifdef PCC_STATIC_STRUCT_RETURN  if (flag_pcc_struct_return      && (TYPE_MODE (TREE_TYPE (TREE_TYPE (fndecl))) == BLKmode	  || RETURN_IN_MEMORY (TREE_TYPE (TREE_TYPE (fndecl)))))    return "inline functions not supported for this return value type";#endif  /* Don't inline functions which have BLKmode arguments.     Don't inline functions that take the address of       a parameter and do not specify a function prototype.  */  for (parms = DECL_ARGUMENTS (fndecl); parms; parms = TREE_CHAIN (parms))    {      if (TYPE_MODE (TREE_TYPE (parms)) == BLKmode)	return "function with large aggregate parameter cannot be inline";      if (last == NULL_TREE && TREE_ADDRESSABLE (parms))	return "no prototype, and parameter address used; cannot be inline";      /* If an aggregate is thought of as "in memory"	 then its components are referred to by narrower memory refs.	 If the actual parameter is a reg, these refs can't be translated,	 esp. since copy_rtx_and_substitute doesn't know whether it is	 reading or writing.  */      if ((TREE_CODE (TREE_TYPE (parms)) == RECORD_TYPE	   || TREE_CODE (TREE_TYPE (parms)) == UNION_TYPE)	  && GET_CODE (DECL_RTL (parms)) == MEM)	return "address of an aggregate parameter is used; cannot be inline";    }  if (!TREE_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_CODE (insn) == INSN	      || GET_CODE (insn) == JUMP_INSN	      || GET_CODE (insn) == CALL_INSN)	    ninsns++;	}      if (ninsns >= max_insns)	return "function too large to be inline";    }  return 0;}/* Variables used within save_for_inline.  *//* Mapping from old pesudo-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;/* Offset from arg ptr to the first parm of this inline function.  */static int first_parm_offset;/* On machines that perform a function return with a single   instruction, such as the VAX, these return insns must be   mapped into branch statements.  */extern rtx return_label;/* Copy an rtx for save_for_inline.  */static rtx copy_for_inline ();/* 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.  */voidsave_for_inline (fndecl)     tree fndecl;{  extern rtx *regno_reg_rtx;	/* in emit-rtl.c.  */  extern current_function_args_size;  rtx first_insn, last_insn, insn;  rtx head, copy;  tree parms;  int max_labelno, min_labelno, i, len;  int max_reg;  int max_uid;  /* Make and emit a return-label if we have not already done so.  */  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_parm_reg = max_parm_reg_num ();  max_reg = max_reg_num ();  /* Set up PARMDECL_MAP which maps pseudo-reg number to its PARM_DECL.     Set TREE_VOLATILE to 0 if the parm is in a register, otherwise 1.     Later we set TREE_READONLY to 0 if the parm is modified inside the fn.  */  parmdecl_map = (tree *) alloca (max_parm_reg * sizeof (tree));  bzero (parmdecl_map, max_parm_reg * sizeof (tree));  for (parms = DECL_ARGUMENTS (fndecl); parms; parms = TREE_CHAIN (parms))    {      rtx p = DECL_RTL (parms);      if (GET_CODE (p) == REG)	{	  parmdecl_map[REGNO (p)] = parms;	  TREE_VOLATILE (parms) = 0;	}      else	TREE_VOLATILE (parms) = 1;      TREE_READONLY (parms) = 1;    }  /* The list of DECL_SAVES_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 label used by that function,     the last label used by that function,     and the total number of registers used.  */  head = gen_inline_header_rtx (NULL, NULL, min_labelno, max_labelno,				max_parm_reg, max_reg,				current_function_args_size, stack_slot_list);  max_uid = INSN_UID (head);  /* We have now allocated all that needs to be allocated permanently     on the rtx obstack.  Set our high-water mark, so that we     can free the rest of this when the time comes.  */  preserve_data ();  /* Copy the chain insns of this function.     Install the copied chain as the insns of this function,     for continued compilation;     the original chain is recorded as the DECL_SAVED_INSNS     for inlining future calls.  */  /* If there are insns that copy parms from the stack into pseudo registers,     those insns are not copied.  `expand_inline_function' must     emit the correct code to handle such things.  */  insn = get_insns ();  if (GET_CODE (insn) != NOTE)    abort ();  first_insn = rtx_alloc (NOTE);  NOTE_SOURCE_FILE (first_insn) = NOTE_SOURCE_FILE (insn);  NOTE_LINE_NUMBER (first_insn) = NOTE_LINE_NUMBER (insn);  INSN_UID (first_insn) = INSN_UID (insn);  PREV_INSN (first_insn) = NULL;  NEXT_INSN (first_insn) = NULL;  last_insn = first_insn;  /* Each pseudo-reg in the old insn chain must have a unique rtx in the copy.     Make these new rtx's now, and install them in regno_reg_rtx, so they     will be the official pseudo-reg rtx's for the rest of compilation.  */  reg_map = (rtx *) alloca ((max_reg + 1) * sizeof (rtx));  len = sizeof (struct rtx_def) + (GET_RTX_LENGTH (REG) - 1) * sizeof (rtunion);  for (i = max_reg - 1; i >= FIRST_PSEUDO_REGISTER; i--)    reg_map[i] = (rtx)obstack_copy (&maybepermanent_obstack, regno_reg_rtx[i], len);  bcopy (reg_map + FIRST_PSEUDO_REGISTER,	 regno_reg_rtx + FIRST_PSEUDO_REGISTER,	 (max_reg - FIRST_PSEUDO_REGISTER) * sizeof (rtx));  /* Likewise each label rtx must have a unique rtx as its copy.  */  label_map = (rtx *)alloca ((max_labelno - min_labelno) * sizeof (rtx));  label_map -= min_labelno;  for (i = min_labelno; i < max_labelno; i++)    label_map[i] = gen_label_rtx ();  /* Record the mapping of old insns to copied insns.  */  insn_map = (rtx *) alloca (max_uid * sizeof (rtx));  bzero (insn_map, max_uid * sizeof (rtx));  /* Now copy the chain of insns.  */  for (insn = NEXT_INSN (insn); insn; insn = NEXT_INSN (insn))    {      orig_asm_operands_vector = 0;      copy_asm_operands_vector = 0;      switch (GET_CODE (insn))	{	case NOTE:	  /* No need to keep these.  */	  if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED)	    continue;	  copy = rtx_alloc (NOTE);	  NOTE_SOURCE_FILE (copy) = NOTE_SOURCE_FILE (insn);	  NOTE_LINE_NUMBER (copy) = NOTE_LINE_NUMBER (insn);	  break;	case INSN:	case CALL_INSN:	case JUMP_INSN:	  copy = rtx_alloc (GET_CODE (insn));	  PATTERN (copy) = copy_for_inline (PATTERN (insn));	  INSN_CODE (copy) = -1;	  LOG_LINKS (copy) = NULL;	  RTX_INTEGRATED_P (copy) = RTX_INTEGRATED_P (insn);	  break;	case CODE_LABEL:	  copy = label_map[CODE_LABEL_NUMBER (insn)];	  break;	case BARRIER:	  copy = rtx_alloc (BARRIER);	  break;	default:	  abort ();	}      INSN_UID (copy) = INSN_UID (insn);      insn_map[INSN_UID (insn)] = copy;      NEXT_INSN (last_insn) = copy;      PREV_INSN (copy) = last_insn;      last_insn = copy;    }  /* Now copy the reg notes of the insns.     Do this now because there can be forward references.  */  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))    if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN	|| GET_CODE (insn) == CALL_INSN)      {	rtx copy = insn_map[INSN_UID (insn)];	REG_NOTES (copy) = copy_for_inline (REG_NOTES (insn));      }  NEXT_INSN (last_insn) = NULL;  NEXT_INSN (head) = get_first_nonparm_insn ();

⌨️ 快捷键说明

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