X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fcalls.c;h=e15a96b9c3749c3b9d7c95e39f2f7e87b1d9614f;hb=ac4ededf628466d520f6b6edbf15f14d2c1fe776;hp=b4d66f9221286c725b0a7e0ebda8291c6d2c731e;hpb=a8349c62da4e62b8ab039f14ee293e6a24c56026;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/calls.c b/gcc/calls.c index b4d66f92212..e15a96b9c37 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -120,7 +120,7 @@ int stack_arg_under_construction; static int calls_function (tree, int); static int calls_function_1 (tree, int); -static void emit_call_1 (rtx, tree, tree, HOST_WIDE_INT, HOST_WIDE_INT, +static void emit_call_1 (rtx, tree, tree, tree, HOST_WIDE_INT, HOST_WIDE_INT, HOST_WIDE_INT, rtx, rtx, int, rtx, int, CUMULATIVE_ARGS *); static void precompute_register_parameters (int, struct arg_data *, int *); @@ -133,7 +133,8 @@ static int compute_argument_block_size (int, struct args_size *, int); static void initialize_argument_information (int, struct arg_data *, struct args_size *, int, tree, tree, CUMULATIVE_ARGS *, int, - rtx *, int *, int *, int *); + rtx *, int *, int *, int *, + bool *, bool); static void compute_argument_addresses (struct arg_data *, rtx, int); static rtx rtx_for_function_call (tree, tree); static void load_register_parameters (struct arg_data *, int, rtx *, int, @@ -141,7 +142,6 @@ static void load_register_parameters (struct arg_data *, int, rtx *, int, static rtx emit_library_call_value_1 (int, rtx, rtx, enum libcall_type, enum machine_mode, int, va_list); static int special_function_p (tree, int); -static rtx try_to_integrate (tree, tree, rtx, int, tree, rtx); static int check_sibcall_argument_overlap_1 (rtx); static int check_sibcall_argument_overlap (rtx, struct arg_data *, int); @@ -279,17 +279,11 @@ calls_function_1 (tree exp, int which) CALL_INSN_FUNCTION_USAGE information. */ rtx -prepare_call_address (rtx funexp, tree fndecl, rtx *call_fusage, - int reg_parm_seen, int sibcallp) +prepare_call_address (rtx funexp, rtx static_chain_value, + rtx *call_fusage, int reg_parm_seen, int sibcallp) { - 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 through pseudo-regs, but not for a constant address if -fno-function-cse. */ if (GET_CODE (funexp) != SYMBOL_REF) @@ -361,7 +355,8 @@ prepare_call_address (rtx funexp, tree fndecl, rtx *call_fusage, denote registers used by the called function. */ static void -emit_call_1 (rtx funexp, tree fndecl ATTRIBUTE_UNUSED, tree funtype ATTRIBUTE_UNUSED, +emit_call_1 (rtx funexp, tree fntree, tree fndecl ATTRIBUTE_UNUSED, + tree funtype ATTRIBUTE_UNUSED, HOST_WIDE_INT stack_size ATTRIBUTE_UNUSED, HOST_WIDE_INT rounded_stack_size, HOST_WIDE_INT struct_value_size ATTRIBUTE_UNUSED, @@ -505,7 +500,16 @@ emit_call_1 (rtx funexp, tree fndecl ATTRIBUTE_UNUSED, tree funtype ATTRIBUTE_UN REG_NOTES (call_insn) = gen_rtx_EXPR_LIST (REG_EH_REGION, const0_rtx, REG_NOTES (call_insn)); else - note_eh_region_may_contain_throw (); + { + int rn = lookup_stmt_eh_region (fntree); + + /* If rn < 0, then either (1) tree-ssa not used or (2) doesn't + throw, which we already took care of. */ + if (rn > 0) + REG_NOTES (call_insn) = gen_rtx_EXPR_LIST (REG_EH_REGION, GEN_INT (rn), + REG_NOTES (call_insn)); + note_current_region_may_contain_throw (); + } if (ecf_flags & ECF_NORETURN) REG_NOTES (call_insn) = gen_rtx_EXPR_LIST (REG_NORETURN, const0_rtx, @@ -589,8 +593,7 @@ emit_call_1 (rtx funexp, tree fndecl ATTRIBUTE_UNUSED, tree funtype ATTRIBUTE_UN static int special_function_p (tree fndecl, int flags) { - if (! (flags & ECF_MALLOC) - && fndecl && DECL_NAME (fndecl) + if (fndecl && DECL_NAME (fndecl) && IDENTIFIER_LENGTH (DECL_NAME (fndecl)) <= 17 /* Exclude functions not at the file scope, or not `extern', since they are not the magic functions we would otherwise @@ -652,21 +655,8 @@ special_function_p (tree fndecl, int flags) else if (tname[0] == 'l' && tname[1] == 'o' && ! strcmp (tname, "longjmp")) flags |= ECF_LONGJMP; - - else if ((tname[0] == 'f' && tname[1] == 'o' - && ! strcmp (tname, "fork")) - /* Linux specific: __clone. check NAME to insist on the - leading underscores, to avoid polluting the ISO / POSIX - namespace. */ - || (name[0] == '_' && name[1] == '_' - && ! strcmp (tname, "clone")) - || (tname[0] == 'e' && tname[1] == 'x' && tname[2] == 'e' - && tname[3] == 'c' && (tname[4] == 'l' || tname[4] == 'v') - && (tname[5] == '\0' - || ((tname[5] == 'p' || tname[5] == 'e') - && tname[6] == '\0')))) - flags |= ECF_FORK_OR_EXEC; } + return flags; } @@ -725,10 +715,11 @@ flags_from_decl_or_type (tree exp) flags |= ECF_NOTHROW; if (TREE_READONLY (exp) && ! TREE_THIS_VOLATILE (exp)) - flags |= ECF_LIBCALL_BLOCK; - } + flags |= ECF_LIBCALL_BLOCK | ECF_CONST; - if (TREE_READONLY (exp) && ! TREE_THIS_VOLATILE (exp)) + flags = special_function_p (exp, flags); + } + else if (TYPE_P (exp) && TYPE_READONLY (exp) && ! TREE_THIS_VOLATILE (exp)) flags |= ECF_CONST; if (TREE_THIS_VOLATILE (exp)) @@ -1023,7 +1014,13 @@ store_unaligned_arguments_into_pseudos (struct arg_data *args, int num_actuals) and may be modified by this routine. OLD_PENDING_ADJ, MUST_PREALLOCATE and FLAGS are pointers to integer - flags which may may be modified by this routine. */ + flags which may may be modified by this routine. + + MAY_TAILCALL is cleared if we encounter an invisible pass-by-reference + that requires allocation of stack space. + + CALL_FROM_THUNK_P is true if this call is the jump from a thunk to + the thunked-to function. */ static void initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED, @@ -1034,7 +1031,8 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED, CUMULATIVE_ARGS *args_so_far, int reg_parm_stack_space, rtx *old_stack_level, int *old_pending_adj, - int *must_preallocate, int *ecf_flags) + int *must_preallocate, int *ecf_flags, + bool *may_tailcall, bool call_from_thunk_p) { /* 1 if scanning parms front to back, -1 if scanning back to front. */ int inc; @@ -1107,7 +1105,7 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED, { /* If we're compiling a thunk, pass through invisible references instead of making a copy. */ - if (current_function_is_thunk + if (call_from_thunk_p #ifdef FUNCTION_ARG_CALLEE_COPIES || (FUNCTION_ARG_CALLEE_COPIES (*args_so_far, TYPE_MODE (type), type, argpos < n_named_args) @@ -1147,6 +1145,7 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED, build_pointer_type (type), args[i].tree_value); type = build_pointer_type (type); + *may_tailcall = false; } else { @@ -1186,11 +1185,12 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED, build_pointer_type (type), make_tree (type, copy)); type = build_pointer_type (type); + *may_tailcall = false; } } mode = TYPE_MODE (type); - unsignedp = TREE_UNSIGNED (type); + unsignedp = TYPE_UNSIGNED (type); if (targetm.calls.promote_function_args (fndecl ? TREE_TYPE (fndecl) : 0)) mode = promote_mode (type, mode, &unsignedp, 1); @@ -1344,11 +1344,6 @@ compute_argument_block_size (int reg_parm_stack_space, args_size->constant = MAX (args_size->constant, reg_parm_stack_space); -#ifdef MAYBE_REG_PARM_STACK_SPACE - if (reg_parm_stack_space == 0) - args_size->constant = 0; -#endif - #ifndef OUTGOING_REG_PARM_STACK_SPACE args_size->constant -= reg_parm_stack_space; #endif @@ -1371,20 +1366,16 @@ precompute_arguments (int flags, int num_actuals, struct arg_data *args) { int i; - /* If this function call is cse'able, precompute all the parameters. - Note that if the parameter is constructed into a temporary, this will - cause an additional copy because the parameter will be constructed - into a temporary location and then copied into the outgoing arguments. - If a parameter contains a call to alloca and this function uses the - stack, precompute the parameter. */ - - /* If we preallocated the stack space, and some arguments must be passed - on the stack, then we must precompute any parameter which contains a - function call which will store arguments on the stack. - Otherwise, evaluating the parameter may clobber previous parameters - which have already been stored into the stack. (we have code to avoid - such case by saving the outgoing stack arguments, but it results in - worse code) */ + /* If this is a libcall, then precompute all arguments so that we do not + get extraneous instructions emitted as part of the libcall sequence. + + If this target defines ACCUMULATE_OUTGOING_ARGS to true, then we must + precompute all arguments that contain function calls. Otherwise, + computing arguments for a subcall may clobber arguments for this call. + + If this target defines ACCUMULATE_OUTGOING_ARGS to false, then we only + need to precompute arguments that change the stack pointer, such as calls + to alloca, and calls that do not pop all of their arguments. */ for (i = 0; i < num_actuals; i++) if ((flags & ECF_LIBCALL_BLOCK) @@ -1412,7 +1403,7 @@ precompute_arguments (int flags, int num_actuals, struct arg_data *args) args[i].value = convert_modes (args[i].mode, mode, args[i].value, args[i].unsignedp); -#ifdef PROMOTE_FOR_CALL_ONLY +#if defined(PROMOTE_FUNCTION_MODE) && !defined(PROMOTE_MODE) /* CSE will replace this only if it contains args[i].value pseudo, so convert it down to the declared mode using a SUBREG. */ @@ -1679,10 +1670,14 @@ load_register_parameters (struct arg_data *args, int num_actuals, { rtx mem = validize_mem (args[i].value); -#ifdef BLOCK_REG_PADDING /* Handle a BLKmode that needs shifting. */ if (nregs == 1 && size < UNITS_PER_WORD - && args[i].locate.where_pad == downward) +#ifdef BLOCK_REG_PADDING + && args[i].locate.where_pad == downward +#else + && BYTES_BIG_ENDIAN +#endif + ) { rtx tem = operand_subword_force (mem, 0, args[i].mode); rtx ri = gen_rtx_REG (word_mode, REGNO (reg)); @@ -1697,7 +1692,6 @@ load_register_parameters (struct arg_data *args, int num_actuals, emit_move_insn (ri, x); } else -#endif move_block_to_reg (REGNO (reg), mem, nregs, args[i].mode); } @@ -1720,123 +1714,6 @@ load_register_parameters (struct arg_data *args, int num_actuals, } } -/* Try to integrate function. See expand_inline_function for documentation - about the parameters. */ - -static rtx -try_to_integrate (tree fndecl, tree actparms, rtx target, int ignore, - tree type, rtx structure_value_addr) -{ - rtx temp; - rtx before_call; - int i; - rtx old_stack_level = 0; - int reg_parm_stack_space = 0; - -#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 - - before_call = get_last_insn (); - - timevar_push (TV_INTEGRATION); - - temp = expand_inline_function (fndecl, actparms, target, - ignore, type, - structure_value_addr); - - timevar_pop (TV_INTEGRATION); - - /* If inlining succeeded, return. */ - if (temp != (rtx) (size_t) - 1) - { - if (ACCUMULATE_OUTGOING_ARGS) - { - /* If the outgoing argument list must be preserved, push - the stack before executing the inlined function if it - makes any calls. */ - - i = reg_parm_stack_space; - if (i > highest_outgoing_arg_in_use) - i = highest_outgoing_arg_in_use; - while (--i >= 0 && stack_usage_map[i] == 0) - ; - - if (stack_arg_under_construction || i >= 0) - { - rtx first_insn - = before_call ? NEXT_INSN (before_call) : get_insns (); - rtx insn = NULL_RTX, seq; - - /* Look for a call in the inline function code. - If DECL_SAVED_INSNS (fndecl)->outgoing_args_size is - nonzero then there is a call and it is not necessary - to scan the insns. */ - - if (DECL_SAVED_INSNS (fndecl)->outgoing_args_size == 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. - - Add the stack space reserved for register arguments, if - any, 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. */ - - int adjust = (DECL_SAVED_INSNS (fndecl)->outgoing_args_size - + reg_parm_stack_space); - - start_sequence (); - emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX); - allocate_dynamic_stack_space (GEN_INT (adjust), - NULL_RTX, BITS_PER_UNIT); - seq = get_insns (); - end_sequence (); - emit_insn_before (seq, first_insn); - emit_stack_restore (SAVE_BLOCK, old_stack_level, NULL_RTX); - } - } - } - - /* 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 ("%Jinlining failed in call to '%F'", fndecl, fndecl); - warning ("called from here"); - } - (*lang_hooks.mark_addressable) (fndecl); - return (rtx) (size_t) - 1; -} - /* We need to pop PENDING_STACK_ADJUST bytes. But, if the arguments wouldn't fill up an even multiple of PREFERRED_UNIT_STACK_BOUNDARY bytes, then we would need to push some additional bytes to pad the @@ -2047,6 +1924,69 @@ shift_returned_value (tree type, rtx *value) return false; } +/* Remove all REG_EQUIV notes found in the insn chain. */ + +static void +purge_reg_equiv_notes (void) +{ + rtx insn; + + for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) + { + while (1) + { + rtx note = find_reg_note (insn, REG_EQUIV, 0); + if (note) + { + /* Remove the note and keep looking at the notes for + this insn. */ + remove_note (insn, note); + continue; + } + break; + } + } +} + +/* Clear RTX_UNCHANGING_P flag of incoming argument MEMs. */ + +static void +purge_mem_unchanging_flag (rtx x) +{ + RTX_CODE code; + int i, j; + const char *fmt; + + if (x == NULL_RTX) + return; + + code = GET_CODE (x); + + if (code == MEM) + { + if (RTX_UNCHANGING_P (x) + && (XEXP (x, 0) == current_function_internal_arg_pointer + || (GET_CODE (XEXP (x, 0)) == PLUS + && XEXP (XEXP (x, 0), 0) == + current_function_internal_arg_pointer + && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT))) + RTX_UNCHANGING_P (x) = 0; + return; + } + + /* Scan all subexpressions. */ + fmt = GET_RTX_FORMAT (code); + for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++) + { + if (*fmt == 'e') + purge_mem_unchanging_flag (XEXP (x, i)); + else if (*fmt == 'E') + for (j = 0; j < XVECLEN (x, i); j++) + purge_mem_unchanging_flag (XVECEXP (x, i, j)); + } +} + + /* 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. @@ -2063,11 +2003,9 @@ expand_call (tree exp, rtx target, int ignore) tree actparms = TREE_OPERAND (exp, 1); /* RTX for the function to be called. */ rtx funexp; - /* Sequence of insns to perform a tail recursive "call". */ - rtx tail_recursion_insns = NULL_RTX; /* Sequence of insns to perform a normal "call". */ rtx normal_call_insns = NULL_RTX; - /* Sequence of insns to perform a tail recursive "call". */ + /* Sequence of insns to perform a tail "call". */ rtx tail_call_insns = NULL_RTX; /* Data type of the function. */ tree funtype; @@ -2075,9 +2013,9 @@ expand_call (tree exp, rtx target, int ignore) /* Declaration of the function being called, or 0 if the function is computed (not known by name). */ tree fndecl = 0; - rtx insn; - int try_tail_call = 1; - int try_tail_recursion = 1; + /* The type of the function being called. */ + tree fntype; + bool try_tail_call = CALL_EXPR_TAILCALL (exp); int pass; /* Register in which non-BLKmode value will be returned, @@ -2138,8 +2076,6 @@ expand_call (tree exp, rtx target, int ignore) /* Mask of ECF_ flags. */ int flags = 0; - /* Nonzero if this is a call to an inline function. */ - int is_integrable = 0; #ifdef REG_PARM_STACK_SPACE /* Define the boundary of the register parm stack space that needs to be saved, if any. */ @@ -2148,7 +2084,6 @@ expand_call (tree exp, rtx target, int ignore) #endif int initial_highest_arg_in_use = highest_outgoing_arg_in_use; - rtx temp_target = 0; char *initial_stack_usage_map = stack_usage_map; int old_stack_allocated; @@ -2172,61 +2107,27 @@ expand_call (tree exp, rtx target, int ignore) HOST_WIDE_INT preferred_stack_boundary; /* The alignment of the stack, in bytes. */ HOST_WIDE_INT preferred_unit_stack_boundary; - + /* The static chain value to use for this call. */ + rtx static_chain_value; /* See if this is "nothrow" function call. */ if (TREE_NOTHROW (exp)) flags |= ECF_NOTHROW; - /* 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. */ - + /* See if we can find a DECL-node for the actual function, and get the + function attributes (flags) from the function decl or type node. */ fndecl = get_callee_fndecl (exp); if (fndecl) { - if (!flag_no_inline - && fndecl != current_function_decl - && DECL_INLINE (fndecl) - && DECL_SAVED_INSNS (fndecl) - && DECL_SAVED_INSNS (fndecl)->inlinable) - 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 ("%Jcan't inline call to '%F'", fndecl, fndecl); - warning ("called from here"); - } - (*lang_hooks.mark_addressable) (fndecl); - } - - if (ignore - && lookup_attribute ("warn_unused_result", - TYPE_ATTRIBUTES (TREE_TYPE (fndecl)))) - warning ("ignoring return value of `%D', " - "declared with attribute warn_unused_result", fndecl); - + fntype = TREE_TYPE (fndecl); flags |= flags_from_decl_or_type (fndecl); } - - /* If we don't have specific function to call, see if we have a - attributes set in the type. */ else { - if (ignore - && lookup_attribute ("warn_unused_result", - TYPE_ATTRIBUTES (TREE_TYPE (TREE_TYPE (p))))) - warning ("ignoring return value of function " - "declared with attribute warn_unused_result"); - flags |= flags_from_decl_or_type (TREE_TYPE (TREE_TYPE (p))); + fntype = TREE_TYPE (TREE_TYPE (p)); + flags |= flags_from_decl_or_type (fntype); } - struct_value = targetm.calls.struct_value_rtx (fndecl ? TREE_TYPE (fndecl) : 0, 0); + struct_value = targetm.calls.struct_value_rtx (fntype, 0); /* Warn if this value is an aggregate type, regardless of which calling convention we are using for it. */ @@ -2260,12 +2161,8 @@ expand_call (tree exp, rtx target, int ignore) } #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 #ifndef OUTGOING_REG_PARM_STACK_SPACE if (reg_parm_stack_space > 0 && PUSH_ARGS) @@ -2283,15 +2180,6 @@ expand_call (tree exp, rtx target, int ignore) #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)) - (*lang_hooks.mark_addressable) (fndecl); - is_integrable = 0; - } } #else /* not PCC_STATIC_STRUCT_RETURN */ { @@ -2324,17 +2212,6 @@ expand_call (tree exp, rtx target, int ignore) #endif /* not PCC_STATIC_STRUCT_RETURN */ } - /* If called function is inline, try to integrate it. */ - - if (is_integrable) - { - rtx temp = try_to_integrate (fndecl, actparms, target, - ignore, TREE_TYPE (exp), - structure_value_addr); - if (temp != (rtx) (size_t) - 1) - return temp; - } - /* Figure out the amount to which the stack should be aligned. */ preferred_stack_boundary = PREFERRED_STACK_BOUNDARY; if (fndecl) @@ -2352,7 +2229,7 @@ expand_call (tree exp, rtx target, int ignore) /* Munge the tree to split complex arguments into their imaginary and real parts. */ - if (SPLIT_COMPLEX_ARGS) + if (targetm.calls.split_complex_arg) { type_arg_types = split_complex_types (TYPE_ARG_TYPES (funtype)); actparms = split_complex_values (actparms); @@ -2360,10 +2237,6 @@ expand_call (tree exp, rtx target, int ignore) else type_arg_types = TYPE_ARG_TYPES (funtype); - /* See if this is a call to a function that can return more than once - or a call to longjmp or malloc. */ - flags |= special_function_p (fndecl, flags); - if (flags & ECF_MAY_BE_ALLOCA) current_function_calls_alloca = 1; @@ -2380,7 +2253,8 @@ expand_call (tree exp, rtx target, int ignore) || (ACCUMULATE_OUTGOING_ARGS && stack_arg_under_construction && structure_value_addr == virtual_outgoing_args_rtx) - ? copy_addr_to_reg (structure_value_addr) + ? copy_addr_to_reg (convert_memory_address + (Pmode, structure_value_addr)) : structure_value_addr); actparms @@ -2395,14 +2269,6 @@ expand_call (tree exp, rtx target, int ignore) for (p = actparms, num_actuals = 0; p; p = TREE_CHAIN (p)) num_actuals++; - /* 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); - /* 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 @@ -2434,6 +2300,14 @@ expand_call (tree exp, rtx target, int ignore) /* If we know nothing, treat all args as named. */ n_named_args = num_actuals; + /* 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 fourth 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, n_named_args); + /* Make a vector to hold all the information about each arg. */ args = alloca (num_actuals * sizeof (struct arg_data)); memset (args, 0, num_actuals * sizeof (struct arg_data)); @@ -2444,7 +2318,8 @@ expand_call (tree exp, rtx target, int ignore) n_named_args, actparms, fndecl, &args_so_far, reg_parm_stack_space, &old_stack_level, &old_pending_adj, - &must_preallocate, &flags); + &must_preallocate, &flags, + &try_tail_call, CALL_FROM_THUNK_P (exp)); if (args_size.var) { @@ -2493,14 +2368,9 @@ expand_call (tree exp, rtx target, int ignore) || !rtx_equal_function_value_matters || current_nesting_level () == 0 || any_pending_cleanups () - || args_size.var) - try_tail_call = try_tail_recursion = 0; - - /* Tail recursion fails, when we are not dealing with recursive calls. */ - if (!try_tail_recursion - || TREE_CODE (addr) != ADDR_EXPR - || TREE_OPERAND (addr, 0) != current_function_decl) - try_tail_recursion = 0; + || args_size.var + || lookup_stmt_eh_region (exp) >= 0) + try_tail_call = 0; /* Rest of purposes for tail call optimizations to fail. */ if ( @@ -2517,7 +2387,7 @@ expand_call (tree exp, rtx target, int ignore) || structure_value_addr != NULL_RTX /* Check whether the target is able to optimize the call into a sibcall. */ - || !(*targetm.function_ok_for_sibcall) (fndecl, exp) + || !targetm.function_ok_for_sibcall (fndecl, exp) /* Functions that do not return exactly once may not be sibcall optimized. */ || (flags & (ECF_RETURNS_TWICE | ECF_LONGJMP | ECF_NORETURN)) @@ -2535,10 +2405,10 @@ expand_call (tree exp, rtx target, int ignore) != RETURN_POPS_ARGS (current_function_decl, TREE_TYPE (current_function_decl), current_function_args_size)) - || !(*lang_hooks.decls.ok_for_sibcall) (fndecl)) + || !lang_hooks.decls.ok_for_sibcall (fndecl)) try_tail_call = 0; - if (try_tail_call || try_tail_recursion) + if (try_tail_call) { int end, inc; actparms = NULL_TREE; @@ -2573,11 +2443,6 @@ expand_call (tree exp, rtx target, int ignore) for (; i != end; i += inc) { args[i].tree_value = fix_unsafe_tree (args[i].tree_value); - /* We need to build actparms for optimize_tail_recursion. We can - safely trash away TREE_PURPOSE, since it is unused by this - function. */ - if (try_tail_recursion) - actparms = tree_cons (NULL_TREE, args[i].tree_value, actparms); } /* Do the same for the function address if it is an expression. */ if (!fndecl) @@ -2585,62 +2450,9 @@ expand_call (tree exp, rtx target, int ignore) /* Expanding one of those dangerous arguments could have added cleanups, but otherwise give it a whirl. */ if (any_pending_cleanups ()) - try_tail_call = try_tail_recursion = 0; - } - - /* Generate a tail recursion sequence when calling ourselves. */ - - if (try_tail_recursion) - { - /* We want to emit any pending stack adjustments before the tail - recursion "call". That way we know any adjustment after the tail - recursion call can be ignored if we indeed use the tail recursion - call expansion. */ - int save_pending_stack_adjust = pending_stack_adjust; - int save_stack_pointer_delta = stack_pointer_delta; - - /* Emit any queued insns now; otherwise they would end up in - only one of the alternates. */ - emit_queue (); - - /* Use a new sequence to hold any RTL we generate. We do not even - know if we will use this RTL yet. The final decision can not be - made until after RTL generation for the entire function is - complete. */ - start_sequence (); - /* If expanding any of the arguments creates cleanups, we can't - do a tailcall. So, we'll need to pop the pending cleanups - list. If, however, all goes well, and there are no cleanups - then the call to expand_start_target_temps will have no - effect. */ - expand_start_target_temps (); - if (optimize_tail_recursion (actparms, get_last_insn ())) - { - if (any_pending_cleanups ()) - try_tail_call = try_tail_recursion = 0; - else - tail_recursion_insns = get_insns (); - } - expand_end_target_temps (); - end_sequence (); - - /* Restore the original pending stack adjustment for the sibling and - normal call cases below. */ - pending_stack_adjust = save_pending_stack_adjust; - stack_pointer_delta = save_stack_pointer_delta; + try_tail_call = 0; } - if (profile_arc_flag && (flags & ECF_FORK_OR_EXEC)) - { - /* A fork duplicates the profile information, and an exec discards - it. We can't rely on fork/exec to be paired. So write out the - profile information we have gathered so far, and clear it. */ - /* ??? When Linux's __clone is called with CLONE_VM set, profiling - is subject to race conditions, just as with multithreaded - programs. */ - - emit_library_call (gcov_flush_libfunc, LCT_ALWAYS_RETURN, VOIDmode, 0); - } /* Ensure current function's preferred stack boundary is at least what we need. We don't have to increase alignment for recursive @@ -2663,7 +2475,7 @@ expand_call (tree exp, rtx target, int ignore) int sibcall_failure = 0; /* We want to emit any pending stack adjustments before the tail recursion "call". That way we know any adjustment after the tail - recursion call can be ignored if we indeed use the tail recursion + recursion call can be ignored if we indeed use the tail call expansion. */ int save_pending_stack_adjust = 0; int save_stack_pointer_delta = 0; @@ -2722,10 +2534,6 @@ expand_call (tree exp, rtx target, int ignore) if (pass && (flags & ECF_LIBCALL_BLOCK)) NO_DEFER_POP; -#ifdef FINAL_REG_PARM_STACK_SPACE - reg_parm_stack_space = FINAL_REG_PARM_STACK_SPACE (args_size.constant, - args_size.var); -#endif /* Precompute any arguments as needed. */ if (pass) precompute_arguments (flags, num_actuals, args); @@ -2999,6 +2807,12 @@ expand_call (tree exp, rtx target, int ignore) once we have started filling any specific hard regs. */ precompute_register_parameters (num_actuals, args, ®_parm_seen); + if (TREE_OPERAND (exp, 2)) + static_chain_value = expand_expr (TREE_OPERAND (exp, 2), + NULL_RTX, VOIDmode, 0); + else + static_chain_value = 0; + #ifdef REG_PARM_STACK_SPACE /* Save the fixed argument area if it's part of the caller's frame and is clobbered by argument setup for this call. */ @@ -3089,8 +2903,8 @@ expand_call (tree exp, rtx target, int ignore) use_reg (&call_fusage, struct_value); } - funexp = prepare_call_address (funexp, fndecl, &call_fusage, - reg_parm_seen, pass == 0); + funexp = prepare_call_address (funexp, static_chain_value, + &call_fusage, reg_parm_seen, pass == 0); load_register_parameters (args, num_actuals, &call_fusage, flags, pass == 0, &sibcall_failure); @@ -3121,7 +2935,7 @@ expand_call (tree exp, rtx target, int ignore) abort (); /* Generate the actual call instruction. */ - emit_call_1 (funexp, fndecl, funtype, unadjusted_args_size, + emit_call_1 (funexp, exp, fndecl, funtype, unadjusted_args_size, adjusted_args_size.constant, struct_value_size, next_arg_reg, valreg, old_inhibit_defer_pop, call_fusage, flags, & args_so_far); @@ -3288,11 +3102,7 @@ expand_call (tree exp, rtx target, int ignore) The Irix 6 ABI has examples of this. */ else if (GET_CODE (valreg) == PARALLEL) { - /* Second condition is added because "target" is freed at the - the end of "pass0" for -O2 when call is made to - expand_end_target_temps (). Its "in_use" flag has been set - to false, so allocate a new temp. */ - if (target == 0 || (pass == 1 && target == temp_target)) + if (target == 0) { /* This will only be assigned once, so it can be readonly. */ tree nt = build_qualified_type (TREE_TYPE (exp), @@ -3300,7 +3110,6 @@ expand_call (tree exp, rtx target, int ignore) | TYPE_QUAL_CONST)); target = assign_temp (nt, 0, 1, 1); - temp_target = target; preserve_temp_slots (target); } @@ -3353,7 +3162,7 @@ expand_call (tree exp, rtx target, int ignore) && GET_MODE (target) != TYPE_MODE (TREE_TYPE (exp))) { tree type = TREE_TYPE (exp); - int unsignedp = TREE_UNSIGNED (type); + int unsignedp = TYPE_UNSIGNED (type); int offset = 0; /* If we don't promote as expected, something is wrong. */ @@ -3425,8 +3234,8 @@ expand_call (tree exp, rtx target, int ignore) Check for the handler slots since we might not have a save area for non-local gotos. */ - if ((flags & ECF_MAY_BE_ALLOCA) && nonlocal_goto_handler_slots != 0) - emit_stack_save (SAVE_NONLOCAL, &nonlocal_goto_stack_level, NULL_RTX); + if ((flags & ECF_MAY_BE_ALLOCA) && cfun->nonlocal_goto_save_area != 0) + update_nonlocal_goto_save_area (); /* Free up storage we no longer need. */ for (i = 0; i < num_actuals; ++i) @@ -3495,48 +3304,16 @@ expand_call (tree exp, rtx target, int ignore) zero out the sequence. */ if (sibcall_failure) tail_call_insns = NULL_RTX; + else + break; } - /* The function optimize_sibling_and_tail_recursive_calls doesn't - handle CALL_PLACEHOLDERs inside other CALL_PLACEHOLDERs. This - can happen if the arguments to this function call an inline - function who's expansion contains another CALL_PLACEHOLDER. - - If there are any C_Ps in any of these sequences, replace them - with their normal call. */ - - for (insn = normal_call_insns; insn; insn = NEXT_INSN (insn)) - if (GET_CODE (insn) == CALL_INSN - && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER) - replace_call_placeholder (insn, sibcall_use_normal); - - for (insn = tail_call_insns; insn; insn = NEXT_INSN (insn)) - if (GET_CODE (insn) == CALL_INSN - && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER) - replace_call_placeholder (insn, sibcall_use_normal); - - for (insn = tail_recursion_insns; insn; insn = NEXT_INSN (insn)) - if (GET_CODE (insn) == CALL_INSN - && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER) - replace_call_placeholder (insn, sibcall_use_normal); - - /* If this was a potential tail recursion site, then emit a - CALL_PLACEHOLDER with the normal and the tail recursion streams. - One of them will be selected later. */ - if (tail_recursion_insns || tail_call_insns) + /* If tail call production suceeded, we need to remove REG_EQUIV notes on + arguments too, as argument area is now clobbered by the call. */ + if (tail_call_insns) { - /* The tail recursion label must be kept around. We could expose - its use in the CALL_PLACEHOLDER, but that creates unwanted edges - and makes determining true tail recursion sites difficult. - - So we set LABEL_PRESERVE_P here, then clear it when we select - one of the call sequences after rtl generation is complete. */ - if (tail_recursion_insns) - LABEL_PRESERVE_P (tail_recursion_label) = 1; - emit_call_insn (gen_rtx_CALL_PLACEHOLDER (VOIDmode, normal_call_insns, - tail_call_insns, - tail_recursion_insns, - tail_recursion_label)); + emit_insn (tail_call_insns); + cfun->tail_call_emit = true; } else emit_insn (normal_call_insns); @@ -3549,7 +3326,7 @@ expand_call (tree exp, rtx target, int ignore) if (flags & ECF_SP_DEPRESSED) { clear_pending_stack_adjust (); - emit_insn (gen_rtx (CLOBBER, VOIDmode, stack_pointer_rtx)); + emit_insn (gen_rtx_CLOBBER (VOIDmode, stack_pointer_rtx)); emit_move_insn (virtual_stack_dynamic_rtx, stack_pointer_rtx); save_stack_pointer (); } @@ -3557,6 +3334,47 @@ expand_call (tree exp, rtx target, int ignore) return target; } +/* A sibling call sequence invalidates any REG_EQUIV notes made for + this function's incoming arguments. + + At the start of RTL generation we know the only REG_EQUIV notes + in the rtl chain are those for incoming arguments, so we can safely + flush any REG_EQUIV note. + + This is (slight) overkill. We could keep track of the highest + argument we clobber and be more selective in removing notes, but it + does not seem to be worth the effort. */ +void +fixup_tail_calls (void) +{ + rtx insn; + tree arg; + + purge_reg_equiv_notes (); + + /* A sibling call sequence also may invalidate RTX_UNCHANGING_P + flag of some incoming arguments MEM RTLs, because it can write into + those slots. We clear all those bits now. + + This is (slight) overkill, we could keep track of which arguments + we actually write into. */ + for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) + { + if (INSN_P (insn)) + purge_mem_unchanging_flag (PATTERN (insn)); + } + + /* Similarly, invalidate RTX_UNCHANGING_P for any incoming + arguments passed in registers. */ + for (arg = DECL_ARGUMENTS (current_function_decl); + arg; + arg = TREE_CHAIN (arg)) + { + if (REG_P (DECL_RTL (arg))) + RTX_UNCHANGING_P (DECL_RTL (arg)) = false; + } +} + /* Traverse an argument list in VALUES and expand all complex arguments into their components. */ tree @@ -3564,6 +3382,17 @@ split_complex_values (tree values) { tree p; + /* Before allocating memory, check for the common case of no complex. */ + for (p = values; p; p = TREE_CHAIN (p)) + { + tree type = TREE_TYPE (TREE_VALUE (p)); + if (type && TREE_CODE (type) == COMPLEX_TYPE + && targetm.calls.split_complex_arg (type)) + goto found; + } + return values; + + found: values = copy_list (values); for (p = values; p; p = TREE_CHAIN (p)) @@ -3575,7 +3404,8 @@ split_complex_values (tree values) if (!complex_type) continue; - if (TREE_CODE (complex_type) == COMPLEX_TYPE) + if (TREE_CODE (complex_type) == COMPLEX_TYPE + && targetm.calls.split_complex_arg (complex_type)) { tree subtype; tree real, imag, next; @@ -3606,13 +3436,25 @@ split_complex_types (tree types) { tree p; + /* Before allocating memory, check for the common case of no complex. */ + for (p = types; p; p = TREE_CHAIN (p)) + { + tree type = TREE_VALUE (p); + if (TREE_CODE (type) == COMPLEX_TYPE + && targetm.calls.split_complex_arg (type)) + goto found; + } + return types; + + found: types = copy_list (types); for (p = types; p; p = TREE_CHAIN (p)) { tree complex_type = TREE_VALUE (p); - if (TREE_CODE (complex_type) == COMPLEX_TYPE) + if (TREE_CODE (complex_type) == COMPLEX_TYPE + && targetm.calls.split_complex_arg (complex_type)) { tree next, imag; @@ -3688,12 +3530,8 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, rtx struct_value = targetm.calls.struct_value_rtx (0, 0); #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 ((tree) 0); #endif -#endif /* By default, library functions can not throw. */ flags = ECF_NOTHROW; @@ -3738,7 +3576,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, decide where in memory it should come back. */ if (outmode != VOIDmode) { - tfom = (*lang_hooks.types.type_for_mode) (outmode, 0); + tfom = lang_hooks.types.type_for_mode (outmode, 0); if (aggregate_value_p (tfom, 0)) { #ifdef PCC_STATIC_STRUCT_RETURN @@ -3777,7 +3615,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, #ifdef INIT_CUMULATIVE_LIBCALL_ARGS INIT_CUMULATIVE_LIBCALL_ARGS (args_so_far, outmode, fun); #else - INIT_CUMULATIVE_ARGS (args_so_far, NULL_TREE, fun, 0); + INIT_CUMULATIVE_ARGS (args_so_far, NULL_TREE, fun, 0, nargs); #endif args_size.constant = 0; @@ -3883,13 +3721,13 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, slot = val; else if (must_copy) { - slot = assign_temp ((*lang_hooks.types.type_for_mode) (mode, 0), + slot = assign_temp (lang_hooks.types.type_for_mode (mode, 0), 0, 1, 1); emit_move_insn (slot, val); } else { - tree type = (*lang_hooks.types.type_for_mode) (mode, 0); + tree type = lang_hooks.types.type_for_mode (mode, 0); slot = gen_rtx_MEM (mode, @@ -3944,10 +3782,6 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, FUNCTION_ARG_ADVANCE (args_so_far, mode, (tree) 0, 1); } -#ifdef FINAL_REG_PARM_STACK_SPACE - reg_parm_stack_space = FINAL_REG_PARM_STACK_SPACE (args_size.constant, - args_size.var); -#endif /* If this machine requires an external definition for library functions, write one out. */ assemble_external_libcall (fun); @@ -4152,7 +3986,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, else argnum = 0; - fun = prepare_call_address (fun, NULL_TREE, &call_fusage, 0, 0); + fun = prepare_call_address (fun, NULL, &call_fusage, 0, 0); /* Now load any reg parms into their regs. */ @@ -4214,7 +4048,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, always signed. We also assume that the list of arguments passed has no impact, so we pretend it is unknown. */ - emit_call_1 (fun, + emit_call_1 (fun, NULL, get_identifier (XSTR (orgfun, 0)), build_function_type (tfom, NULL_TREE), original_args_size.constant, args_size.constant,