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

📄 calls.c

📁 GCC编译器源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
						NULL_RTX, BITS_PER_UNIT);		  seq = get_insns ();		  end_sequence ();		  emit_insns_before (seq, first_insn);		  emit_stack_restore (SAVE_BLOCK, old_stack_level, NULL_RTX);		}	    }#endif	  /* If the result is equivalent to TARGET, return TARGET to simplify	     checks in store_expr.  They can be equivalent but not equal in the	     case of a function that returns BLKmode.  */	  if (temp != target && rtx_equal_p (temp, target))	    return target;	  return temp;	}      /* If inlining failed, mark FNDECL as needing to be compiled	 separately after all.  If function was declared inline,	 give a warning.  */      if (DECL_INLINE (fndecl) && warn_inline && !flag_no_inline	  && optimize > 0 && ! TREE_ADDRESSABLE (fndecl))	{	  warning_with_decl (fndecl, "inlining failed in call to `%s'");	  warning ("called from here");	}      mark_addressable (fndecl);    }  /* When calling a const function, we must pop the stack args right away,     so that the pop is deleted or moved with the call.  */  if (is_const)    NO_DEFER_POP;  function_call_count++;  if (fndecl && DECL_NAME (fndecl))    name = IDENTIFIER_POINTER (DECL_NAME (fndecl));#if 0  /* Unless it's a call to a specific function that isn't alloca,     if it has one argument, we must assume it might be alloca.  */  may_be_alloca    = (!(fndecl != 0 && strcmp (name, "alloca"))       && actparms != 0       && TREE_CHAIN (actparms) == 0);#else  /* We assume that alloca will always be called by name.  It     makes no sense to pass it as a pointer-to-function to     anything that does not understand its behavior.  */  may_be_alloca    = (name && ((IDENTIFIER_LENGTH (DECL_NAME (fndecl)) == 6		 && name[0] == 'a'		 && ! strcmp (name, "alloca"))		|| (IDENTIFIER_LENGTH (DECL_NAME (fndecl)) == 16		    && name[0] == '_'		    && ! strcmp (name, "__builtin_alloca"))));#endif  /* See if this is a call to a function that can return more than once     or a call to longjmp.  */  returns_twice = 0;  is_longjmp = 0;  if (name != 0 && IDENTIFIER_LENGTH (DECL_NAME (fndecl)) <= 15)    {      char *tname = name;      /* Disregard prefix _, __ or __x.  */      if (name[0] == '_')	{	  if (name[1] == '_' && name[2] == 'x')	    tname += 3;	  else if (name[1] == '_')	    tname += 2;	  else	    tname += 1;	}      if (tname[0] == 's')	{	  returns_twice	    = ((tname[1] == 'e'		&& (! strcmp (tname, "setjmp")		    || ! strcmp (tname, "setjmp_syscall")))	       || (tname[1] == 'i'		   && ! strcmp (tname, "sigsetjmp"))	       || (tname[1] == 'a'		   && ! strcmp (tname, "savectx")));	  if (tname[1] == 'i'	      && ! strcmp (tname, "siglongjmp"))	    is_longjmp = 1;	}      else if ((tname[0] == 'q' && tname[1] == 's'		&& ! strcmp (tname, "qsetjmp"))	       || (tname[0] == 'v' && tname[1] == 'f'		   && ! strcmp (tname, "vfork")))	returns_twice = 1;      else if (tname[0] == 'l' && tname[1] == 'o'	       && ! strcmp (tname, "longjmp"))	is_longjmp = 1;    }  if (may_be_alloca)    current_function_calls_alloca = 1;  /* Don't let pending stack adjusts add up to too much.     Also, do all pending adjustments now     if there is any chance this might be a call to alloca.  */  if (pending_stack_adjust >= 32      || (pending_stack_adjust > 0 && may_be_alloca))    do_pending_stack_adjust ();  /* Operand 0 is a pointer-to-function; get the type of the function.  */  funtype = TREE_TYPE (TREE_OPERAND (exp, 0));  if (TREE_CODE (funtype) != POINTER_TYPE)    abort ();  funtype = TREE_TYPE (funtype);  /* Push the temporary stack slot level so that we can free any temporaries     we make.  */  push_temp_slots ();  /* Start updating where the next arg would go.     On some machines (such as the PA) indirect calls have a different     calling convention than normal calls.  The last argument in     INIT_CUMULATIVE_ARGS tells the backend if this is an indirect call     or not.  */  INIT_CUMULATIVE_ARGS (args_so_far, funtype, NULL_RTX, (fndecl == 0));  /* If struct_value_rtx is 0, it means pass the address     as if it were an extra parameter.  */  if (structure_value_addr && struct_value_rtx == 0)    {      /* If structure_value_addr is a REG other than	 virtual_outgoing_args_rtx, we can use always use it.  If it	 is not a REG, we must always copy it into a register.	 If it is virtual_outgoing_args_rtx, we must copy it to another	 register in some cases.  */      rtx temp = (GET_CODE (structure_value_addr) != REG#ifdef ACCUMULATE_OUTGOING_ARGS		  || (stack_arg_under_construction		      && structure_value_addr == virtual_outgoing_args_rtx)#endif		  ? copy_addr_to_reg (structure_value_addr)		  : structure_value_addr);      actparms	= tree_cons (error_mark_node,		     make_tree (build_pointer_type (TREE_TYPE (funtype)),				temp),		     actparms);      structure_value_addr_parm = 1;    }  /* Count the arguments and set NUM_ACTUALS.  */  for (p = actparms, i = 0; p; p = TREE_CHAIN (p)) i++;  num_actuals = i;  /* Compute number of named args.     Normally, don't include the last named arg if anonymous args follow.     We do include the last named arg if STRICT_ARGUMENT_NAMING is defined.     (If no anonymous args follow, the result of list_length is actually     one too large.  This is harmless.)     If SETUP_INCOMING_VARARGS is defined and STRICT_ARGUMENT_NAMING is not,     this machine will be able to place unnamed args that were passed in     registers into the stack.  So treat all args as named.  This allows the     insns emitting for a specific argument list to be independent of the     function declaration.     If SETUP_INCOMING_VARARGS is not defined, we do not have any reliable     way to pass unnamed args in registers, so we must force them into     memory.  */#if !defined(SETUP_INCOMING_VARARGS) || defined(STRICT_ARGUMENT_NAMING)  if (TYPE_ARG_TYPES (funtype) != 0)    n_named_args      = (list_length (TYPE_ARG_TYPES (funtype))#ifndef STRICT_ARGUMENT_NAMING	 /* Don't include the last named arg.  */	 - 1#endif	 /* Count the struct value address, if it is passed as a parm.  */	 + structure_value_addr_parm);  else#endif    /* If we know nothing, treat all args as named.  */    n_named_args = num_actuals;  /* Make a vector to hold all the information about each arg.  */  args = (struct arg_data *) alloca (num_actuals * sizeof (struct arg_data));  bzero ((char *) args, num_actuals * sizeof (struct arg_data));  args_size.constant = 0;  args_size.var = 0;  /* In this loop, we consider args in the order they are written.     We fill up ARGS from the front or from the back if necessary     so that in any case the first arg to be pushed ends up at the front.  */#ifdef PUSH_ARGS_REVERSED  i = num_actuals - 1, inc = -1;  /* In this case, must reverse order of args     so that we compute and push the last arg first.  */#else  i = 0, inc = 1;#endif  /* I counts args in order (to be) pushed; ARGPOS counts in order written.  */  for (p = actparms, argpos = 0; p; p = TREE_CHAIN (p), i += inc, argpos++)    {      tree type = TREE_TYPE (TREE_VALUE (p));      int unsignedp;      enum machine_mode mode;      args[i].tree_value = TREE_VALUE (p);      /* Replace erroneous argument with constant zero.  */      if (type == error_mark_node || TYPE_SIZE (type) == 0)	args[i].tree_value = integer_zero_node, type = integer_type_node;      /* If TYPE is a transparent union, pass things the way we would	 pass the first field of the union.  We have already verified that	 the modes are the same.  */      if (TYPE_TRANSPARENT_UNION (type))	type = TREE_TYPE (TYPE_FIELDS (type));      /* Decide where to pass this arg.	 args[i].reg is nonzero if all or part is passed in registers.	 args[i].partial is nonzero if part but not all is passed in registers,	 and the exact value says how many words are passed in registers.	 args[i].pass_on_stack is nonzero if the argument must at least be	 computed on the stack.  It may then be loaded back into registers	 if args[i].reg is nonzero.	 These decisions are driven by the FUNCTION_... macros and must agree	 with those made by function.c.  */      /* See if this argument should be passed by invisible reference.  */      if ((TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST	   && contains_placeholder_p (TYPE_SIZE (type)))	  || TREE_ADDRESSABLE (type)#ifdef FUNCTION_ARG_PASS_BY_REFERENCE	  || FUNCTION_ARG_PASS_BY_REFERENCE (args_so_far, TYPE_MODE (type),					     type, argpos < n_named_args)#endif	  )	{	  /* If we're compiling a thunk, pass through invisible             references instead of making a copy.  */	  if (current_function_is_thunk#ifdef FUNCTION_ARG_CALLEE_COPIES	      || (FUNCTION_ARG_CALLEE_COPIES (args_so_far, TYPE_MODE (type),					     type, argpos < n_named_args)		  /* If it's in a register, we must make a copy of it too.  */		  /* ??? Is this a sufficient test?  Is there a better one? */		  && !(TREE_CODE (args[i].tree_value) == VAR_DECL		       && REG_P (DECL_RTL (args[i].tree_value)))		  && ! TREE_ADDRESSABLE (type))#endif	      )	    {	      args[i].tree_value = build1 (ADDR_EXPR,					   build_pointer_type (type),					   args[i].tree_value);	      type = build_pointer_type (type);	    }	  else	    {	      /* We make a copy of the object and pass the address to the		 function being called.  */	      rtx copy;	      if (TYPE_SIZE (type) == 0		  || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST		  || (flag_stack_check && ! STACK_CHECK_BUILTIN		      && (TREE_INT_CST_HIGH (TYPE_SIZE (type)) != 0			  || (TREE_INT_CST_LOW (TYPE_SIZE (type))			      > STACK_CHECK_MAX_VAR_SIZE * BITS_PER_UNIT))))		{		  /* This is a variable-sized object.  Make space on the stack		     for it.  */		  rtx size_rtx = expr_size (TREE_VALUE (p));		  if (old_stack_level == 0)		    {		      emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX);		      old_pending_adj = pending_stack_adjust;		      pending_stack_adjust = 0;		    }		  copy = gen_rtx (MEM, BLKmode,				  allocate_dynamic_stack_space (size_rtx,								NULL_RTX,								TYPE_ALIGN (type)));		}	      else		{		  int size = int_size_in_bytes (type);		  copy = assign_stack_temp (TYPE_MODE (type), size, 0);		}	      MEM_IN_STRUCT_P (copy) = AGGREGATE_TYPE_P (type);	      store_expr (args[i].tree_value, copy, 0);	      is_const = 0;	      args[i].tree_value = build1 (ADDR_EXPR,					   build_pointer_type (type),					   make_tree (type, copy));	      type = build_pointer_type (type);	    }	}      mode = TYPE_MODE (type);      unsignedp = TREE_UNSIGNED (type);#ifdef PROMOTE_FUNCTION_ARGS      mode = promote_mode (type, mode, &unsignedp, 1);#endif      args[i].unsignedp = unsignedp;      args[i].mode = mode;      args[i].reg = FUNCTION_ARG (args_so_far, mode, type,				  argpos < n_named_args);#ifdef FUNCTION_ARG_PARTIAL_NREGS      if (args[i].reg)	args[i].partial	  = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, mode, type,					argpos < n_named_args);#endif      args[i].pass_on_stack = MUST_PASS_IN_STACK (mode, type);      /* If FUNCTION_ARG returned a (parallel [(expr_list (nil) ...) ...]),	 it means that we are to pass this arg in the register(s) designated	 by the PARALLEL, but also to pass it in the stack.  */      if (args[i].reg && GET_CODE (args[i].reg) == PARALLEL	  && XEXP (XVECEXP (args[i].reg, 0, 0), 0) == 0)	args[i].pass_on_stack = 1;      /* If this is an addressable type, we must preallocate the stack	 since we must evaluate the object into its final location.	 If this is to be passed in both registers and the stack, it is simpler	 to preallocate.  */      if (TREE_ADDRESSABLE (type)	  || (args[i].pass_on_stack && args[i].reg != 0))	must_preallocate = 1;      /* If this is an addressable type, we cannot pre-evaluate it.  Thus,	 we cannot consider this function call constant.  */      if (TREE_ADDRESSABLE (type))	is_const = 0;      /* Compute the stack-size of this argument.  */      if (args[i].reg == 0 || args[i].partial != 0#ifdef REG_PARM_STACK_SPACE	  || reg_parm_stack_space > 0#endif	  || args[i].pass_on_stack)	locate_and_pad_parm (mode, type,#ifdef STACK_PARMS_IN_REG_PARM_AREA			     1,#else			     args[i].reg != 0,#endif			     fndecl, &args_size, &args[i].offset,			     &args[i].size);#ifndef ARGS_GROW_DOWNWARD      args[i].slot_offset = args_size;#endif#ifndef REG_PARM_STACK_SPACE      /* If a part of the arg was put into registers,	 don't include that part in the amount pushed.  */      if (! args[i].pass_on_stack)	args[i].size.constant -= ((args[i].partial * UNITS_PER_WORD)				  / (PARM_BOUNDARY / BITS_PER_UNIT)				  * (PARM_BOUNDARY / BITS_PER_UNIT));#endif            /* Update ARGS_SIZE, the total stack space for args so far.  */

⌨️ 快捷键说明

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