📄 calls.c
字号:
#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), stack_size_rtx, next_arg_reg, NULL_RTX)); else emit_call_insn (gen_call (gen_rtx (MEM, FUNCTION_MODE, funexp), stack_size_rtx, next_arg_reg, struct_value_size_rtx)); } else#endif abort (); /* Find the CALL insn we just emitted. */ for (call_insn = get_last_insn (); call_insn && GET_CODE (call_insn) != CALL_INSN; call_insn = PREV_INSN (call_insn)) ; if (! call_insn) abort (); /* Put the register usage information on the CALL. If there is already some usage information, put ours at the end. */ if (CALL_INSN_FUNCTION_USAGE (call_insn)) { rtx link; for (link = CALL_INSN_FUNCTION_USAGE (call_insn); XEXP (link, 1) != 0; link = XEXP (link, 1)) ; XEXP (link, 1) = call_fusage; } else CALL_INSN_FUNCTION_USAGE (call_insn) = call_fusage; /* If this is a const call, then set the insn's unchanging bit. */ if (is_const) CONST_CALL_P (call_insn) = 1; /* Restore this now, so that we do defer pops for this call's args if the context of the call as a whole permits. */ inhibit_defer_pop = old_inhibit_defer_pop;#ifndef ACCUMULATE_OUTGOING_ARGS /* If returning from the subroutine does not automatically pop the args, we need an instruction to pop them sooner or later. Perhaps do it now; perhaps just record how much space to pop later. If returning from the subroutine does pop the args, indicate that the stack pointer will be changed. */ if (stack_size != 0 && RETURN_POPS_ARGS (fndecl, funtype, stack_size) > 0) { if (!already_popped) CALL_INSN_FUNCTION_USAGE (call_insn) = gen_rtx (EXPR_LIST, VOIDmode, gen_rtx (CLOBBER, VOIDmode, stack_pointer_rtx), CALL_INSN_FUNCTION_USAGE (call_insn)); stack_size -= RETURN_POPS_ARGS (fndecl, funtype, stack_size); stack_size_rtx = GEN_INT (stack_size); } if (stack_size != 0) { if (flag_defer_pop && inhibit_defer_pop == 0 && !is_const) pending_stack_adjust += stack_size; else adjust_stack (stack_size_rtx); }#endif}/* Generate all the code for a function call and return an rtx for its value. Store the value in TARGET (specified as an rtx) if convenient. If the value is stored in TARGET then TARGET is returned. If IGNORE is nonzero, then we ignore the value of the function call. */rtxexpand_call (exp, target, ignore) tree exp; rtx target; int ignore;{ /* List of actual parameters. */ tree actparms = TREE_OPERAND (exp, 1); /* RTX for the function to be called. */ rtx funexp; /* Tree node for the function to be called (not the address!). */ tree funtree; /* Data type of the function. */ tree funtype; /* Declaration of the function being called, or 0 if the function is computed (not known by name). */ tree fndecl = 0; char *name = 0; /* Register in which non-BLKmode value will be returned, or 0 if no value or if value is BLKmode. */ rtx valreg; /* Address where we should return a BLKmode value; 0 if value not BLKmode. */ rtx structure_value_addr = 0; /* Nonzero if that address is being passed by treating it as an extra, implicit first parameter. Otherwise, it is passed by being copied directly into struct_value_rtx. */ int structure_value_addr_parm = 0; /* Size of aggregate value wanted, or zero if none wanted or if we are using the non-reentrant PCC calling convention or expecting the value in registers. */ int struct_value_size = 0; /* Nonzero if called function returns an aggregate in memory PCC style, by returning the address of where to find it. */ int pcc_struct_value = 0; /* Number of actual parameters in this call, including struct value addr. */ int num_actuals; /* Number of named args. Args after this are anonymous ones and they must all go on the stack. */ int n_named_args; /* Count arg position in order args appear. */ int argpos; /* Vector of information about each argument. Arguments are numbered in the order they will be pushed, not the order they are written. */ struct arg_data *args; /* Total size in bytes of all the stack-parms scanned so far. */ struct args_size args_size; /* Size of arguments before any adjustments (such as rounding). */ struct args_size original_args_size; /* Data on reg parms scanned so far. */ CUMULATIVE_ARGS args_so_far; /* Nonzero if a reg parm has been scanned. */ int reg_parm_seen; /* Nonzero if this is an indirect function call. */ /* Nonzero if we must avoid push-insns in the args for this call. If stack space is allocated for register parameters, but not by the caller, then it is preallocated in the fixed part of the stack frame. So the entire argument block must then be preallocated (i.e., we ignore PUSH_ROUNDING in that case). */#if defined(REG_PARM_STACK_SPACE) && ! defined(OUTGOING_REG_PARM_STACK_SPACE) int must_preallocate = 1;#else#ifdef PUSH_ROUNDING int must_preallocate = 0;#else int must_preallocate = 1;#endif#endif /* Size of the stack reserved for parameter registers. */ int reg_parm_stack_space = 0; /* 1 if scanning parms front to back, -1 if scanning back to front. */ int inc; /* Address of space preallocated for stack parms (on machines that lack push insns), or 0 if space not preallocated. */ rtx argblock = 0; /* Nonzero if it is plausible that this is a call to alloca. */ int may_be_alloca; /* Nonzero if this is a call to setjmp or a related function. */ int returns_twice; /* Nonzero if this is a call to `longjmp'. */ int is_longjmp; /* Nonzero if this is a call to an inline function. */ int is_integrable = 0; /* Nonzero if this is a call to a `const' function. Note that only explicitly named functions are handled as `const' here. */ int is_const = 0; /* Nonzero if this is a call to a `volatile' function. */ int is_volatile = 0;#if defined(ACCUMULATE_OUTGOING_ARGS) && defined(REG_PARM_STACK_SPACE) /* Define the boundary of the register parm stack space that needs to be save, if any. */ int low_to_save = -1, high_to_save; rtx save_area = 0; /* Place that it is saved */#endif#ifdef ACCUMULATE_OUTGOING_ARGS int initial_highest_arg_in_use = highest_outgoing_arg_in_use; char *initial_stack_usage_map = stack_usage_map;#endif rtx old_stack_level = 0; int old_pending_adj = 0; int old_stack_arg_under_construction; int old_inhibit_defer_pop = inhibit_defer_pop; rtx call_fusage = 0; register tree p; register int i, j; /* The value of the function call can be put in a hard register. But if -fcheck-memory-usage, code which invokes functions (and thus damages some hard registers) can be inserted before using the value. So, target is always a pseudo-register in that case. */ if (flag_check_memory_usage) target = 0; /* See if we can find a DECL-node for the actual function. As a result, decide whether this is a call to an integrable function. */ p = TREE_OPERAND (exp, 0); if (TREE_CODE (p) == ADDR_EXPR) { fndecl = TREE_OPERAND (p, 0); if (TREE_CODE (fndecl) != FUNCTION_DECL) fndecl = 0; else { if (!flag_no_inline && fndecl != current_function_decl && DECL_INLINE (fndecl) && DECL_SAVED_INSNS (fndecl) && RTX_INTEGRATED_P (DECL_SAVED_INSNS (fndecl))) is_integrable = 1; else if (! TREE_ADDRESSABLE (fndecl)) { /* In case this function later becomes inlinable, record that there was already a non-inline call to it. Use abstraction instead of setting TREE_ADDRESSABLE directly. */ if (DECL_INLINE (fndecl) && warn_inline && !flag_no_inline && optimize > 0) { warning_with_decl (fndecl, "can't inline call to `%s'"); warning ("called from here"); } mark_addressable (fndecl); } if (TREE_READONLY (fndecl) && ! TREE_THIS_VOLATILE (fndecl) && TYPE_MODE (TREE_TYPE (exp)) != VOIDmode) is_const = 1; if (TREE_THIS_VOLATILE (fndecl)) is_volatile = 1; } } /* If we don't have specific function to call, see if we have a constant or `noreturn' function from the type. */ if (fndecl == 0) { is_const = TREE_READONLY (TREE_TYPE (TREE_TYPE (p))); is_volatile = TREE_THIS_VOLATILE (TREE_TYPE (TREE_TYPE (p))); }#ifdef REG_PARM_STACK_SPACE#ifdef MAYBE_REG_PARM_STACK_SPACE reg_parm_stack_space = MAYBE_REG_PARM_STACK_SPACE;#else reg_parm_stack_space = REG_PARM_STACK_SPACE (fndecl);#endif#endif /* Warn if this value is an aggregate type, regardless of which calling convention we are using for it. */ if (warn_aggregate_return && AGGREGATE_TYPE_P (TREE_TYPE (exp))) warning ("function call has aggregate value"); /* Set up a place to return a structure. */ /* Cater to broken compilers. */ if (aggregate_value_p (exp)) { /* This call returns a big structure. */ is_const = 0;#ifdef PCC_STATIC_STRUCT_RETURN { pcc_struct_value = 1; /* Easier than making that case work right. */ if (is_integrable) { /* In case this is a static function, note that it has been used. */ if (! TREE_ADDRESSABLE (fndecl)) mark_addressable (fndecl); is_integrable = 0; } }#else /* not PCC_STATIC_STRUCT_RETURN */ { struct_value_size = int_size_in_bytes (TREE_TYPE (exp)); if (target && GET_CODE (target) == MEM) structure_value_addr = XEXP (target, 0); else { /* Assign a temporary to hold the value. */ tree d; /* For variable-sized objects, we must be called with a target specified. If we were to allocate space on the stack here, we would have no way of knowing when to free it. */ if (struct_value_size < 0) abort (); /* This DECL is just something to feed to mark_addressable; it doesn't get pushed. */ d = build_decl (VAR_DECL, NULL_TREE, TREE_TYPE (exp)); DECL_RTL (d) = assign_temp (TREE_TYPE (exp), 1, 0, 1); mark_addressable (d); structure_value_addr = XEXP (DECL_RTL (d), 0); MEM_IN_STRUCT_P (structure_value_addr) = AGGREGATE_TYPE_P (TREE_TYPE (exp)); target = 0; } }#endif /* not PCC_STATIC_STRUCT_RETURN */ } /* If called function is inline, try to integrate it. */ if (is_integrable) { rtx temp; rtx before_call = get_last_insn (); temp = expand_inline_function (fndecl, actparms, target, ignore, TREE_TYPE (exp), structure_value_addr); /* If inlining succeeded, return. */ if ((HOST_WIDE_INT) temp != -1) {#ifdef ACCUMULATE_OUTGOING_ARGS /* If the outgoing argument list must be preserved, push the stack before executing the inlined function if it makes any calls. */ for (i = reg_parm_stack_space - 1; i >= 0; i--) if (i < highest_outgoing_arg_in_use && stack_usage_map[i] != 0) break; if (stack_arg_under_construction || i >= 0) { rtx first_insn = before_call ? NEXT_INSN (before_call) : get_insns (); rtx insn, seq; /* Look for a call in the inline function code. If OUTGOING_ARGS_SIZE (DECL_SAVED_INSNS (fndecl)) is nonzero then there is a call and it is not necessary to scan the insns. */ if (OUTGOING_ARGS_SIZE (DECL_SAVED_INSNS (fndecl)) == 0) for (insn = first_insn; insn; insn = NEXT_INSN (insn)) if (GET_CODE (insn) == CALL_INSN) break; if (insn) { /* Reserve enough stack space so that the largest argument list of any function call in the inline function does not overlap the argument list being evaluated. This is usually an overestimate because allocate_dynamic_stack_space reserves space for an outgoing argument list in addition to the requested space, but there is no way to ask for stack space such that an argument list of a certain length can be safely constructed. */ int adjust = OUTGOING_ARGS_SIZE (DECL_SAVED_INSNS (fndecl));#ifdef REG_PARM_STACK_SPACE /* Add the stack space reserved for register arguments in the inline function. What is really needed is the largest value of reg_parm_stack_space in the inline function, but that is not available. Using the current value of reg_parm_stack_space is wrong, but gives correct results on all supported machines. */ adjust += reg_parm_stack_space;#endif start_sequence (); emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX); allocate_dynamic_stack_space (GEN_INT (adjust),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -