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

📄 calls.c

📁 GUN开源阻止下的编译器GCC
💻 C
📖 第 1 页 / 共 5 页
字号:
/* Convert function calls to rtl insns, for GNU C compiler.   Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.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 "rtl.h"#include "tree.h"#include "flags.h"#include "expr.h"#ifdef __STDC__#include <stdarg.h>#else#include <varargs.h>#endif#include "insn-flags.h"/* Decide whether a function's arguments should be processed   from first to last or from last to first.   They should if the stack and args grow in opposite directions, but   only if we have push insns.  */#ifdef PUSH_ROUNDING#if defined (STACK_GROWS_DOWNWARD) != defined (ARGS_GROW_DOWNWARD)#define PUSH_ARGS_REVERSED	/* If it's last to first */#endif#endif/* Like STACK_BOUNDARY but in units of bytes, not bits.  */#define STACK_BYTES (STACK_BOUNDARY / BITS_PER_UNIT)/* Data structure and subroutines used within expand_call.  */struct arg_data{  /* Tree node for this argument.  */  tree tree_value;  /* Mode for value; TYPE_MODE unless promoted.  */  enum machine_mode mode;  /* Current RTL value for argument, or 0 if it isn't precomputed.  */  rtx value;  /* Initially-compute RTL value for argument; only for const functions.  */  rtx initial_value;  /* Register to pass this argument in, 0 if passed on stack, or an     EXPR_LIST if the arg is to be copied into multiple different     registers.  */  rtx reg;  /* If REG was promoted from the actual mode of the argument expression,     indicates whether the promotion is sign- or zero-extended.  */  int unsignedp;  /* Number of registers to use.  0 means put the whole arg in registers.     Also 0 if not passed in registers.  */  int partial;  /* Non-zero if argument must be passed on stack.     Note that some arguments may be passed on the stack     even though pass_on_stack is zero, just because FUNCTION_ARG says so.     pass_on_stack identifies arguments that *cannot* go in registers.  */  int pass_on_stack;  /* Offset of this argument from beginning of stack-args.  */  struct args_size offset;  /* Similar, but offset to the start of the stack slot.  Different from     OFFSET if this arg pads downward.  */  struct args_size slot_offset;  /* Size of this argument on the stack, rounded up for any padding it gets,     parts of the argument passed in registers do not count.     If REG_PARM_STACK_SPACE is defined, then register parms     are counted here as well.  */  struct args_size size;  /* Location on the stack at which parameter should be stored.  The store     has already been done if STACK == VALUE.  */  rtx stack;  /* Location on the stack of the start of this argument slot.  This can     differ from STACK if this arg pads downward.  This location is known     to be aligned to FUNCTION_ARG_BOUNDARY.  */  rtx stack_slot;#ifdef ACCUMULATE_OUTGOING_ARGS  /* Place that this stack area has been saved, if needed.  */  rtx save_area;#endif#ifdef STRICT_ALIGNMENT  /* If an argument's alignment does not permit direct copying into registers,     copy in smaller-sized pieces into pseudos.  These are stored in a     block pointed to by this field.  The next field says how many     word-sized pseudos we made.  */  rtx *aligned_regs;  int n_aligned_regs;#endif};#ifdef ACCUMULATE_OUTGOING_ARGS/* A vector of one char per byte of stack space.  A byte if non-zero if   the corresponding stack location has been used.   This vector is used to prevent a function call within an argument from   clobbering any stack already set up.  */static char *stack_usage_map;/* Size of STACK_USAGE_MAP.  */static int highest_outgoing_arg_in_use;/* stack_arg_under_construction is nonzero when an argument may be   initialized with a constructor call (including a C function that   returns a BLKmode struct) and expand_call must take special action   to make sure the object being constructed does not overlap the   argument list for the constructor call.  */int stack_arg_under_construction;#endifstatic int calls_function	PROTO((tree, int));static int calls_function_1	PROTO((tree, int));static void emit_call_1		PROTO((rtx, tree, tree, int, int, rtx, rtx,				       int, rtx, int));static void store_one_arg	PROTO ((struct arg_data *, rtx, int, int,					tree, int));/* If WHICH is 1, return 1 if EXP contains a call to the built-in function   `alloca'.   If WHICH is 0, return 1 if EXP contains a call to any function.   Actually, we only need return 1 if evaluating EXP would require pushing   arguments on the stack, but that is too difficult to compute, so we just   assume any function call might require the stack.  */static tree calls_function_save_exprs;static intcalls_function (exp, which)     tree exp;     int which;{  int val;  calls_function_save_exprs = 0;  val = calls_function_1 (exp, which);  calls_function_save_exprs = 0;  return val;}static intcalls_function_1 (exp, which)     tree exp;     int which;{  register int i;  enum tree_code code = TREE_CODE (exp);  int type = TREE_CODE_CLASS (code);  int length = tree_code_length[(int) code];  /* If this code is language-specific, we don't know what it will do.  */  if ((int) code >= NUM_TREE_CODES)    return 1;  /* Only expressions and references can contain calls.  */  if (type != 'e' && type != '<' && type != '1' && type != '2' && type != 'r'      && type != 'b')    return 0;  switch (code)    {    case CALL_EXPR:      if (which == 0)	return 1;      else if (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR	       && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))		   == FUNCTION_DECL))	{	  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);	  if ((DECL_BUILT_IN (fndecl)	       && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_ALLOCA)	      || (DECL_SAVED_INSNS (fndecl)		  && (FUNCTION_FLAGS (DECL_SAVED_INSNS (fndecl))		      & FUNCTION_FLAGS_CALLS_ALLOCA)))	    return 1;	}      /* Third operand is RTL.  */      length = 2;      break;    case SAVE_EXPR:      if (SAVE_EXPR_RTL (exp) != 0)	return 0;      if (value_member (exp, calls_function_save_exprs))	return 0;      calls_function_save_exprs = tree_cons (NULL_TREE, exp,					     calls_function_save_exprs);      return (TREE_OPERAND (exp, 0) != 0	      && calls_function_1 (TREE_OPERAND (exp, 0), which));    case BLOCK:      {	register tree local;	for (local = BLOCK_VARS (exp); local; local = TREE_CHAIN (local))	  if (DECL_INITIAL (local) != 0	      && calls_function_1 (DECL_INITIAL (local), which))	    return 1;      }      {	register tree subblock;	for (subblock = BLOCK_SUBBLOCKS (exp);	     subblock;	     subblock = TREE_CHAIN (subblock))	  if (calls_function_1 (subblock, which))	    return 1;      }      return 0;    case METHOD_CALL_EXPR:      length = 3;      break;    case WITH_CLEANUP_EXPR:      length = 1;      break;    case RTL_EXPR:      return 0;    }  for (i = 0; i < length; i++)    if (TREE_OPERAND (exp, i) != 0	&& calls_function_1 (TREE_OPERAND (exp, i), which))      return 1;  return 0;}/* Force FUNEXP into a form suitable for the address of a CALL,   and return that as an rtx.  Also load the static chain register   if FNDECL is a nested function.   CALL_FUSAGE points to a variable holding the prospective   CALL_INSN_FUNCTION_USAGE information.  */rtxprepare_call_address (funexp, fndecl, call_fusage, reg_parm_seen)     rtx funexp;     tree fndecl;     rtx *call_fusage;     int reg_parm_seen;{  rtx static_chain_value = 0;  funexp = protect_from_queue (funexp, 0);  if (fndecl != 0)    /* Get possible static chain value for nested function in C. */    static_chain_value = lookup_static_chain (fndecl);  /* Make a valid memory address and copy constants thru pseudo-regs,     but not for a constant address if -fno-function-cse.  */  if (GET_CODE (funexp) != SYMBOL_REF)    funexp =#ifdef SMALL_REGISTER_CLASSES    /* If we are using registers for parameters, force the	 function address into a register now.  */      reg_parm_seen ? force_not_mem (memory_address (FUNCTION_MODE, funexp))		    :#endif		      memory_address (FUNCTION_MODE, funexp);  else    {#ifndef NO_FUNCTION_CSE      if (optimize && ! flag_no_function_cse)#ifdef NO_RECURSIVE_FUNCTION_CSE	if (fndecl != current_function_decl)#endif	  funexp = force_reg (Pmode, funexp);#endif    }  if (static_chain_value != 0)    {      emit_move_insn (static_chain_rtx, static_chain_value);      if (GET_CODE (static_chain_rtx) == REG)	use_reg (call_fusage, static_chain_rtx);    }  return funexp;}/* Generate instructions to call function FUNEXP,   and optionally pop the results.   The CALL_INSN is the first insn generated.   FNDECL is the declaration node of the function.  This is given ot the   macro RETURN_POPS_ARGS to determine whether this function pops its own args.   FUNTYPE is the data type of the function, or, for a library call,   the identifier for the name of the call.  This is given to the   macro RETURN_POPS_ARGS to determine whether this function pops its own args.   STACK_SIZE is the number of bytes of arguments on the stack,   rounded up to STACK_BOUNDARY; zero if the size is variable.   This is both to put into the call insn and   to generate explicit popping code if necessary.   STRUCT_VALUE_SIZE is the number of bytes wanted in a structure value.   It is zero if this call doesn't want a structure value.   NEXT_ARG_REG is the rtx that results from executing     FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1)   just after all the args have had their registers assigned.   This could be whatever you like, but normally it is the first   arg-register beyond those used for args in this call,   or 0 if all the arg-registers are used in this call.   It is passed on to `gen_call' so you can put this info in the call insn.   VALREG is a hard register in which a value is returned,   or 0 if the call does not return a value.   OLD_INHIBIT_DEFER_POP is the value that `inhibit_defer_pop' had before   the args to this call were processed.   We restore `inhibit_defer_pop' to that value.   CALL_FUSAGE is either empty or an EXPR_LIST of USE expressions that   denote registers used by the called function.   IS_CONST is true if this is a `const' call.  */static voidemit_call_1 (funexp, fndecl, funtype, stack_size, struct_value_size,              next_arg_reg, valreg, old_inhibit_defer_pop, call_fusage,	     is_const)     rtx funexp;     tree fndecl;     tree funtype;     int stack_size;     int struct_value_size;     rtx next_arg_reg;     rtx valreg;     int old_inhibit_defer_pop;     rtx call_fusage;     int is_const;{  rtx stack_size_rtx = GEN_INT (stack_size);  rtx struct_value_size_rtx = GEN_INT (struct_value_size);  rtx call_insn;  int already_popped = 0;  /* Ensure address is valid.  SYMBOL_REF is already valid, so no need,     and we don't want to load it into a register as an optimization,     because prepare_call_address already did it if it should be done.  */  if (GET_CODE (funexp) != SYMBOL_REF)    funexp = memory_address (FUNCTION_MODE, funexp);#ifndef ACCUMULATE_OUTGOING_ARGS#if defined (HAVE_call_pop) && defined (HAVE_call_value_pop)  if (HAVE_call_pop && HAVE_call_value_pop      && (RETURN_POPS_ARGS (fndecl, funtype, stack_size) > 0           || stack_size == 0))    {      rtx n_pop = GEN_INT (RETURN_POPS_ARGS (fndecl, funtype, stack_size));      rtx pat;      /* If this subroutine pops its own args, record that in the call insn	 if possible, for the sake of frame pointer elimination.  */      if (valreg)	pat = gen_call_value_pop (valreg,				  gen_rtx (MEM, FUNCTION_MODE, funexp),				  stack_size_rtx, next_arg_reg, n_pop);      else	pat = gen_call_pop (gen_rtx (MEM, FUNCTION_MODE, funexp),			    stack_size_rtx, next_arg_reg, n_pop);      emit_call_insn (pat);      already_popped = 1;    }  else#endif#endif#if defined (HAVE_call) && defined (HAVE_call_value)  if (HAVE_call && HAVE_call_value)    {      if (valreg)	emit_call_insn (gen_call_value (valreg,					gen_rtx (MEM, FUNCTION_MODE, funexp),

⌨️ 快捷键说明

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