X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fcalls.c;h=2cc15fc2e819e7087158258cddff0ffbc296354f;hb=1a788acdc36ef26e2222ab82bfb4c5ce3cb7bd09;hp=bd889e1ae71537f4b07377202598ac21c506f70c;hpb=95cedffb7229d00b1fe6f7943139ff8c6d2bf0b4;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/calls.c b/gcc/calls.c index bd889e1ae71..2cc15fc2e81 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -1,6 +1,7 @@ /* Convert function calls to rtl insns, for GNU C compiler. - Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998 - 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, + 1999, 2000, 2001, 2002, 2003, 2004, 2005 + Free Software Foundation, Inc. This file is part of GCC. @@ -16,8 +17,8 @@ for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ +Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. */ #include "config.h" #include "system.h" @@ -27,6 +28,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "tree.h" #include "flags.h" #include "expr.h" +#include "optabs.h" #include "libfuncs.h" #include "function.h" #include "regs.h" @@ -40,30 +42,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "cgraph.h" #include "except.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 - -#ifndef PUSH_ARGS_REVERSED -#if defined (STACK_GROWS_DOWNWARD) != defined (ARGS_GROW_DOWNWARD) -#define PUSH_ARGS_REVERSED PUSH_ARGS -#endif -#endif - -#endif - -#ifndef PUSH_ARGS_REVERSED -#define PUSH_ARGS_REVERSED 0 -#endif - -#ifndef STACK_POINTER_OFFSET -#define STACK_POINTER_OFFSET 0 -#endif - /* Like PREFERRED_STACK_BOUNDARY but in units of bytes, not bits. */ #define STACK_BYTES (PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT) @@ -87,27 +65,22 @@ struct arg_data This is not the same register as for normal calls on machines with register windows. */ rtx tail_call_reg; + /* If REG is a PARALLEL, this is a copy of VALUE pulled into the correct + form for emit_group_move. */ + rtx parallel_value; /* 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. */ + /* Number of bytes to put in registers. 0 means put the whole arg + in registers. Also 0 if not passed in registers. */ int partial; /* Nonzero 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; + /* Some fields packaged up for locate_and_pad_parm. */ + struct locate_and_pad_arg_data locate; /* Location on the stack at which parameter should be stored. The store has already been done if STACK == VALUE. */ rtx stack; @@ -123,9 +96,6 @@ struct arg_data word-sized pseudos we made. */ rtx *aligned_regs; int n_aligned_regs; - /* The amount that the stack pointer needs to be adjusted to - force alignment for the next argument. */ - struct args_size alignment_pad; }; /* A vector of one char per byte of stack space. A byte if nonzero if @@ -149,183 +119,43 @@ static sbitmap stored_args_map; 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; - -static int calls_function PARAMS ((tree, int)); -static int calls_function_1 PARAMS ((tree, int)); - -static void emit_call_1 PARAMS ((rtx, tree, tree, HOST_WIDE_INT, - HOST_WIDE_INT, HOST_WIDE_INT, rtx, - rtx, int, rtx, int, - CUMULATIVE_ARGS *)); -static void precompute_register_parameters PARAMS ((int, - struct arg_data *, - int *)); -static int store_one_arg PARAMS ((struct arg_data *, rtx, int, int, - int)); -static void store_unaligned_arguments_into_pseudos PARAMS ((struct arg_data *, - int)); -static int finalize_must_preallocate PARAMS ((int, int, - struct arg_data *, - struct args_size *)); -static void precompute_arguments PARAMS ((int, int, - struct arg_data *)); -static int compute_argument_block_size PARAMS ((int, - struct args_size *, - int)); -static void initialize_argument_information PARAMS ((int, - struct arg_data *, - struct args_size *, - int, tree, tree, - CUMULATIVE_ARGS *, - int, rtx *, int *, - int *, int *)); -static void compute_argument_addresses PARAMS ((struct arg_data *, - rtx, int)); -static rtx rtx_for_function_call PARAMS ((tree, tree)); -static void load_register_parameters PARAMS ((struct arg_data *, - int, rtx *, int, - int, int *)); -static rtx emit_library_call_value_1 PARAMS ((int, rtx, rtx, - enum libcall_type, - enum machine_mode, - int, va_list)); -static int special_function_p PARAMS ((tree, int)); -static rtx try_to_integrate PARAMS ((tree, tree, rtx, - int, tree, rtx)); -static int check_sibcall_argument_overlap_1 PARAMS ((rtx)); -static int check_sibcall_argument_overlap PARAMS ((rtx, struct arg_data *, - int)); - -static int combine_pending_stack_adjustment_and_call - PARAMS ((int, struct args_size *, int)); -static tree fix_unsafe_tree PARAMS ((tree)); +static int stack_arg_under_construction; + +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 *); +static int store_one_arg (struct arg_data *, rtx, int, int, int); +static void store_unaligned_arguments_into_pseudos (struct arg_data *, int); +static int finalize_must_preallocate (int, int, struct arg_data *, + struct args_size *); +static void precompute_arguments (int, int, struct arg_data *); +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 *, + 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, + int, 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 int check_sibcall_argument_overlap_1 (rtx); +static int check_sibcall_argument_overlap (rtx, struct arg_data *, int); + +static int combine_pending_stack_adjustment_and_call (int, struct args_size *, + unsigned int); +static tree split_complex_values (tree); +static tree split_complex_types (tree); #ifdef REG_PARM_STACK_SPACE -static rtx save_fixed_argument_area PARAMS ((int, rtx, int *, int *)); -static void restore_fixed_argument_area PARAMS ((rtx, rtx, int, int)); +static rtx save_fixed_argument_area (int, rtx, int *, int *); +static void restore_fixed_argument_area (rtx, rtx, int, int); #endif -/* 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 int -calls_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; -} - -/* Recursive function to do the work of above function. */ - -static int -calls_function_1 (exp, which) - tree exp; - int which; -{ - int i; - enum tree_code code = TREE_CODE (exp); - int class = TREE_CODE_CLASS (code); - int length = first_rtl_op (code); - - /* If this code is language-specific, we don't know what it will do. */ - if ((int) code >= NUM_TREE_CODES) - return 1; - - switch (code) - { - case CALL_EXPR: - if (which == 0) - return 1; - else if ((TREE_CODE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0)))) - == FUNCTION_TYPE) - && (TYPE_RETURNS_STACK_DEPRESSED - (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0)))))) - return 1; - else if (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR - && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)) - == FUNCTION_DECL) - && (special_function_p (TREE_OPERAND (TREE_OPERAND (exp, 0), 0), - 0) - & ECF_MAY_BE_ALLOCA)) - return 1; - - break; - - case CONSTRUCTOR: - { - tree tem; - - for (tem = CONSTRUCTOR_ELTS (exp); tem != 0; tem = TREE_CHAIN (tem)) - if (calls_function_1 (TREE_VALUE (tem), which)) - return 1; - } - - return 0; - - 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: - { - tree local; - tree subblock; - - for (local = BLOCK_VARS (exp); local; local = TREE_CHAIN (local)) - if (DECL_INITIAL (local) != 0 - && calls_function_1 (DECL_INITIAL (local), which)) - return 1; - - for (subblock = BLOCK_SUBBLOCKS (exp); - subblock; - subblock = TREE_CHAIN (subblock)) - if (calls_function_1 (subblock, which)) - return 1; - } - return 0; - - case TREE_LIST: - for (; exp != 0; exp = TREE_CHAIN (exp)) - if (calls_function_1 (TREE_VALUE (exp), which)) - return 1; - return 0; - - default: - break; - } - - /* Only expressions, references, and blocks can contain calls. */ - if (! IS_EXPR_CODE_CLASS (class) && class != 'r' && class != 'b') - 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. @@ -334,22 +164,10 @@ calls_function_1 (exp, which) CALL_INSN_FUNCTION_USAGE information. */ rtx -prepare_call_address (funexp, fndecl, call_fusage, reg_parm_seen, sibcallp) - 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 thru pseudo-regs, + /* 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) /* If we are using registers for parameters, force the @@ -361,18 +179,16 @@ prepare_call_address (funexp, fndecl, call_fusage, reg_parm_seen, sibcallp) { #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); + funexp = force_reg (Pmode, funexp); #endif } if (static_chain_value != 0) { + static_chain_value = convert_memory_address (Pmode, static_chain_value); emit_move_insn (static_chain_rtx, static_chain_value); - if (GET_CODE (static_chain_rtx) == REG) + if (REG_P (static_chain_rtx)) use_reg (call_fusage, static_chain_rtx); } @@ -420,21 +236,14 @@ prepare_call_address (funexp, fndecl, call_fusage, reg_parm_seen, sibcallp) denote registers used by the called function. */ static void -emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size, - struct_value_size, next_arg_reg, valreg, old_inhibit_defer_pop, - call_fusage, ecf_flags, args_so_far) - rtx funexp; - 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; - rtx next_arg_reg ATTRIBUTE_UNUSED; - rtx valreg; - int old_inhibit_defer_pop; - rtx call_fusage; - int ecf_flags; - CUMULATIVE_ARGS *args_so_far 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, + rtx next_arg_reg ATTRIBUTE_UNUSED, rtx valreg, + int old_inhibit_defer_pop, rtx call_fusage, int ecf_flags, + CUMULATIVE_ARGS *args_so_far ATTRIBUTE_UNUSED) { rtx rounded_stack_size_rtx = GEN_INT (rounded_stack_size); rtx call_insn; @@ -448,7 +257,7 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size, #ifdef CALL_POPS_ARGS n_popped += CALL_POPS_ARGS (* args_so_far); #endif - + /* 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. */ @@ -545,16 +354,10 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size, } 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)) - ; + gcc_unreachable (); - if (! call_insn) - abort (); + /* Find the call we just emitted. */ + call_insn = last_call_insn (); /* Mark memory as used for "pure" function call. */ if (ecf_flags & ECF_PURE) @@ -565,20 +368,8 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size, gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (VOIDmode))), call_fusage); - /* 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; + /* Put the register usage information there. */ + add_function_usage_to (call_insn, call_fusage); /* If this is a const call, then set the insn's unchanging bit. */ if (ecf_flags & (ECF_CONST | ECF_PURE)) @@ -590,14 +381,20 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size, 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, REG_NOTES (call_insn)); - if (ecf_flags & ECF_ALWAYS_RETURN) - REG_NOTES (call_insn) = gen_rtx_EXPR_LIST (REG_ALWAYS_RETURN, const0_rtx, - REG_NOTES (call_insn)); if (ecf_flags & ECF_RETURNS_TWICE) { @@ -635,7 +432,7 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size, if (rounded_stack_size != 0) { - if (ecf_flags & ECF_SP_DEPRESSED) + if (ecf_flags & (ECF_SP_DEPRESSED | ECF_NORETURN)) /* Just pretend we did the pop. */ stack_pointer_delta -= rounded_stack_size; else if (flag_defer_pop && inhibit_defer_pop == 0 @@ -666,23 +463,26 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size, For example, if the function might return more than one time (setjmp), then set RETURNS_TWICE to a nonzero value. - Similarly set LONGJMP for if the function is in the longjmp family. + Similarly set NORETURN if the function is in the longjmp family. Set MAY_BE_ALLOCA for any memory allocation function that might allocate space from the stack such as alloca. */ static int -special_function_p (fndecl, flags) - tree fndecl; - int flags; +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 - think they are. */ - && DECL_CONTEXT (fndecl) == NULL_TREE && TREE_PUBLIC (fndecl)) + think they are. + FIXME: this should be handled with attributes, not with this + hacky imitation of DECL_ASSEMBLER_NAME. It's (also) wrong + because you can declare fork() inside a function if you + wish. */ + && (DECL_CONTEXT (fndecl) == NULL_TREE + || TREE_CODE (DECL_CONTEXT (fndecl)) == TRANSLATION_UNIT_DECL) + && TREE_PUBLIC (fndecl)) { const char *name = IDENTIFIER_POINTER (DECL_NAME (fndecl)); const char *tname = name; @@ -722,48 +522,35 @@ special_function_p (fndecl, flags) if (tname[1] == 'i' && ! strcmp (tname, "siglongjmp")) - flags |= ECF_LONGJMP; + flags |= ECF_NORETURN; } else if ((tname[0] == 'q' && tname[1] == 's' && ! strcmp (tname, "qsetjmp")) || (tname[0] == 'v' && tname[1] == 'f' - && ! strcmp (tname, "vfork"))) + && ! strcmp (tname, "vfork")) + || (tname[0] == 'g' && tname[1] == 'e' + && !strcmp (tname, "getcontext"))) flags |= ECF_RETURNS_TWICE; 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; + flags |= ECF_NORETURN; } + return flags; } -/* Return nonzero when tree represent call to longjmp. */ +/* Return nonzero when FNDECL represents a call to setjmp. */ int -setjmp_call_p (fndecl) - tree fndecl; +setjmp_call_p (tree fndecl) { return special_function_p (fndecl, 0) & ECF_RETURNS_TWICE; } /* Return true when exp contains alloca call. */ bool -alloca_call_p (exp) - tree exp; +alloca_call_p (tree exp) { if (TREE_CODE (exp) == CALL_EXPR && TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR @@ -778,39 +565,40 @@ alloca_call_p (exp) /* Detect flags (function attributes) from the function decl or type node. */ int -flags_from_decl_or_type (exp) - tree exp; +flags_from_decl_or_type (tree exp) { int flags = 0; tree type = exp; if (DECL_P (exp)) { - struct cgraph_rtl_info *i = cgraph_rtl_info (exp); type = TREE_TYPE (exp); - if (i) - { - if (i->pure_function) - flags |= ECF_PURE | ECF_LIBCALL_BLOCK; - if (i->const_function) - flags |= ECF_CONST | ECF_LIBCALL_BLOCK; - } - /* The function exp may have the `malloc' attribute. */ if (DECL_IS_MALLOC (exp)) flags |= ECF_MALLOC; + /* The function exp may have the `returns_twice' attribute. */ + if (DECL_IS_RETURNS_TWICE (exp)) + flags |= ECF_RETURNS_TWICE; + /* The function exp may have the `pure' attribute. */ if (DECL_IS_PURE (exp)) - flags |= ECF_PURE | ECF_LIBCALL_BLOCK; + flags |= ECF_PURE; + + if (DECL_IS_NOVOPS (exp)) + flags |= ECF_NOVOPS; if (TREE_NOTHROW (exp)) flags |= ECF_NOTHROW; - } - if (TREE_READONLY (exp) && ! TREE_THIS_VOLATILE (exp)) - flags |= ECF_CONST | ECF_LIBCALL_BLOCK; + if (TREE_READONLY (exp) && ! TREE_THIS_VOLATILE (exp)) + flags |= ECF_CONST; + + 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)) flags |= ECF_NORETURN; @@ -820,7 +608,29 @@ flags_from_decl_or_type (exp) if (TREE_CODE (type) == FUNCTION_TYPE && TYPE_RETURNS_STACK_DEPRESSED (type)) { flags |= ECF_SP_DEPRESSED; - flags &= ~(ECF_PURE | ECF_CONST | ECF_LIBCALL_BLOCK); + flags &= ~(ECF_PURE | ECF_CONST); + } + + return flags; +} + +/* Detect flags from a CALL_EXPR. */ + +int +call_expr_flags (tree t) +{ + int flags; + tree decl = get_callee_fndecl (t); + + if (decl) + flags = flags_from_decl_or_type (decl); + else + { + t = TREE_TYPE (TREE_OPERAND (t, 0)); + if (t && TREE_CODE (t) == POINTER_TYPE) + flags = flags_from_decl_or_type (TREE_TYPE (t)); + else + flags = 0; } return flags; @@ -834,10 +644,8 @@ flags_from_decl_or_type (exp) Set REG_PARM_SEEN if we encounter a register parameter. */ static void -precompute_register_parameters (num_actuals, args, reg_parm_seen) - int num_actuals; - struct arg_data *args; - int *reg_parm_seen; +precompute_register_parameters (int num_actuals, struct arg_data *args, + int *reg_parm_seen) { int i; @@ -855,10 +663,6 @@ precompute_register_parameters (num_actuals, args, reg_parm_seen) VOIDmode, 0); preserve_temp_slots (args[i].value); pop_temp_slots (); - - /* ANSI doesn't require a sequence point here, - but PCC has one, so this will avoid some problems. */ - emit_queue (); } /* If the value is a non-legitimate constant, force it into a @@ -876,6 +680,17 @@ precompute_register_parameters (num_actuals, args, reg_parm_seen) TYPE_MODE (TREE_TYPE (args[i].tree_value)), args[i].value, args[i].unsignedp); + /* If we're going to have to load the value by parts, pull the + parts into pseudos. The part extraction process can involve + non-trivial computation. */ + if (GET_CODE (args[i].reg) == PARALLEL) + { + tree type = TREE_TYPE (args[i].tree_value); + args[i].parallel_value + = emit_group_load_into_temps (args[i].reg, args[i].value, + type, int_size_in_bytes (type)); + } + /* If the value is expensive, and we are inside an appropriately short loop, put the value into a pseudo and then put the pseudo into the hard reg. @@ -884,13 +699,13 @@ precompute_register_parameters (num_actuals, args, reg_parm_seen) register parameters. This is to avoid reload conflicts while loading the parameters registers. */ - if ((! (GET_CODE (args[i].value) == REG - || (GET_CODE (args[i].value) == SUBREG - && GET_CODE (SUBREG_REG (args[i].value)) == REG))) - && args[i].mode != BLKmode - && rtx_cost (args[i].value, SET) > COSTS_N_INSNS (1) - && ((SMALL_REGISTER_CLASSES && *reg_parm_seen) - || preserve_subexpressions_p ())) + else if ((! (REG_P (args[i].value) + || (GET_CODE (args[i].value) == SUBREG + && REG_P (SUBREG_REG (args[i].value))))) + && args[i].mode != BLKmode + && rtx_cost (args[i].value, SET) > COSTS_N_INSNS (1) + && ((SMALL_REGISTER_CLASSES && *reg_parm_seen) + || optimize)) args[i].value = copy_to_mode_reg (args[i].mode, args[i].value); } } @@ -902,12 +717,7 @@ precompute_register_parameters (num_actuals, args, reg_parm_seen) parameters, we must save and restore it. */ static rtx -save_fixed_argument_area (reg_parm_stack_space, argblock, - low_to_save, high_to_save) - int reg_parm_stack_space; - rtx argblock; - int *low_to_save; - int *high_to_save; +save_fixed_argument_area (int reg_parm_stack_space, rtx argblock, int *low_to_save, int *high_to_save) { int low; int high; @@ -974,11 +784,7 @@ save_fixed_argument_area (reg_parm_stack_space, argblock, } static void -restore_fixed_argument_area (save_area, argblock, high_to_save, low_to_save) - rtx save_area; - rtx argblock; - int high_to_save; - int low_to_save; +restore_fixed_argument_area (rtx save_area, rtx argblock, int high_to_save, int low_to_save) { enum machine_mode save_mode = GET_MODE (save_area); int delta; @@ -1013,9 +819,7 @@ restore_fixed_argument_area (save_area, argblock, high_to_save, low_to_save) the aligned_regs array if it is nonzero. */ static void -store_unaligned_arguments_into_pseudos (args, num_actuals) - struct arg_data *args; - int num_actuals; +store_unaligned_arguments_into_pseudos (struct arg_data *args, int num_actuals) { int i, j; @@ -1026,22 +830,35 @@ store_unaligned_arguments_into_pseudos (args, num_actuals) < (unsigned int) MIN (BIGGEST_ALIGNMENT, BITS_PER_WORD))) { int bytes = int_size_in_bytes (TREE_TYPE (args[i].tree_value)); - int big_endian_correction = 0; + int endian_correction = 0; - args[i].n_aligned_regs - = args[i].partial ? args[i].partial - : (bytes + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD; + if (args[i].partial) + { + gcc_assert (args[i].partial % UNITS_PER_WORD == 0); + args[i].n_aligned_regs = args[i].partial / UNITS_PER_WORD; + } + else + { + args[i].n_aligned_regs + = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD; + } - args[i].aligned_regs = (rtx *) xmalloc (sizeof (rtx) - * args[i].n_aligned_regs); + args[i].aligned_regs = xmalloc (sizeof (rtx) * args[i].n_aligned_regs); - /* Structures smaller than a word are aligned to the least - significant byte (to the right). On a BYTES_BIG_ENDIAN machine, + /* Structures smaller than a word are normally aligned to the + least significant byte. On a BYTES_BIG_ENDIAN machine, this means we must skip the empty high order bytes when calculating the bit offset. */ - if (BYTES_BIG_ENDIAN - && bytes < UNITS_PER_WORD) - big_endian_correction = (BITS_PER_WORD - (bytes * BITS_PER_UNIT)); + if (bytes < UNITS_PER_WORD +#ifdef BLOCK_REG_PADDING + && (BLOCK_REG_PADDING (args[i].mode, + TREE_TYPE (args[i].tree_value), 1) + == downward) +#else + && BYTES_BIG_ENDIAN +#endif + ) + endian_correction = BITS_PER_WORD - bytes * BITS_PER_UNIT; for (j = 0; j < args[i].n_aligned_regs; j++) { @@ -1050,6 +867,8 @@ store_unaligned_arguments_into_pseudos (args, num_actuals) int bitsize = MIN (bytes * BITS_PER_UNIT, BITS_PER_WORD); args[i].aligned_regs[j] = reg; + word = extract_bit_field (word, bitsize, 0, 1, NULL_RTX, + word_mode, word_mode); /* There is no need to restrict this code to loading items in TYPE_ALIGN sized hunks. The bitfield instructions can @@ -1065,11 +884,8 @@ store_unaligned_arguments_into_pseudos (args, num_actuals) emit_move_insn (reg, const0_rtx); bytes -= bitsize / BITS_PER_UNIT; - store_bit_field (reg, bitsize, big_endian_correction, word_mode, - extract_bit_field (word, bitsize, 0, 1, NULL_RTX, - word_mode, word_mode, - BITS_PER_WORD), - BITS_PER_WORD); + store_bit_field (reg, bitsize, endian_correction, word_mode, + word); } } } @@ -1093,26 +909,25 @@ store_unaligned_arguments_into_pseudos (args, 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 (num_actuals, args, args_size, n_named_args, - actparms, fndecl, args_so_far, - reg_parm_stack_space, old_stack_level, - old_pending_adj, must_preallocate, - ecf_flags) - int num_actuals ATTRIBUTE_UNUSED; - struct arg_data *args; - struct args_size *args_size; - int n_named_args ATTRIBUTE_UNUSED; - tree actparms; - tree fndecl; - CUMULATIVE_ARGS *args_so_far; - int reg_parm_stack_space; - rtx *old_stack_level; - int *old_pending_adj; - int *must_preallocate; - int *ecf_flags; +initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED, + struct arg_data *args, + struct args_size *args_size, + int n_named_args ATTRIBUTE_UNUSED, + tree actparms, tree fndecl, + CUMULATIVE_ARGS *args_so_far, + int reg_parm_stack_space, + rtx *old_stack_level, int *old_pending_adj, + 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; @@ -1120,7 +935,6 @@ initialize_argument_information (num_actuals, args, args_size, n_named_args, /* Count arg position in order args appear. */ int argpos; - struct args_size alignment_pad; int i; tree p; @@ -1166,7 +980,7 @@ initialize_argument_information (num_actuals, args, args_size, n_named_args, 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. + and the exact value says how many bytes 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 @@ -1176,57 +990,33 @@ initialize_argument_information (num_actuals, args, args_size, n_named_args, 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 (pass_by_reference (args_so_far, TYPE_MODE (type), + type, argpos < n_named_args)) { - /* 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 - ) + bool callee_copies; + tree base; + + callee_copies + = reference_callee_copied (args_so_far, TYPE_MODE (type), + type, argpos < n_named_args); + + /* If we're compiling a thunk, pass through invisible references + instead of making a copy. */ + if (call_from_thunk_p + || (callee_copies + && !TREE_ADDRESSABLE (type) + && (base = get_base_address (args[i].tree_value)) + && (!DECL_P (base) || MEM_P (DECL_RTL (base))))) { - /* C++ uses a TARGET_EXPR to indicate that we want to make a - new object from the argument. If we are passing by - invisible reference, the callee will do that for us, so we - can strip off the TARGET_EXPR. This is not always safe, - but it is safe in the only case where this is a useful - optimization; namely, when the argument is a plain object. - In that case, the frontend is just asking the backend to - make a bitwise copy of the argument. */ - - if (TREE_CODE (args[i].tree_value) == TARGET_EXPR - && (DECL_P (TREE_OPERAND (args[i].tree_value, 1))) - && ! REG_P (DECL_RTL (TREE_OPERAND (args[i].tree_value, 1)))) - args[i].tree_value = TREE_OPERAND (args[i].tree_value, 1); - - args[i].tree_value = build1 (ADDR_EXPR, - build_pointer_type (type), - args[i].tree_value); - type = build_pointer_type (type); - } - else if (TREE_CODE (args[i].tree_value) == TARGET_EXPR) - { - /* In the V3 C++ ABI, parameters are destroyed in the caller. - We implement this by passing the address of the temporary - rather than expanding it into another allocated slot. */ - args[i].tree_value = build1 (ADDR_EXPR, - build_pointer_type (type), - args[i].tree_value); - type = build_pointer_type (type); + /* We can't use sibcalls if a callee-copied argument is + stored in the current function's frame. */ + if (!call_from_thunk_p && DECL_P (base) && !TREE_STATIC (base)) + *may_tailcall = false; + + args[i].tree_value = build_fold_addr_expr (args[i].tree_value); + type = TREE_TYPE (args[i].tree_value); + + *ecf_flags &= ~(ECF_CONST | ECF_LIBCALL_BLOCK); } else { @@ -1260,21 +1050,24 @@ initialize_argument_information (num_actuals, args, args_size, n_named_args, copy = assign_temp (type, 0, 1, 0); store_expr (args[i].tree_value, copy, 0); - *ecf_flags &= ~(ECF_CONST | ECF_PURE | ECF_LIBCALL_BLOCK); - args[i].tree_value = build1 (ADDR_EXPR, - build_pointer_type (type), - make_tree (type, copy)); - type = build_pointer_type (type); + if (callee_copies) + *ecf_flags &= ~(ECF_CONST | ECF_LIBCALL_BLOCK); + else + *ecf_flags &= ~(ECF_CONST | ECF_PURE | ECF_LIBCALL_BLOCK); + + args[i].tree_value + = build_fold_addr_expr (make_tree (type, copy)); + type = TREE_TYPE (args[i].tree_value); + *may_tailcall = false; } } mode = TYPE_MODE (type); - unsignedp = TREE_UNSIGNED (type); + unsignedp = TYPE_UNSIGNED (type); -#ifdef PROMOTE_FUNCTION_ARGS - mode = promote_mode (type, mode, &unsignedp, 1); -#endif + if (targetm.calls.promote_function_args (fndecl ? TREE_TYPE (fndecl) : 0)) + mode = promote_mode (type, mode, &unsignedp, 1); args[i].unsignedp = unsignedp; args[i].mode = mode; @@ -1291,14 +1084,12 @@ initialize_argument_information (num_actuals, args, args_size, n_named_args, args[i].tail_call_reg = args[i].reg; #endif -#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 + = targetm.calls.arg_partial_bytes (args_so_far, mode, type, + argpos < n_named_args); - args[i].pass_on_stack = MUST_PASS_IN_STACK (mode, type); + args[i].pass_on_stack = targetm.calls.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 @@ -1331,39 +1122,22 @@ initialize_argument_information (num_actuals, args, args_size, n_named_args, #else args[i].reg != 0, #endif - fndecl, args_size, &args[i].offset, - &args[i].size, &alignment_pad); - -#ifndef ARGS_GROW_DOWNWARD - args[i].slot_offset = *args_size; + args[i].pass_on_stack ? 0 : args[i].partial, + fndecl, args_size, &args[i].locate); +#ifdef BLOCK_REG_PADDING + else + /* The argument is passed entirely in registers. See at which + end it should be padded. */ + args[i].locate.where_pad = + BLOCK_REG_PADDING (mode, type, + int_size_in_bytes (type) <= UNITS_PER_WORD); #endif - args[i].alignment_pad = alignment_pad; - - /* If a part of the arg was put into registers, - don't include that part in the amount pushed. */ - if (reg_parm_stack_space == 0 && ! 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)); - /* Update ARGS_SIZE, the total stack space for args so far. */ - args_size->constant += args[i].size.constant; - if (args[i].size.var) - { - ADD_PARM_SIZE (*args_size, args[i].size.var); - } - - /* Since the slot offset points to the bottom of the slot, - we must record it after incrementing if the args grow down. */ -#ifdef ARGS_GROW_DOWNWARD - args[i].slot_offset = *args_size; - - args[i].slot_offset.constant = -args_size->constant; - if (args_size->var) - SUB_PARM_SIZE (args[i].slot_offset, args_size->var); -#endif + args_size->constant += args[i].locate.size.constant; + if (args[i].locate.size.var) + ADD_PARM_SIZE (*args_size, args[i].locate.size.var); /* Increment ARGS_SO_FAR, which has info about which arg-registers have been used, etc. */ @@ -1380,11 +1154,9 @@ initialize_argument_information (num_actuals, args, args_size, n_named_args, for arguments passed in registers. */ static int -compute_argument_block_size (reg_parm_stack_space, args_size, - preferred_stack_boundary) - int reg_parm_stack_space; - struct args_size *args_size; - int preferred_stack_boundary ATTRIBUTE_UNUSED; +compute_argument_block_size (int reg_parm_stack_space, + struct args_size *args_size, + int preferred_stack_boundary ATTRIBUTE_UNUSED) { int unadjusted_args_size = args_size->constant; @@ -1409,8 +1181,7 @@ compute_argument_block_size (reg_parm_stack_space, args_size, /* We don't handle this case yet. To handle it correctly we have to add the delta, round and subtract the delta. Currently no machine description requires this support. */ - if (stack_pointer_delta & (preferred_stack_boundary - 1)) - abort (); + gcc_assert (!(stack_pointer_delta & (preferred_stack_boundary - 1))); args_size->var = round_up (args_size->var, preferred_stack_boundary); } @@ -1444,11 +1215,6 @@ compute_argument_block_size (reg_parm_stack_space, args_size, 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 @@ -1467,70 +1233,47 @@ compute_argument_block_size (reg_parm_stack_space, args_size, precomputed argument. */ static void -precompute_arguments (flags, num_actuals, args) - int flags; - int num_actuals; - struct arg_data *args; +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 ((flags & ECF_LIBCALL_BLOCK) == 0) + return; for (i = 0; i < num_actuals; i++) - if ((flags & ECF_LIBCALL_BLOCK) - || calls_function (args[i].tree_value, !ACCUMULATE_OUTGOING_ARGS)) - { - enum machine_mode mode; - - /* If this is an addressable type, we cannot pre-evaluate it. */ - if (TREE_ADDRESSABLE (TREE_TYPE (args[i].tree_value))) - abort (); - - args[i].value - = expand_expr (args[i].tree_value, NULL_RTX, VOIDmode, 0); + { + enum machine_mode mode; - /* ANSI doesn't require a sequence point here, - but PCC has one, so this will avoid some problems. */ - emit_queue (); + /* If this is an addressable type, we cannot pre-evaluate it. */ + gcc_assert (!TREE_ADDRESSABLE (TREE_TYPE (args[i].tree_value))); - args[i].initial_value = args[i].value - = protect_from_queue (args[i].value, 0); + args[i].initial_value = args[i].value + = expand_expr (args[i].tree_value, NULL_RTX, VOIDmode, 0); - mode = TYPE_MODE (TREE_TYPE (args[i].tree_value)); - if (mode != args[i].mode) - { - args[i].value - = convert_modes (args[i].mode, mode, - args[i].value, args[i].unsignedp); -#ifdef PROMOTE_FOR_CALL_ONLY - /* CSE will replace this only if it contains args[i].value - pseudo, so convert it down to the declared mode using - a SUBREG. */ - if (GET_CODE (args[i].value) == REG - && GET_MODE_CLASS (args[i].mode) == MODE_INT) - { - args[i].initial_value - = gen_lowpart_SUBREG (mode, args[i].value); - SUBREG_PROMOTED_VAR_P (args[i].initial_value) = 1; - SUBREG_PROMOTED_UNSIGNED_SET (args[i].initial_value, - args[i].unsignedp); - } + mode = TYPE_MODE (TREE_TYPE (args[i].tree_value)); + if (mode != args[i].mode) + { + args[i].value + = convert_modes (args[i].mode, mode, + args[i].value, args[i].unsignedp); +#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. */ + if (REG_P (args[i].value) + && GET_MODE_CLASS (args[i].mode) == MODE_INT) + { + args[i].initial_value + = gen_lowpart_SUBREG (mode, args[i].value); + SUBREG_PROMOTED_VAR_P (args[i].initial_value) = 1; + SUBREG_PROMOTED_UNSIGNED_SET (args[i].initial_value, + args[i].unsignedp); + } #endif - } - } + } + } } /* Given the current state of MUST_PREALLOCATE and information about @@ -1538,11 +1281,7 @@ precompute_arguments (flags, num_actuals, args) compute and return the final value for MUST_PREALLOCATE. */ static int -finalize_must_preallocate (must_preallocate, num_actuals, args, args_size) - int must_preallocate; - int num_actuals; - struct arg_data *args; - struct args_size *args_size; +finalize_must_preallocate (int must_preallocate, int num_actuals, struct arg_data *args, struct args_size *args_size) { /* See if we have or want to preallocate stack space. @@ -1601,10 +1340,7 @@ finalize_must_preallocate (must_preallocate, num_actuals, args, args_size) ARGBLOCK is an rtx for the address of the outgoing arguments. */ static void -compute_argument_addresses (args, argblock, num_actuals) - struct arg_data *args; - rtx argblock; - int num_actuals; +compute_argument_addresses (struct arg_data *args, rtx argblock, int num_actuals) { if (argblock) { @@ -1616,9 +1352,10 @@ compute_argument_addresses (args, argblock, num_actuals) for (i = 0; i < num_actuals; i++) { - rtx offset = ARGS_SIZE_RTX (args[i].offset); - rtx slot_offset = ARGS_SIZE_RTX (args[i].slot_offset); + rtx offset = ARGS_SIZE_RTX (args[i].locate.offset); + rtx slot_offset = ARGS_SIZE_RTX (args[i].locate.slot_offset); rtx addr; + unsigned int align, boundary; /* Skip this parm if it will not be passed on the stack. */ if (! args[i].pass_on_stack && args[i].reg != 0) @@ -1631,9 +1368,18 @@ compute_argument_addresses (args, argblock, num_actuals) addr = plus_constant (addr, arg_offset); args[i].stack = gen_rtx_MEM (args[i].mode, addr); - set_mem_align (args[i].stack, PARM_BOUNDARY); set_mem_attributes (args[i].stack, TREE_TYPE (args[i].tree_value), 1); + align = BITS_PER_UNIT; + boundary = args[i].locate.boundary; + if (args[i].locate.where_pad != downward) + align = boundary; + else if (GET_CODE (offset) == CONST_INT) + { + align = INTVAL (offset) * BITS_PER_UNIT | boundary; + align = align & -align; + } + set_mem_align (args[i].stack, align); if (GET_CODE (slot_offset) == CONST_INT) addr = plus_constant (arg_reg, INTVAL (slot_offset)); @@ -1642,9 +1388,9 @@ compute_argument_addresses (args, argblock, num_actuals) addr = plus_constant (addr, arg_offset); args[i].stack_slot = gen_rtx_MEM (args[i].mode, addr); - set_mem_align (args[i].stack_slot, PARM_BOUNDARY); set_mem_attributes (args[i].stack_slot, TREE_TYPE (args[i].tree_value), 1); + set_mem_align (args[i].stack_slot, args[i].locate.boundary); /* Function incoming arguments may overlap with sibling call outgoing arguments and we cannot allow reordering of reads @@ -1665,9 +1411,7 @@ compute_argument_addresses (args, argblock, num_actuals) ADDR is the operand 0 of CALL_EXPR for this call. */ static rtx -rtx_for_function_call (fndecl, addr) - tree fndecl; - tree addr; +rtx_for_function_call (tree fndecl, tree addr) { rtx funexp; @@ -1691,70 +1435,130 @@ rtx_for_function_call (fndecl, addr) push_temp_slots (); funexp = expand_expr (addr, NULL_RTX, VOIDmode, 0); pop_temp_slots (); /* FUNEXP can't be BLKmode. */ - emit_queue (); } return funexp; } +/* Return true if and only if SIZE storage units (usually bytes) + starting from address ADDR overlap with already clobbered argument + area. This function is used to determine if we should give up a + sibcall. */ + +static bool +mem_overlaps_already_clobbered_arg_p (rtx addr, unsigned HOST_WIDE_INT size) +{ + HOST_WIDE_INT i; + + if (addr == current_function_internal_arg_pointer) + i = 0; + else if (GET_CODE (addr) == PLUS + && (XEXP (addr, 0) + == current_function_internal_arg_pointer) + && GET_CODE (XEXP (addr, 1)) == CONST_INT) + i = INTVAL (XEXP (addr, 1)); + else + return false; + +#ifdef ARGS_GROW_DOWNWARD + i = -i - size; +#endif + if (size > 0) + { + unsigned HOST_WIDE_INT k; + + for (k = 0; k < size; k++) + if (i + k < stored_args_map->n_bits + && TEST_BIT (stored_args_map, i + k)) + return true; + } + + return false; +} + /* Do the register loads required for any wholly-register parms or any parms which are passed both on the stack and in a register. Their expressions were already evaluated. Mark all register-parms as living through the call, putting these USE - insns in the CALL_INSN_FUNCTION_USAGE field. - - When IS_SIBCALL, perform the check_sibcall_overlap_argument_overlap + insns in the CALL_INSN_FUNCTION_USAGE field. + + When IS_SIBCALL, perform the check_sibcall_argument_overlap checking, setting *SIBCALL_FAILURE if appropriate. */ static void -load_register_parameters (args, num_actuals, call_fusage, flags, - is_sibcall, sibcall_failure) - struct arg_data *args; - int num_actuals; - rtx *call_fusage; - int flags; - int is_sibcall; - int *sibcall_failure; +load_register_parameters (struct arg_data *args, int num_actuals, + rtx *call_fusage, int flags, int is_sibcall, + int *sibcall_failure) { int i, j; -#ifdef LOAD_ARGS_REVERSED - for (i = num_actuals - 1; i >= 0; i--) -#else for (i = 0; i < num_actuals; i++) -#endif { rtx reg = ((flags & ECF_SIBCALL) ? args[i].tail_call_reg : args[i].reg); - int partial = args[i].partial; - int nregs; - if (reg) { + int partial = args[i].partial; + int nregs; + int size = 0; rtx before_arg = get_last_insn (); - /* Set to non-negative if must move a word at a time, even if just - one word (e.g, partial == 1 && mode == DFmode). Set to -1 if - we just use a normal move insn. This value can be zero if the - argument is a zero size structure with no fields. */ - nregs = (partial ? partial - : (TYPE_MODE (TREE_TYPE (args[i].tree_value)) == BLKmode - ? ((int_size_in_bytes (TREE_TYPE (args[i].tree_value)) - + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD) - : -1)); + /* Set non-negative if we must move a word at a time, even if + just one word (e.g, partial == 4 && mode == DFmode). Set + to -1 if we just use a normal move insn. This value can be + zero if the argument is a zero size structure. */ + nregs = -1; + if (GET_CODE (reg) == PARALLEL) + ; + else if (partial) + { + gcc_assert (partial % UNITS_PER_WORD == 0); + nregs = partial / UNITS_PER_WORD; + } + else if (TYPE_MODE (TREE_TYPE (args[i].tree_value)) == BLKmode) + { + size = int_size_in_bytes (TREE_TYPE (args[i].tree_value)); + nregs = (size + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD; + } + else + size = GET_MODE_SIZE (args[i].mode); /* Handle calls that pass values in multiple non-contiguous locations. The Irix 6 ABI has examples of this. */ if (GET_CODE (reg) == PARALLEL) - emit_group_load (reg, args[i].value, - int_size_in_bytes (TREE_TYPE (args[i].tree_value))); + emit_group_move (reg, args[i].parallel_value); /* If simple case, just do move. If normal partial, store_one_arg has already loaded the register for us. In all other cases, load the register(s) from memory. */ else if (nregs == -1) - emit_move_insn (reg, args[i].value); + { + emit_move_insn (reg, args[i].value); +#ifdef BLOCK_REG_PADDING + /* Handle case where we have a value that needs shifting + up to the msb. eg. a QImode value and we're padding + upward on a BYTES_BIG_ENDIAN machine. */ + if (size < UNITS_PER_WORD + && (args[i].locate.where_pad + == (BYTES_BIG_ENDIAN ? upward : downward))) + { + rtx x; + int shift = (UNITS_PER_WORD - size) * BITS_PER_UNIT; + + /* Assigning REG here rather than a temp makes CALL_FUSAGE + report the whole reg as used. Strictly speaking, the + call only uses SIZE bytes at the msb end, but it doesn't + seem worth generating rtl to say that. */ + reg = gen_rtx_REG (word_mode, REGNO (reg)); + x = expand_shift (LSHIFT_EXPR, word_mode, reg, + build_int_cst (NULL_TREE, shift), + reg, 1); + if (x != reg) + emit_move_insn (reg, x); + } +#endif + } /* If we have pre-computed the values to put in the registers in the case of non-aligned structures, copy them in now. */ @@ -1765,9 +1569,41 @@ load_register_parameters (args, num_actuals, call_fusage, flags, args[i].aligned_regs[j]); else if (partial == 0 || args[i].pass_on_stack) - move_block_to_reg (REGNO (reg), - validize_mem (args[i].value), nregs, - args[i].mode); + { + rtx mem = validize_mem (args[i].value); + + /* Check for overlap with already clobbered argument area. */ + if (is_sibcall + && mem_overlaps_already_clobbered_arg_p (XEXP (args[i].value, 0), + size)) + *sibcall_failure = 1; + + /* Handle a BLKmode that needs shifting. */ + if (nregs == 1 && size < UNITS_PER_WORD +#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)); + rtx x = gen_reg_rtx (word_mode); + int shift = (UNITS_PER_WORD - size) * BITS_PER_UNIT; + enum tree_code dir = BYTES_BIG_ENDIAN ? RSHIFT_EXPR + : LSHIFT_EXPR; + + emit_move_insn (x, tem); + x = expand_shift (dir, word_mode, x, + build_int_cst (NULL_TREE, shift), + ri, 1); + if (x != ri) + emit_move_insn (ri, x); + } + else + move_block_to_reg (REGNO (reg), mem, nregs, args[i].mode); + } /* When a parameter is a block, and perhaps in other cases, it is possible that it did a load from an argument slot that was @@ -1782,132 +1618,10 @@ load_register_parameters (args, num_actuals, call_fusage, flags, use_group_regs (call_fusage, reg); else if (nregs == -1) use_reg (call_fusage, reg); - else - use_regs (call_fusage, REGNO (reg), nregs == 0 ? 1 : nregs); - } - } -} - -/* Try to integrate function. See expand_inline_function for documentation - about the parameters. */ - -static rtx -try_to_integrate (fndecl, actparms, target, ignore, type, structure_value_addr) - 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); - } - } + else if (nregs > 0) + use_regs (call_fusage, REGNO (reg), nregs); } - - /* 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"); } - (*lang_hooks.mark_addressable) (fndecl); - return (rtx) (size_t) - 1; } /* We need to pop PENDING_STACK_ADJUST bytes. But, if the arguments @@ -1920,19 +1634,16 @@ try_to_integrate (fndecl, actparms, target, ignore, type, structure_value_addr) be popped after the call. Returns the adjustment. */ static int -combine_pending_stack_adjustment_and_call (unadjusted_args_size, - args_size, - preferred_unit_stack_boundary) - int unadjusted_args_size; - struct args_size *args_size; - int preferred_unit_stack_boundary; +combine_pending_stack_adjustment_and_call (int unadjusted_args_size, + struct args_size *args_size, + unsigned int preferred_unit_stack_boundary) { /* The number of bytes to pop so that the stack will be under-aligned by UNADJUSTED_ARGS_SIZE bytes. */ HOST_WIDE_INT adjustment; /* The alignment of the stack after the arguments are pushed, if we just pushed the arguments without adjust the stack here. */ - HOST_WIDE_INT unadjusted_alignment; + unsigned HOST_WIDE_INT unadjusted_alignment; unadjusted_alignment = ((stack_pointer_delta + unadjusted_args_size) @@ -1976,12 +1687,10 @@ combine_pending_stack_adjustment_and_call (unadjusted_args_size, zero otherwise. */ static int -check_sibcall_argument_overlap_1 (x) - rtx x; +check_sibcall_argument_overlap_1 (rtx x) { RTX_CODE code; int i, j; - unsigned int k; const char *fmt; if (x == NULL_RTX) @@ -1990,28 +1699,8 @@ check_sibcall_argument_overlap_1 (x) code = GET_CODE (x); if (code == MEM) - { - if (XEXP (x, 0) == current_function_internal_arg_pointer) - i = 0; - else if (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) - i = INTVAL (XEXP (XEXP (x, 0), 1)); - else - return 0; - -#ifdef ARGS_GROW_DOWNWARD - i = -i - GET_MODE_SIZE (GET_MODE (x)); -#endif - - for (k = 0; k < GET_MODE_SIZE (GET_MODE (x)); k++) - if (i + k < stored_args_map->n_bits - && TEST_BIT (stored_args_map, i + k)) - return 1; - - return 0; - } + return mem_overlaps_already_clobbered_arg_p (XEXP (x, 0), + GET_MODE_SIZE (GET_MODE (x))); /* Scan all subexpressions. */ fmt = GET_RTX_FORMAT (code); @@ -2040,10 +1729,7 @@ check_sibcall_argument_overlap_1 (x) slots, zero otherwise. */ static int -check_sibcall_argument_overlap (insn, arg, mark_stored_args_map) - rtx insn; - struct arg_data *arg; - int mark_stored_args_map; +check_sibcall_argument_overlap (rtx insn, struct arg_data *arg, int mark_stored_args_map) { int low, high; @@ -2060,44 +1746,38 @@ check_sibcall_argument_overlap (insn, arg, mark_stored_args_map) if (mark_stored_args_map) { #ifdef ARGS_GROW_DOWNWARD - low = -arg->slot_offset.constant - arg->size.constant; + low = -arg->locate.slot_offset.constant - arg->locate.size.constant; #else - low = arg->slot_offset.constant; + low = arg->locate.slot_offset.constant; #endif - for (high = low + arg->size.constant; low < high; low++) + for (high = low + arg->locate.size.constant; low < high; low++) SET_BIT (stored_args_map, low); } return insn != NULL_RTX; } -static tree -fix_unsafe_tree (t) - tree t; -{ - switch (unsafe_for_reeval (t)) - { - case 0: /* Safe. */ - break; +/* Given that a function returns a value of mode MODE at the most + significant end of hard register VALUE, shift VALUE left or right + as specified by LEFT_P. Return true if some action was needed. */ - case 1: /* Mildly unsafe. */ - t = unsave_expr (t); - break; +bool +shift_return_value (enum machine_mode mode, bool left_p, rtx value) +{ + HOST_WIDE_INT shift; - case 2: /* Wildly unsafe. */ - { - tree var = build_decl (VAR_DECL, NULL_TREE, - TREE_TYPE (t)); - SET_DECL_RTL (var, - expand_expr (t, NULL_RTX, VOIDmode, EXPAND_NORMAL)); - t = var; - } - break; + gcc_assert (REG_P (value) && HARD_REGISTER_P (value)); + shift = GET_MODE_BITSIZE (GET_MODE (value)) - GET_MODE_BITSIZE (mode); + if (shift == 0) + return false; - default: - abort (); - } - return t; + /* Use ashr rather than lshr for right shifts. This is for the benefit + of the MIPS port, which requires SImode values to be sign-extended + when stored in 64-bit registers. */ + if (!force_expand_binop (GET_MODE (value), left_p ? ashl_optab : ashr_optab, + value, GEN_INT (shift), value, 1, OPTAB_WIDEN)) + gcc_unreachable (); + return true; } /* Generate all the code for a function call @@ -2107,10 +1787,7 @@ fix_unsafe_tree (t) If IGNORE is nonzero, then we ignore the value of the function call. */ rtx -expand_call (exp, target, ignore) - tree exp; - rtx target; - int ignore; +expand_call (tree exp, rtx target, int ignore) { /* Nonzero if we are currently expanding a call. */ static int currently_expanding_call = 0; @@ -2119,20 +1796,19 @@ expand_call (exp, target, 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; + tree type_arg_types; /* 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, @@ -2152,6 +1828,7 @@ expand_call (exp, target, ignore) /* 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; + rtx struct_value = 0; /* Number of actual parameters in this call, including struct value addr. */ int num_actuals; @@ -2192,8 +1869,6 @@ expand_call (exp, target, 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. */ @@ -2203,6 +1878,7 @@ expand_call (exp, target, ignore) int initial_highest_arg_in_use = highest_outgoing_arg_in_use; char *initial_stack_usage_map = stack_usage_map; + char *stack_usage_map_buf = NULL; int old_stack_allocated; @@ -2222,72 +1898,75 @@ expand_call (exp, target, ignore) tree addr = TREE_OPERAND (exp, 0); int i; /* The alignment of the stack, in bits. */ - HOST_WIDE_INT preferred_stack_boundary; + unsigned HOST_WIDE_INT preferred_stack_boundary; /* The alignment of the stack, in bytes. */ - HOST_WIDE_INT preferred_unit_stack_boundary; - + unsigned 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) + { + fntype = TREE_TYPE (fndecl); + flags |= flags_from_decl_or_type (fndecl); + } + else + { + fntype = TREE_TYPE (TREE_TYPE (p)); + flags |= flags_from_decl_or_type (fntype); + } + + struct_value = targetm.calls.struct_value_rtx (fntype, 0); - fndecl = get_callee_fndecl (exp); - if (fndecl) + /* Warn if this value is an aggregate type, + regardless of which calling convention we are using for it. */ + if (AGGREGATE_TYPE_P (TREE_TYPE (exp))) + warning (OPT_Waggregate_return, "function call has aggregate value"); + + /* If the result of a pure or const function call is ignored (or void), + and none of its arguments are volatile, we can avoid expanding the + call and just evaluate the arguments for side-effects. */ + if ((flags & (ECF_CONST | ECF_PURE)) + && (ignore || target == const0_rtx + || TYPE_MODE (TREE_TYPE (exp)) == VOIDmode)) { - 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. + bool volatilep = false; + tree arg; - 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"); - } - (*lang_hooks.mark_addressable) (fndecl); - } + for (arg = actparms; arg; arg = TREE_CHAIN (arg)) + if (TREE_THIS_VOLATILE (TREE_VALUE (arg))) + { + volatilep = true; + break; + } - flags |= flags_from_decl_or_type (fndecl); + if (! volatilep) + { + for (arg = actparms; arg; arg = TREE_CHAIN (arg)) + expand_expr (TREE_VALUE (arg), const0_rtx, + VOIDmode, EXPAND_NORMAL); + return const0_rtx; + } } - /* If we don't have specific function to call, see if we have a - attributes set in the type. */ - else - flags |= flags_from_decl_or_type (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 #ifndef OUTGOING_REG_PARM_STACK_SPACE if (reg_parm_stack_space > 0 && PUSH_ARGS) must_preallocate = 1; #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)) + if (aggregate_value_p (exp, fndecl)) { /* This call returns a big structure. */ flags &= ~(ECF_CONST | ECF_PURE | ECF_LIBCALL_BLOCK); @@ -2295,31 +1974,12 @@ expand_call (exp, target, 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 */ { struct_value_size = int_size_in_bytes (TREE_TYPE (exp)); - if (CALL_EXPR_HAS_RETURN_SLOT_ADDR (exp)) - { - /* The structure value address arg is already in actparms. - Pull it out. It might be nice to just leave it there, but - we need to set structure_value_addr. */ - tree return_arg = TREE_VALUE (actparms); - actparms = TREE_CHAIN (actparms); - structure_value_addr = expand_expr (return_arg, NULL_RTX, - VOIDmode, EXPAND_NORMAL); - } - else if (target && GET_CODE (target) == MEM) + if (target && MEM_P (target) && CALL_EXPR_RETURN_SLOT_OPT (exp)) structure_value_addr = XEXP (target, 0); else { @@ -2336,17 +1996,6 @@ expand_call (exp, target, 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) @@ -2358,31 +2007,37 @@ expand_call (exp, target, ignore) /* Operand 0 is a pointer-to-function; get the type of the function. */ funtype = TREE_TYPE (addr); - if (! POINTER_TYPE_P (funtype)) - abort (); + gcc_assert (POINTER_TYPE_P (funtype)); funtype = TREE_TYPE (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); + /* Munge the tree to split complex arguments into their imaginary + and real parts. */ + if (targetm.calls.split_complex_arg) + { + type_arg_types = split_complex_types (TYPE_ARG_TYPES (funtype)); + actparms = split_complex_values (actparms); + } + else + type_arg_types = TYPE_ARG_TYPES (funtype); if (flags & ECF_MAY_BE_ALLOCA) current_function_calls_alloca = 1; /* 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 && struct_value == 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 + rtx temp = (!REG_P (structure_value_addr) || (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 @@ -2398,28 +2053,11 @@ expand_call (exp, target, ignore) num_actuals++; /* 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 nonzero. - (If no anonymous args follow, the result of list_length is actually - one too large. This is harmless.) - - If PRETEND_OUTGOING_VARARGS_NAMED is set and STRICT_ARGUMENT_NAMING is - zero, 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 PRETEND_OUTGOING_VARARGS_NAMED is not set, we do not have any - reliable way to pass unnamed args in registers, so we must force - them into memory. */ + First, do a raw count of the args for INIT_CUMULATIVE_ARGS. */ - if ((STRICT_ARGUMENT_NAMING - || ! PRETEND_OUTGOING_VARARGS_NAMED) - && TYPE_ARG_TYPES (funtype) != 0) + if (type_arg_types != 0) n_named_args - = (list_length (TYPE_ARG_TYPES (funtype)) - /* Don't include the last named arg. */ - - (STRICT_ARGUMENT_NAMING ? 0 : 1) + = (list_length (type_arg_types) /* Count the struct value address, if it is passed as a parm. */ + structure_value_addr_parm); else @@ -2429,14 +2067,43 @@ expand_call (exp, target, ignore) /* 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 + 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); + INIT_CUMULATIVE_ARGS (args_so_far, funtype, NULL_RTX, fndecl, n_named_args); + + /* Now possibly adjust the number of named args. + Normally, don't include the last named arg if anonymous args follow. + We do include the last named arg if + targetm.calls.strict_argument_naming() returns nonzero. + (If no anonymous args follow, the result of list_length is actually + one too large. This is harmless.) + + If targetm.calls.pretend_outgoing_varargs_named() returns + nonzero, and targetm.calls.strict_argument_naming() returns zero, + 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 targetm.calls.pretend_outgoing_varargs_named() returns zero, + we do not have any reliable way to pass unnamed args in + registers, so we must force them into memory. */ + + if (type_arg_types != 0 + && targetm.calls.strict_argument_naming (&args_so_far)) + ; + else if (type_arg_types != 0 + && ! targetm.calls.pretend_outgoing_varargs_named (&args_so_far)) + /* Don't include the last named arg. */ + --n_named_args; + else + /* 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)); - memset ((char *) args, 0, num_actuals * sizeof (struct arg_data)); + args = alloca (num_actuals * sizeof (struct arg_data)); + memset (args, 0, num_actuals * sizeof (struct arg_data)); /* Build up entries in the ARGS array, compute the size of the arguments into ARGS_SIZE, etc. */ @@ -2444,7 +2111,8 @@ expand_call (exp, target, 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) { @@ -2474,29 +2142,16 @@ expand_call (exp, target, ignore) || (!ACCUMULATE_OUTGOING_ARGS && args_size.constant))) structure_value_addr = copy_to_reg (structure_value_addr); - /* Tail calls can make things harder to debug, and we're traditionally + /* Tail calls can make things harder to debug, and we've traditionally pushed these optimizations into -O2. Don't try if we're already expanding a call, as that means we're an argument. Don't try if - there's cleanups, as we know there's code to follow the call. - - If rtx_equal_function_value_matters is false, that means we've - finished with regular parsing. Which means that some of the - machinery we use to generate tail-calls is no longer in place. - This is most often true of sjlj-exceptions, which we couldn't - tail-call to anyway. */ + there's cleanups, as we know there's code to follow the call. */ if (currently_expanding_call++ != 0 || !flag_optimize_sibling_calls - || !rtx_equal_function_value_matters - || any_pending_cleanups (1) - || 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 ( @@ -2513,130 +2168,30 @@ expand_call (exp, target, 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)) + || (flags & (ECF_RETURNS_TWICE | ECF_NORETURN)) || TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (addr))) /* If the called function is nested in the current one, it might access some of the caller's arguments, but could clobber them beforehand if the argument areas are shared. */ || (fndecl && decl_function_context (fndecl) == current_function_decl) /* If this function requires more stack slots than the current - function, we cannot change it into a sibling call. */ - || args_size.constant > current_function_args_size + function, we cannot change it into a sibling call. + current_function_pretend_args_size is not part of the + stack allocated by our caller. */ + || args_size.constant > (current_function_args_size + - current_function_pretend_args_size) /* If the callee pops its own arguments, then it must pop exactly the same number of arguments as the current function. */ - || RETURN_POPS_ARGS (fndecl, funtype, args_size.constant) - != RETURN_POPS_ARGS (current_function_decl, - TREE_TYPE (current_function_decl), - current_function_args_size)) + || (RETURN_POPS_ARGS (fndecl, funtype, args_size.constant) + != RETURN_POPS_ARGS (current_function_decl, + TREE_TYPE (current_function_decl), + current_function_args_size)) + || !lang_hooks.decls.ok_for_sibcall (fndecl)) try_tail_call = 0; - if (try_tail_call || try_tail_recursion) - { - int end, inc; - actparms = NULL_TREE; - /* Ok, we're going to give the tail call the old college try. - This means we're going to evaluate the function arguments - up to three times. There are two degrees of badness we can - encounter, those that can be unsaved and those that can't. - (See unsafe_for_reeval commentary for details.) - - Generate a new argument list. Pass safe arguments through - unchanged. For the easy badness wrap them in UNSAVE_EXPRs. - For hard badness, evaluate them now and put their resulting - rtx in a temporary VAR_DECL. - - initialize_argument_information has ordered the array for the - order to be pushed, and we must remember this when reconstructing - the original argument order. */ - - if (PUSH_ARGS_REVERSED) - { - inc = 1; - i = 0; - end = num_actuals; - } - else - { - inc = -1; - i = num_actuals - 1; - end = -1; - } - - 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) - addr = fix_unsafe_tree (addr); - /* Expanding one of those dangerous arguments could have added - cleanups, but otherwise give it a whirl. */ - if (any_pending_cleanups (1)) - 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 (1)) - 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; - } - - 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 functions. */ @@ -2648,8 +2203,6 @@ expand_call (exp, target, ignore) preferred_unit_stack_boundary = preferred_stack_boundary / BITS_PER_UNIT; - function_call_count++; - /* We want to make two insn chains; one for a sibling call, the other for a normal call. We will select one of the two chains after initial RTL generation is complete. */ @@ -2658,7 +2211,7 @@ expand_call (exp, target, 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; @@ -2667,10 +2220,6 @@ expand_call (exp, target, ignore) if (pass == 0) { - /* Emit any queued insns now; otherwise they would end up in - only one of the alternates. */ - emit_queue (); - /* State variables we need to save and restore between iterations. */ save_pending_stack_adjust = pending_stack_adjust; @@ -2692,23 +2241,18 @@ expand_call (exp, target, ignore) sibcall_failure instead of continuing the loop. */ start_sequence (); - if (pass == 0) - { - /* We know at this point that there are not currently any - pending cleanups. If, however, in the process of evaluating - the arguments we were to create some, we'll need to be - able to get rid of them. */ - expand_start_target_temps (); - } - /* 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 or if we are expanding a sibling call sequence or if we are calling a function that is to return - with stack pointer depressed. */ + with stack pointer depressed. + Also do the adjustments before a throwing call, otherwise + exception handling can fail; PR 19225. */ if (pending_stack_adjust >= 32 || (pending_stack_adjust > 0 && (flags & (ECF_MAY_BE_ALLOCA | ECF_SP_DEPRESSED))) + || (pending_stack_adjust > 0 + && flag_exceptions && !(flags & ECF_NOTHROW)) || pass == 0) do_pending_stack_adjust (); @@ -2717,10 +2261,6 @@ expand_call (exp, target, 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); @@ -2730,6 +2270,9 @@ expand_call (exp, target, ignore) if (pass && (flags & (ECF_LIBCALL_BLOCK | ECF_MALLOC))) start_sequence (); + if (pass == 0 && cfun->stack_protect_guard) + stack_protect_epilogue (); + adjusted_args_size = args_size; /* Compute the actual size of the argument block required. The variable and constant sizes must be combined, the size may have to be rounded, @@ -2825,8 +2368,10 @@ expand_call (exp, target, ignore) highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use, needed); #endif - stack_usage_map - = (char *) alloca (highest_outgoing_arg_in_use); + if (stack_usage_map_buf) + free (stack_usage_map_buf); + stack_usage_map_buf = xmalloc (highest_outgoing_arg_in_use); + stack_usage_map = stack_usage_map_buf; if (initial_highest_arg_in_use) memcpy (stack_usage_map, initial_stack_usage_map, @@ -2883,7 +2428,12 @@ expand_call (exp, target, ignore) if (needed == 0) argblock = virtual_outgoing_args_rtx; else - argblock = push_block (GEN_INT (needed), 0, 0); + { + argblock = push_block (GEN_INT (needed), 0, 0); +#ifdef ARGS_GROW_DOWNWARD + argblock = plus_constant (argblock, needed); +#endif + } /* We only really need to call `copy_to_reg' in the case where push insns are going to be used to pass ARGBLOCK @@ -2926,8 +2476,10 @@ expand_call (exp, target, ignore) = stack_arg_under_construction; stack_arg_under_construction = 0; /* Make a new map for the new argument list. */ - stack_usage_map = (char *) - alloca (highest_outgoing_arg_in_use); + if (stack_usage_map_buf) + free (stack_usage_map_buf); + stack_usage_map_buf = xmalloc (highest_outgoing_arg_in_use); + stack_usage_map = stack_usage_map_buf; memset (stack_usage_map, 0, highest_outgoing_arg_in_use); highest_outgoing_arg_in_use = 0; } @@ -2944,7 +2496,7 @@ expand_call (exp, target, ignore) break; } } - + compute_argument_addresses (args, argblock, num_actuals); /* If we push args individually in reverse order, perform stack alignment @@ -2982,15 +2534,22 @@ expand_call (exp, target, ignore) { if (pcc_struct_value) valreg = hard_function_value (build_pointer_type (TREE_TYPE (exp)), - fndecl, (pass == 0)); + fndecl, NULL, (pass == 0)); else - valreg = hard_function_value (TREE_TYPE (exp), fndecl, (pass == 0)); + valreg = hard_function_value (TREE_TYPE (exp), fndecl, fntype, + (pass == 0)); } /* Precompute all register parameters. It isn't safe to compute anything 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. */ @@ -3017,6 +2576,14 @@ expand_call (exp, target, ignore) && check_sibcall_argument_overlap (before_arg, &args[i], 1))) sibcall_failure = 1; + + if (flags & ECF_CONST + && args[i].stack + && args[i].value == args[i].stack) + call_fusage = gen_rtx_EXPR_LIST (VOIDmode, + gen_rtx_USE (VOIDmode, + args[i].value), + call_fusage); } /* If we have a parm that is passed in registers but not in memory @@ -3062,24 +2629,23 @@ expand_call (exp, target, ignore) structure value. */ if (pass != 0 && structure_value_addr && ! structure_value_addr_parm) { - emit_move_insn (struct_value_rtx, + structure_value_addr + = convert_memory_address (Pmode, structure_value_addr); + emit_move_insn (struct_value, force_reg (Pmode, force_operand (structure_value_addr, NULL_RTX))); - if (GET_CODE (struct_value_rtx) == REG) - use_reg (&call_fusage, struct_value_rtx); + if (REG_P (struct_value)) + 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); - /* Perform postincrements before actually calling the function. */ - emit_queue (); - /* Save a pointer to the last insn before the call, so that we can later safely search backwards to find the CALL_INSN. */ before_call = get_last_insn (); @@ -3099,15 +2665,29 @@ expand_call (exp, target, ignore) now! */ /* Stack must be properly aligned now. */ - if (pass && stack_pointer_delta % preferred_unit_stack_boundary) - abort (); + gcc_assert (!pass + || !(stack_pointer_delta % preferred_unit_stack_boundary)); /* 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); + /* If a non-BLKmode value is returned at the most significant end + of a register, shift the register right by the appropriate amount + and update VALREG accordingly. BLKmode values are handled by the + group load/store machinery below. */ + if (!structure_value_addr + && !pcc_struct_value + && TYPE_MODE (TREE_TYPE (exp)) != BLKmode + && targetm.calls.return_in_msb (TREE_TYPE (exp))) + { + if (shift_return_value (TYPE_MODE (TREE_TYPE (exp)), false, valreg)) + sibcall_failure = 1; + valreg = gen_rtx_REG (TYPE_MODE (TREE_TYPE (exp)), REGNO (valreg)); + } + /* If call is cse'able, make appropriate pair of reg-notes around it. Test valreg so we don't crash; may safely ignore `const' if return type is void. Disable for PARALLEL return values, because @@ -3115,10 +2695,19 @@ expand_call (exp, target, ignore) if (pass && (flags & ECF_LIBCALL_BLOCK)) { rtx insns; + rtx insn; + bool failed = valreg == 0 || GET_CODE (valreg) == PARALLEL; - if (valreg == 0 || GET_CODE (valreg) == PARALLEL) + insns = get_insns (); + + /* Expansion of block moves possibly introduced a loop that may + not appear inside libcall block. */ + for (insn = insns; insn; insn = NEXT_INSN (insn)) + if (JUMP_P (insn)) + failed = true; + + if (failed) { - insns = get_insns (); end_sequence (); emit_insn (insns); } @@ -3132,23 +2721,33 @@ expand_call (exp, target, ignore) mark_reg_pointer (temp, TYPE_ALIGN (TREE_TYPE (TREE_TYPE (exp)))); - /* Construct an "equal form" for the value which mentions all the - arguments in order as well as the function name. */ - for (i = 0; i < num_actuals; i++) - note = gen_rtx_EXPR_LIST (VOIDmode, - args[i].initial_value, note); - note = gen_rtx_EXPR_LIST (VOIDmode, funexp, note); - - insns = get_insns (); end_sequence (); - - if (flags & ECF_PURE) - note = gen_rtx_EXPR_LIST (VOIDmode, + if (flag_unsafe_math_optimizations + && fndecl + && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL + && (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_SQRT + || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_SQRTF + || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_SQRTL)) + note = gen_rtx_fmt_e (SQRT, + GET_MODE (temp), + args[0].initial_value); + else + { + /* Construct an "equal form" for the value which + mentions all the arguments in order as well as + the function name. */ + for (i = 0; i < num_actuals; i++) + note = gen_rtx_EXPR_LIST (VOIDmode, + args[i].initial_value, note); + note = gen_rtx_EXPR_LIST (VOIDmode, funexp, note); + + if (flags & ECF_PURE) + note = gen_rtx_EXPR_LIST (VOIDmode, gen_rtx_USE (VOIDmode, gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (VOIDmode))), note); - + } emit_libcall_block (insns, temp, valreg, note); valreg = temp; @@ -3182,53 +2781,40 @@ expand_call (exp, target, ignore) if nonvolatile values are live. For functions that cannot return, inform flow that control does not fall through. */ - if ((flags & (ECF_NORETURN | ECF_LONGJMP)) || pass == 0) + if ((flags & ECF_NORETURN) || pass == 0) { /* The barrier must be emitted immediately after the CALL_INSN. Some ports emit more than just a CALL_INSN above, so we must search for it here. */ rtx last = get_last_insn (); - while (GET_CODE (last) != CALL_INSN) + while (!CALL_P (last)) { last = PREV_INSN (last); /* There was no CALL_INSN? */ - if (last == before_call) - abort (); + gcc_assert (last != before_call); } emit_barrier_after (last); - } - - if (flags & ECF_LONGJMP) - current_function_calls_longjmp = 1; - /* If this function is returning into a memory location marked as - readonly, it means it is initializing that location. But we normally - treat functions as not clobbering such locations, so we need to - specify that this one does. */ - if (target != 0 && GET_CODE (target) == MEM - && structure_value_addr != 0 && RTX_UNCHANGING_P (target)) - emit_insn (gen_rtx_CLOBBER (VOIDmode, target)); + /* Stack adjustments after a noreturn call are dead code. + However when NO_DEFER_POP is in effect, we must preserve + stack_pointer_delta. */ + if (inhibit_defer_pop == 0) + { + stack_pointer_delta = old_stack_allocated; + pending_stack_adjust = 0; + } + } /* If value type not void, return an rtx for the value. */ - /* If there are cleanups to be called, don't use a hard reg as target. - We need to double check this and see if it matters anymore. */ - if (any_pending_cleanups (1)) - { - if (target && REG_P (target) - && REGNO (target) < FIRST_PSEUDO_REGISTER) - target = 0; - sibcall_failure = 1; - } - if (TYPE_MODE (TREE_TYPE (exp)) == VOIDmode || ignore) target = const0_rtx; else if (structure_value_addr) { - if (target == 0 || GET_CODE (target) != MEM) + if (target == 0 || !MEM_P (target)) { target = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (exp)), @@ -3258,11 +2844,10 @@ expand_call (exp, target, ignore) | TYPE_QUAL_CONST)); target = assign_temp (nt, 0, 1, 1); - preserve_temp_slots (target); } if (! rtx_equal_p (target, valreg)) - emit_group_store (target, valreg, + emit_group_store (target, valreg, TREE_TYPE (exp), int_size_in_bytes (TREE_TYPE (exp))); /* We can not support sibling calls for this case. */ @@ -3272,13 +2857,50 @@ expand_call (exp, target, ignore) && GET_MODE (target) == TYPE_MODE (TREE_TYPE (exp)) && GET_MODE (target) == GET_MODE (valreg)) { - /* TARGET and VALREG cannot be equal at this point because the - latter would not have REG_FUNCTION_VALUE_P true, while the - former would if it were referring to the same register. + bool may_overlap = false; + + /* We have to copy a return value in a CLASS_LIKELY_SPILLED hard + reg to a plain register. */ + if (REG_P (valreg) + && HARD_REGISTER_P (valreg) + && CLASS_LIKELY_SPILLED_P (REGNO_REG_CLASS (REGNO (valreg))) + && !(REG_P (target) && !HARD_REGISTER_P (target))) + valreg = copy_to_reg (valreg); + + /* If TARGET is a MEM in the argument area, and we have + saved part of the argument area, then we can't store + directly into TARGET as it may get overwritten when we + restore the argument save area below. Don't work too + hard though and simply force TARGET to a register if it + is a MEM; the optimizer is quite likely to sort it out. */ + if (ACCUMULATE_OUTGOING_ARGS && pass && MEM_P (target)) + for (i = 0; i < num_actuals; i++) + if (args[i].save_area) + { + may_overlap = true; + break; + } - If they refer to the same register, this move will be a no-op, - except when function inlining is being done. */ - emit_move_insn (target, valreg); + if (may_overlap) + target = copy_to_reg (valreg); + else + { + /* TARGET and VALREG cannot be equal at this point + because the latter would not have + REG_FUNCTION_VALUE_P true, while the former would if + it were referring to the same register. + + If they refer to the same register, this move will be + a no-op, except when function inlining is being + done. */ + emit_move_insn (target, valreg); + + /* If we are setting a MEM, this code must be executed. + Since it is emitted after the call insn, sibcall + optimization cannot be performed in that case. */ + if (MEM_P (target)) + sibcall_failure = 1; + } } else if (TYPE_MODE (TREE_TYPE (exp)) == BLKmode) { @@ -3290,38 +2912,39 @@ expand_call (exp, target, ignore) else target = copy_to_reg (valreg); -#ifdef PROMOTE_FUNCTION_RETURN - /* If we promoted this return value, make the proper SUBREG. TARGET - might be const0_rtx here, so be careful. */ - if (GET_CODE (target) == REG - && TYPE_MODE (TREE_TYPE (exp)) != BLKmode - && GET_MODE (target) != TYPE_MODE (TREE_TYPE (exp))) + if (targetm.calls.promote_function_return(funtype)) { - tree type = TREE_TYPE (exp); - int unsignedp = TREE_UNSIGNED (type); - int offset = 0; - - /* If we don't promote as expected, something is wrong. */ - if (GET_MODE (target) - != promote_mode (type, TYPE_MODE (type), &unsignedp, 1)) - abort (); - - if ((WORDS_BIG_ENDIAN || BYTES_BIG_ENDIAN) - && GET_MODE_SIZE (GET_MODE (target)) - > GET_MODE_SIZE (TYPE_MODE (type))) - { - offset = GET_MODE_SIZE (GET_MODE (target)) - - GET_MODE_SIZE (TYPE_MODE (type)); - if (! BYTES_BIG_ENDIAN) - offset = (offset / UNITS_PER_WORD) * UNITS_PER_WORD; - else if (! WORDS_BIG_ENDIAN) - offset %= UNITS_PER_WORD; - } - target = gen_rtx_SUBREG (TYPE_MODE (type), target, offset); - SUBREG_PROMOTED_VAR_P (target) = 1; - SUBREG_PROMOTED_UNSIGNED_SET (target, unsignedp); + /* If we promoted this return value, make the proper SUBREG. + TARGET might be const0_rtx here, so be careful. */ + if (REG_P (target) + && TYPE_MODE (TREE_TYPE (exp)) != BLKmode + && GET_MODE (target) != TYPE_MODE (TREE_TYPE (exp))) + { + tree type = TREE_TYPE (exp); + int unsignedp = TYPE_UNSIGNED (type); + int offset = 0; + enum machine_mode pmode; + + pmode = promote_mode (type, TYPE_MODE (type), &unsignedp, 1); + /* If we don't promote as expected, something is wrong. */ + gcc_assert (GET_MODE (target) == pmode); + + if ((WORDS_BIG_ENDIAN || BYTES_BIG_ENDIAN) + && (GET_MODE_SIZE (GET_MODE (target)) + > GET_MODE_SIZE (TYPE_MODE (type)))) + { + offset = GET_MODE_SIZE (GET_MODE (target)) + - GET_MODE_SIZE (TYPE_MODE (type)); + if (! BYTES_BIG_ENDIAN) + offset = (offset / UNITS_PER_WORD) * UNITS_PER_WORD; + else if (! WORDS_BIG_ENDIAN) + offset %= UNITS_PER_WORD; + } + target = gen_rtx_SUBREG (TYPE_MODE (type), target, offset); + SUBREG_PROMOTED_VAR_P (target) = 1; + SUBREG_PROMOTED_UNSIGNED_SET (target, unsignedp); + } } -#endif /* If size of args is variable or this was a constructor call for a stack argument, restore saved stack-pointer value. */ @@ -3331,6 +2954,7 @@ expand_call (exp, target, ignore) emit_stack_restore (SAVE_BLOCK, old_stack_level, NULL_RTX); stack_pointer_delta = old_stack_pointer_delta; pending_stack_adjust = old_pending_adj; + old_stack_allocated = stack_pointer_delta - pending_stack_adjust; stack_arg_under_construction = old_stack_arg_under_construction; highest_outgoing_arg_in_use = initial_highest_arg_in_use; stack_usage_map = initial_stack_usage_map; @@ -3358,7 +2982,7 @@ expand_call (exp, target, ignore) emit_move_insn (stack_area, args[i].save_area); else emit_block_move (stack_area, args[i].save_area, - GEN_INT (args[i].size.constant), + GEN_INT (args[i].locate.size.constant), BLOCK_OP_CALL_PARM); } @@ -3370,22 +2994,14 @@ expand_call (exp, target, 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) if (args[i].aligned_regs) free (args[i].aligned_regs); - if (pass == 0) - { - /* Undo the fake expand_start_target_temps we did earlier. If - there had been any cleanups created, we've already set - sibcall_failure. */ - expand_end_target_temps (); - } - insns = get_insns (); end_sequence (); @@ -3414,57 +3030,25 @@ expand_call (exp, target, ignore) normal_call_insns = insns; /* Verify that we've deallocated all the stack we used. */ - if (old_stack_allocated != - stack_pointer_delta - pending_stack_adjust) - abort (); + gcc_assert ((flags & ECF_NORETURN) + || (old_stack_allocated + == stack_pointer_delta - pending_stack_adjust)); } /* If something prevents making this a sibling call, 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 succeeded, 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); @@ -3477,27 +3061,164 @@ expand_call (exp, target, 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 (); } + if (stack_usage_map_buf) + free (stack_usage_map_buf); + 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 look + for REG_EQUIV notes between the start of the function and the + NOTE_INSN_FUNCTION_BEG. + + 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; + + for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) + { + /* There are never REG_EQUIV notes for the incoming arguments + after the NOTE_INSN_FUNCTION_BEG note, so stop if we see it. */ + if (NOTE_P (insn) + && NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG) + break; + + 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; + } + } +} + +/* Traverse an argument list in VALUES and expand all complex + arguments into their components. */ +static tree +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)) + { + tree complex_value = TREE_VALUE (p); + tree complex_type; + + complex_type = TREE_TYPE (complex_value); + if (!complex_type) + continue; + + if (TREE_CODE (complex_type) == COMPLEX_TYPE + && targetm.calls.split_complex_arg (complex_type)) + { + tree subtype; + tree real, imag, next; + + subtype = TREE_TYPE (complex_type); + complex_value = save_expr (complex_value); + real = build1 (REALPART_EXPR, subtype, complex_value); + imag = build1 (IMAGPART_EXPR, subtype, complex_value); + + TREE_VALUE (p) = real; + next = TREE_CHAIN (p); + imag = build_tree_list (NULL_TREE, imag); + TREE_CHAIN (p) = imag; + TREE_CHAIN (imag) = next; + + /* Skip the newly created node. */ + p = TREE_CHAIN (p); + } + } + + return values; +} + +/* Traverse a list of TYPES and expand all complex types into their + components. */ +static tree +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 + && targetm.calls.split_complex_arg (complex_type)) + { + tree next, imag; + + /* Rewrite complex type with component type. */ + TREE_VALUE (p) = TREE_TYPE (complex_type); + next = TREE_CHAIN (p); + + /* Add another component type for the imaginary part. */ + imag = build_tree_list (NULL_TREE, TREE_VALUE (p)); + TREE_CHAIN (p) = imag; + TREE_CHAIN (imag) = next; + + /* Skip the newly created node. */ + p = TREE_CHAIN (p); + } + } + + return types; +} /* Output a library call to function FUN (a SYMBOL_REF rtx). The RETVAL parameter specifies whether return value needs to be saved, other parameters are documented in the emit_library_call function below. */ static rtx -emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p) - int retval; - rtx orgfun; - rtx value; - enum libcall_type fn_type; - enum machine_mode outmode; - int nargs; - va_list p; +emit_library_call_value_1 (int retval, rtx orgfun, rtx value, + enum libcall_type fn_type, + enum machine_mode outmode, int nargs, va_list p) { /* Total size in bytes of all the stack-parms scanned so far. */ struct args_size args_size; @@ -3507,7 +3228,6 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p) rtx fun; int inc; int count; - struct args_size alignment_pad; rtx argblock = 0; CUMULATIVE_ARGS args_so_far; struct arg @@ -3516,8 +3236,7 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p) enum machine_mode mode; rtx reg; int partial; - struct args_size offset; - struct args_size size; + struct locate_and_pad_arg_data locate; rtx save_area; }; struct arg *argvec; @@ -3543,14 +3262,13 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p) /* Size of the stack reserved for parameter registers. */ int initial_highest_arg_in_use = highest_outgoing_arg_in_use; char *initial_stack_usage_map = stack_usage_map; + char *stack_usage_map_buf = NULL; + + 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; @@ -3577,9 +3295,6 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p) case LCT_THROW: flags = ECF_NORETURN; break; - case LCT_ALWAYS_RETURN: - flags = ECF_ALWAYS_RETURN; - break; case LCT_RETURNS_TWICE: flags = ECF_RETURNS_TWICE; break; @@ -3595,19 +3310,19 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p) decide where in memory it should come back. */ if (outmode != VOIDmode) { - tfom = (*lang_hooks.types.type_for_mode) (outmode, 0); - if (aggregate_value_p (tfom)) + tfom = lang_hooks.types.type_for_mode (outmode, 0); + if (aggregate_value_p (tfom, 0)) { #ifdef PCC_STATIC_STRUCT_RETURN rtx pointer_reg - = hard_function_value (build_pointer_type (tfom), 0, 0); + = hard_function_value (build_pointer_type (tfom), 0, 0, 0); mem_value = gen_rtx_MEM (outmode, pointer_reg); pcc_struct_value = 1; if (value == 0) value = gen_reg_rtx (outmode); #else /* not PCC_STATIC_STRUCT_RETURN */ struct_value_size = GET_MODE_SIZE (outmode); - if (value != 0 && GET_CODE (value) == MEM) + if (value != 0 && MEM_P (value)) mem_value = value; else mem_value = assign_temp (tfom, 0, 1, 1); @@ -3628,13 +3343,13 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p) of the full argument passing conventions to limit complexity here since library functions shouldn't have many args. */ - argvec = (struct arg *) alloca ((nargs + 1) * sizeof (struct arg)); - memset ((char *) argvec, 0, (nargs + 1) * sizeof (struct arg)); + argvec = alloca ((nargs + 1) * sizeof (struct arg)); + memset (argvec, 0, (nargs + 1) * sizeof (struct arg)); #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; @@ -3651,13 +3366,14 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p) /* If there's a structure value address to be passed, either pass it in the special place, or pass it as an extra argument. */ - if (mem_value && struct_value_rtx == 0 && ! pcc_struct_value) + if (mem_value && struct_value == 0 && ! pcc_struct_value) { rtx addr = XEXP (mem_value, 0); + nargs++; /* Make sure it is a reasonable operand for a move or push insn. */ - if (GET_CODE (addr) != REG && GET_CODE (addr) != MEM + if (!REG_P (addr) && !MEM_P (addr) && ! (CONSTANT_P (addr) && LEGITIMATE_CONSTANT_P (addr))) addr = force_operand (addr, NULL_RTX); @@ -3666,10 +3382,8 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p) argvec[count].partial = 0; argvec[count].reg = FUNCTION_ARG (args_so_far, Pmode, NULL_TREE, 1); -#ifdef FUNCTION_ARG_PARTIAL_NREGS - if (FUNCTION_ARG_PARTIAL_NREGS (args_so_far, Pmode, NULL_TREE, 1)) - abort (); -#endif + gcc_assert (targetm.calls.arg_partial_bytes (&args_so_far, Pmode, + NULL_TREE, 1) == 0); locate_and_pad_parm (Pmode, NULL_TREE, #ifdef STACK_PARMS_IN_REG_PARM_AREA @@ -3677,12 +3391,11 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p) #else argvec[count].reg != 0, #endif - NULL_TREE, &args_size, &argvec[count].offset, - &argvec[count].size, &alignment_pad); + 0, NULL_TREE, &args_size, &argvec[count].locate); if (argvec[count].reg == 0 || argvec[count].partial != 0 || reg_parm_stack_space > 0) - args_size.constant += argvec[count].size.constant; + args_size.constant += argvec[count].locate.size.constant; FUNCTION_ARG_ADVANCE (args_so_far, Pmode, (tree) 0, 1); @@ -3696,35 +3409,19 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p) /* We cannot convert the arg value to the mode the library wants here; must do it earlier where we know the signedness of the arg. */ - if (mode == BLKmode - || (GET_MODE (val) != mode && GET_MODE (val) != VOIDmode)) - abort (); - - /* On some machines, there's no way to pass a float to a library fcn. - Pass it as a double instead. */ -#ifdef LIBGCC_NEEDS_DOUBLE - if (LIBGCC_NEEDS_DOUBLE && mode == SFmode) - val = convert_modes (DFmode, SFmode, val, 0), mode = DFmode; -#endif - - /* There's no need to call protect_from_queue, because - either emit_move_insn or emit_push_insn will do that. */ + gcc_assert (mode != BLKmode + && (GET_MODE (val) == mode || GET_MODE (val) == VOIDmode)); /* Make sure it is a reasonable operand for a move or push insn. */ - if (GET_CODE (val) != REG && GET_CODE (val) != MEM + if (!REG_P (val) && !MEM_P (val) && ! (CONSTANT_P (val) && LEGITIMATE_CONSTANT_P (val))) val = force_operand (val, NULL_RTX); -#ifdef FUNCTION_ARG_PASS_BY_REFERENCE - if (FUNCTION_ARG_PASS_BY_REFERENCE (args_so_far, mode, NULL_TREE, 1)) + if (pass_by_reference (&args_so_far, mode, NULL_TREE, 1)) { rtx slot; - int must_copy = 1 -#ifdef FUNCTION_ARG_CALLEE_COPIES - && ! FUNCTION_ARG_CALLEE_COPIES (args_so_far, mode, - NULL_TREE, 1) -#endif - ; + int must_copy + = !reference_callee_copied (&args_so_far, mode, NULL_TREE, 1); /* loop.c won't look at CALL_INSN_FUNCTION_USAGE of const/pure functions, so we have to pretend this isn't such a function. */ @@ -3744,25 +3441,14 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p) flags |= ECF_PURE; } - if (GET_MODE (val) == MEM && ! must_copy) + if (GET_MODE (val) == MEM && !must_copy) slot = val; - else if (must_copy) + else { - 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); - - slot - = gen_rtx_MEM (mode, - expand_expr (build1 (ADDR_EXPR, - build_pointer_type (type), - make_tree (type, val)), - NULL_RTX, VOIDmode, 0)); - } call_fusage = gen_rtx_EXPR_LIST (VOIDmode, gen_rtx_USE (VOIDmode, slot), @@ -3776,19 +3462,14 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p) mode = Pmode; val = force_operand (XEXP (slot, 0), NULL_RTX); } -#endif argvec[count].value = val; argvec[count].mode = mode; argvec[count].reg = FUNCTION_ARG (args_so_far, mode, NULL_TREE, 1); -#ifdef FUNCTION_ARG_PARTIAL_NREGS argvec[count].partial - = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, mode, NULL_TREE, 1); -#else - argvec[count].partial = 0; -#endif + = targetm.calls.arg_partial_bytes (&args_so_far, mode, NULL_TREE, 1); locate_and_pad_parm (mode, NULL_TREE, #ifdef STACK_PARMS_IN_REG_PARM_AREA @@ -3796,26 +3477,18 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p) #else argvec[count].reg != 0, #endif - NULL_TREE, &args_size, &argvec[count].offset, - &argvec[count].size, &alignment_pad); + argvec[count].partial, + NULL_TREE, &args_size, &argvec[count].locate); - if (argvec[count].size.var) - abort (); - - if (reg_parm_stack_space == 0 && argvec[count].partial) - argvec[count].size.constant -= argvec[count].partial * UNITS_PER_WORD; + gcc_assert (!argvec[count].locate.size.var); if (argvec[count].reg == 0 || argvec[count].partial != 0 || reg_parm_stack_space > 0) - args_size.constant += argvec[count].size.constant; + args_size.constant += argvec[count].locate.size.constant; 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); @@ -3868,7 +3541,8 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p) highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use, needed); #endif - stack_usage_map = (char *) alloca (highest_outgoing_arg_in_use); + stack_usage_map_buf = xmalloc (highest_outgoing_arg_in_use); + stack_usage_map = stack_usage_map_buf; if (initial_highest_arg_in_use) memcpy (stack_usage_map, initial_stack_usage_map, @@ -3945,11 +3619,11 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p) #ifdef ARGS_GROW_DOWNWARD /* stack_slot is negative, but we want to index stack_usage_map with positive values. */ - upper_bound = -argvec[argnum].offset.constant + 1; - lower_bound = upper_bound - argvec[argnum].size.constant; + upper_bound = -argvec[argnum].locate.offset.constant + 1; + lower_bound = upper_bound - argvec[argnum].locate.size.constant; #else - lower_bound = argvec[argnum].offset.constant; - upper_bound = lower_bound + argvec[argnum].size.constant; + lower_bound = argvec[argnum].locate.offset.constant; + upper_bound = lower_bound + argvec[argnum].locate.size.constant; #endif i = lower_bound; @@ -3962,29 +3636,43 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p) if (i < upper_bound) { - /* We need to make a save area. See what mode we can make - it. */ + /* We need to make a save area. */ + unsigned int size + = argvec[argnum].locate.size.constant * BITS_PER_UNIT; enum machine_mode save_mode - = mode_for_size (argvec[argnum].size.constant - * BITS_PER_UNIT, - MODE_INT, 1); + = mode_for_size (size, MODE_INT, 1); + rtx adr + = plus_constant (argblock, + argvec[argnum].locate.offset.constant); rtx stack_area - = gen_rtx_MEM - (save_mode, - memory_address - (save_mode, - plus_constant (argblock, - argvec[argnum].offset.constant))); - argvec[argnum].save_area = gen_reg_rtx (save_mode); - - emit_move_insn (argvec[argnum].save_area, stack_area); + = gen_rtx_MEM (save_mode, memory_address (save_mode, adr)); + + if (save_mode == BLKmode) + { + argvec[argnum].save_area + = assign_stack_temp (BLKmode, + argvec[argnum].locate.size.constant, + 0); + + emit_block_move (validize_mem (argvec[argnum].save_area), + stack_area, + GEN_INT (argvec[argnum].locate.size.constant), + BLOCK_OP_CALL_PARM); + } + else + { + argvec[argnum].save_area = gen_reg_rtx (save_mode); + + emit_move_insn (argvec[argnum].save_area, stack_area); + } } } emit_push_insn (val, mode, NULL_TREE, NULL_RTX, PARM_BOUNDARY, partial, reg, 0, argblock, - GEN_INT (argvec[argnum].offset.constant), - reg_parm_stack_space, ARGS_SIZE_RTX (alignment_pad)); + GEN_INT (argvec[argnum].locate.offset.constant), + reg_parm_stack_space, + ARGS_SIZE_RTX (argvec[argnum].locate.alignment_pad)); /* Now mark the segment we just used. */ if (ACCUMULATE_OUTGOING_ARGS) @@ -3992,6 +3680,28 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p) stack_usage_map[i] = 1; NO_DEFER_POP; + + if (flags & ECF_CONST) + { + rtx use; + + /* Indicate argument access so that alias.c knows that these + values are live. */ + if (argblock) + use = plus_constant (argblock, + argvec[argnum].locate.offset.constant); + else + /* When arguments are pushed, trying to tell alias.c where + exactly this argument is won't work, because the + auto-increment causes confusion. So we merely indicate + that we access something with a known mode somewhere on + the stack. */ + use = gen_rtx_PLUS (Pmode, virtual_outgoing_args_rtx, + gen_rtx_SCRATCH (Pmode)); + use = gen_rtx_MEM (argvec[argnum].mode, use); + use = gen_rtx_USE (VOIDmode, use); + call_fusage = gen_rtx_EXPR_LIST (VOIDmode, use, call_fusage); + } } } @@ -4006,7 +3716,7 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p) 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. */ @@ -4014,6 +3724,7 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p) are to be pushed. */ for (count = 0; count < nargs; count++, argnum += inc) { + enum machine_mode mode = argvec[argnum].mode; rtx val = argvec[argnum].value; rtx reg = argvec[argnum].reg; int partial = argvec[argnum].partial; @@ -4021,7 +3732,7 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p) /* Handle calls that pass values in multiple non-contiguous locations. The PA64 has examples of this for library calls. */ if (reg != 0 && GET_CODE (reg) == PARALLEL) - emit_group_load (reg, val, GET_MODE_SIZE (GET_MODE (val))); + emit_group_load (reg, val, NULL_TREE, GET_MODE_SIZE (mode)); else if (reg != 0 && partial == 0) emit_move_insn (reg, val); @@ -4039,14 +3750,14 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p) } /* Pass the function the address in which to return a structure value. */ - if (mem_value != 0 && struct_value_rtx != 0 && ! pcc_struct_value) + if (mem_value != 0 && struct_value != 0 && ! pcc_struct_value) { - emit_move_insn (struct_value_rtx, + emit_move_insn (struct_value, force_reg (Pmode, force_operand (XEXP (mem_value, 0), NULL_RTX))); - if (GET_CODE (struct_value_rtx) == REG) - use_reg (&call_fusage, struct_value_rtx); + if (REG_P (struct_value)) + use_reg (&call_fusage, struct_value); } /* Don't allow popping to be deferred, since then @@ -4056,8 +3767,8 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p) ? hard_libcall_value (outmode) : NULL_RTX); /* Stack must be properly aligned now. */ - if (stack_pointer_delta & (PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT - 1)) - abort (); + gcc_assert (!(stack_pointer_delta + & (PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT - 1))); before_call = get_last_insn (); @@ -4068,7 +3779,7 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p) 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, @@ -4081,19 +3792,18 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p) if nonvolatile values are live. For functions that cannot return, inform flow that control does not fall through. */ - if (flags & (ECF_NORETURN | ECF_LONGJMP)) + if (flags & ECF_NORETURN) { /* The barrier note must be emitted immediately after the CALL_INSN. Some ports emit more than just a CALL_INSN above, so we must search for it here. */ rtx last = get_last_insn (); - while (GET_CODE (last) != CALL_INSN) + while (!CALL_P (last)) { last = PREV_INSN (last); /* There was no CALL_INSN? */ - if (last == before_call) - abort (); + gcc_assert (last != before_call); } emit_barrier_after (last); @@ -4125,7 +3835,8 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p) if (GET_CODE (valreg) == PARALLEL) { temp = gen_reg_rtx (outmode); - emit_group_store (temp, valreg, outmode); + emit_group_store (temp, valreg, NULL_TREE, + GET_MODE_SIZE (outmode)); valreg = temp; } @@ -4168,7 +3879,7 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p) { if (value == 0) value = gen_reg_rtx (outmode); - emit_group_store (value, valreg, outmode); + emit_group_store (value, valreg, NULL_TREE, GET_MODE_SIZE (outmode)); } else if (value != 0) emit_move_insn (value, valreg); @@ -4189,20 +3900,27 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p) if (argvec[count].save_area) { enum machine_mode save_mode = GET_MODE (argvec[count].save_area); - rtx stack_area - = gen_rtx_MEM (save_mode, - memory_address - (save_mode, - plus_constant (argblock, - argvec[count].offset.constant))); - - emit_move_insn (stack_area, argvec[count].save_area); + rtx adr = plus_constant (argblock, + argvec[count].locate.offset.constant); + rtx stack_area = gen_rtx_MEM (save_mode, + memory_address (save_mode, adr)); + + if (save_mode == BLKmode) + emit_block_move (stack_area, + validize_mem (argvec[count].save_area), + GEN_INT (argvec[count].locate.size.constant), + BLOCK_OP_CALL_PARM); + else + emit_move_insn (stack_area, argvec[count].save_area); } highest_outgoing_arg_in_use = initial_highest_arg_in_use; stack_usage_map = initial_stack_usage_map; } + if (stack_usage_map_buf) + free (stack_usage_map_buf); + return value; } @@ -4212,7 +3930,6 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p) for a value of mode OUTMODE, with NARGS different arguments, passed as alternating rtx values and machine_modes to convert them to. - The rtx values should have been passed through protect_from_queue already. FN_TYPE should be LCT_NORMAL for `normal' calls, LCT_CONST for `const' calls, LCT_PURE for `pure' calls, LCT_CONST_MAKE_BLOCK for `const' calls @@ -4222,18 +3939,14 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p) or other LCT_ value for other types of library calls. */ void -emit_library_call VPARAMS((rtx orgfun, enum libcall_type fn_type, - enum machine_mode outmode, int nargs, ...)) +emit_library_call (rtx orgfun, enum libcall_type fn_type, + enum machine_mode outmode, int nargs, ...) { - VA_OPEN (p, nargs); - VA_FIXEDARG (p, rtx, orgfun); - VA_FIXEDARG (p, int, fn_type); - VA_FIXEDARG (p, enum machine_mode, outmode); - VA_FIXEDARG (p, int, nargs); + va_list p; + va_start (p, nargs); emit_library_call_value_1 (0, orgfun, NULL_RTX, fn_type, outmode, nargs, p); - - VA_CLOSE (p); + va_end (p); } /* Like emit_library_call except that an extra argument, VALUE, @@ -4245,23 +3958,17 @@ emit_library_call VPARAMS((rtx orgfun, enum libcall_type fn_type, If VALUE is nonzero, VALUE is returned. */ rtx -emit_library_call_value VPARAMS((rtx orgfun, rtx value, - enum libcall_type fn_type, - enum machine_mode outmode, int nargs, ...)) +emit_library_call_value (rtx orgfun, rtx value, + enum libcall_type fn_type, + enum machine_mode outmode, int nargs, ...) { rtx result; - - VA_OPEN (p, nargs); - VA_FIXEDARG (p, rtx, orgfun); - VA_FIXEDARG (p, rtx, value); - VA_FIXEDARG (p, int, fn_type); - VA_FIXEDARG (p, enum machine_mode, outmode); - VA_FIXEDARG (p, int, nargs); + va_list p; + va_start (p, nargs); result = emit_library_call_value_1 (1, orgfun, value, fn_type, outmode, nargs, p); - - VA_CLOSE (p); + va_end (p); return result; } @@ -4286,12 +3993,8 @@ emit_library_call_value VPARAMS((rtx orgfun, rtx value, zero otherwise. */ static int -store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space) - struct arg_data *arg; - rtx argblock; - int flags; - int variable_size ATTRIBUTE_UNUSED; - int reg_parm_stack_space; +store_one_arg (struct arg_data *arg, rtx argblock, int flags, + int variable_size ATTRIBUTE_UNUSED, int reg_parm_stack_space) { tree pval = arg->tree_value; rtx reg = 0; @@ -4321,14 +4024,14 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space) else upper_bound = 0; - lower_bound = upper_bound - arg->size.constant; + lower_bound = upper_bound - arg->locate.size.constant; #else if (GET_CODE (XEXP (arg->stack_slot, 0)) == PLUS) lower_bound = INTVAL (XEXP (XEXP (arg->stack_slot, 0), 1)); else lower_bound = 0; - upper_bound = lower_bound + arg->size.constant; + upper_bound = lower_bound + arg->locate.size.constant; #endif i = lower_bound; @@ -4341,13 +4044,11 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space) if (i < upper_bound) { - /* We need to make a save area. See what mode we can make it. */ - enum machine_mode save_mode - = mode_for_size (arg->size.constant * BITS_PER_UNIT, MODE_INT, 1); - rtx stack_area - = gen_rtx_MEM (save_mode, - memory_address (save_mode, - XEXP (arg->stack_slot, 0))); + /* We need to make a save area. */ + unsigned int size = arg->locate.size.constant * BITS_PER_UNIT; + enum machine_mode save_mode = mode_for_size (size, MODE_INT, 1); + rtx adr = memory_address (save_mode, XEXP (arg->stack_slot, 0)); + rtx stack_area = gen_rtx_MEM (save_mode, adr); if (save_mode == BLKmode) { @@ -4381,11 +4082,10 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space) partial = arg->partial; } - if (reg != 0 && partial == 0) - /* Being passed entirely in a register. We shouldn't be called in - this case. */ - abort (); - + /* Being passed entirely in a register. We shouldn't be called in + this case. */ + gcc_assert (reg == 0 || partial != 0); + /* If this arg needs special alignment, don't load the registers here. */ if (arg->n_aligned_regs != 0) @@ -4433,6 +4133,13 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space) stack_arg_under_construction--; } + /* Check for overlap with already clobbered argument area. */ + if ((flags & ECF_SIBCALL) + && MEM_P (arg->value) + && mem_overlaps_already_clobbered_arg_p (XEXP (arg->value, 0), + arg->locate.size.constant)) + sibcall_failure = 1; + /* Don't allow anything left on stack from computation of argument to alloca. */ if (flags & ECF_MAY_BE_ALLOCA) @@ -4473,10 +4180,10 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space) /* This isn't already where we want it on the stack, so put it there. This can either be done with push or copy insns. */ - emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), NULL_RTX, + emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), NULL_RTX, PARM_BOUNDARY, partial, reg, used - size, argblock, - ARGS_SIZE_RTX (arg->offset), reg_parm_stack_space, - ARGS_SIZE_RTX (arg->alignment_pad)); + ARGS_SIZE_RTX (arg->locate.offset), reg_parm_stack_space, + ARGS_SIZE_RTX (arg->locate.alignment_pad)); /* Unless this is a partially-in-register argument, the argument is now in the stack. */ @@ -4498,30 +4205,29 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space) /* Round its size up to a multiple of the allocation unit for arguments. */ - if (arg->size.var != 0) + if (arg->locate.size.var != 0) { excess = 0; - size_rtx = ARGS_SIZE_RTX (arg->size); + size_rtx = ARGS_SIZE_RTX (arg->locate.size); } else { - /* PUSH_ROUNDING has no effect on us, because - emit_push_insn for BLKmode is careful to avoid it. */ - excess = (arg->size.constant - int_size_in_bytes (TREE_TYPE (pval)) - + partial * UNITS_PER_WORD); + /* PUSH_ROUNDING has no effect on us, because emit_push_insn + for BLKmode is careful to avoid it. */ + excess = (arg->locate.size.constant + - int_size_in_bytes (TREE_TYPE (pval)) + + partial); size_rtx = expand_expr (size_in_bytes (TREE_TYPE (pval)), NULL_RTX, TYPE_MODE (sizetype), 0); } - /* Some types will require stricter alignment, which will be - provided for elsewhere in argument layout. */ - parm_align = MAX (PARM_BOUNDARY, TYPE_ALIGN (TREE_TYPE (pval))); + parm_align = arg->locate.boundary; /* When an argument is padded down, the block is aligned to PARM_BOUNDARY, but the actual argument isn't. */ if (FUNCTION_ARG_PADDING (arg->mode, TREE_TYPE (pval)) == downward) { - if (arg->size.var) + if (arg->locate.size.var) parm_align = BITS_PER_UNIT; else if (excess) { @@ -4530,10 +4236,10 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space) } } - if ((flags & ECF_SIBCALL) && GET_CODE (arg->value) == MEM) + if ((flags & ECF_SIBCALL) && MEM_P (arg->value)) { /* emit_push_insn might not work properly if arg->value and - argblock + arg->offset areas overlap. */ + argblock + arg->locate.offset areas overlap. */ rtx x = arg->value; int i = 0; @@ -4546,18 +4252,18 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space) if (XEXP (x, 0) != current_function_internal_arg_pointer) i = INTVAL (XEXP (XEXP (x, 0), 1)); - /* expand_call should ensure this */ - if (arg->offset.var || GET_CODE (size_rtx) != CONST_INT) - abort (); + /* expand_call should ensure this. */ + gcc_assert (!arg->locate.offset.var + && GET_CODE (size_rtx) == CONST_INT); - if (arg->offset.constant > i) + if (arg->locate.offset.constant > i) { - if (arg->offset.constant < i + INTVAL (size_rtx)) + if (arg->locate.offset.constant < i + INTVAL (size_rtx)) sibcall_failure = 1; } - else if (arg->offset.constant < i) + else if (arg->locate.offset.constant < i) { - if (i < arg->offset.constant + INTVAL (size_rtx)) + if (i < arg->locate.offset.constant + INTVAL (size_rtx)) sibcall_failure = 1; } } @@ -4565,8 +4271,8 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space) emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), size_rtx, parm_align, partial, reg, excess, argblock, - ARGS_SIZE_RTX (arg->offset), reg_parm_stack_space, - ARGS_SIZE_RTX (arg->alignment_pad)); + ARGS_SIZE_RTX (arg->locate.offset), reg_parm_stack_space, + ARGS_SIZE_RTX (arg->locate.alignment_pad)); /* Unless this is a partially-in-register argument, the argument is now in the stack. @@ -4580,6 +4286,14 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space) arg->value = arg->stack_slot; } + if (arg->reg && GET_CODE (arg->reg) == PARALLEL) + { + tree type = TREE_TYPE (arg->tree_value); + arg->parallel_value + = emit_group_load_into_temps (arg->reg, arg->value, type, + int_size_in_bytes (type)); + } + /* Mark all slots this store used. */ if (ACCUMULATE_OUTGOING_ARGS && !(flags & ECF_SIBCALL) && argblock && ! variable_size && arg->stack) @@ -4590,10 +4304,6 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space) be deferred during the rest of the arguments. */ NO_DEFER_POP; - /* ANSI doesn't require a sequence point here, - but PCC has one, so this will avoid some problems. */ - emit_queue (); - /* Free any temporary slots made in processing this argument. Show that we might have taken the address of something and pushed that as an operand. */ @@ -4604,26 +4314,33 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space) return sibcall_failure; } -/* Nonzero if we do not know how to pass TYPE solely in registers. - We cannot do so in the following cases: +/* Nonzero if we do not know how to pass TYPE solely in registers. */ + +bool +must_pass_in_stack_var_size (enum machine_mode mode ATTRIBUTE_UNUSED, + tree type) +{ + if (!type) + return false; + + /* If the type has variable size... */ + if (TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST) + return true; - - if the type has variable size - - if the type is marked as addressable (it is required to be constructed - into the stack) - - if the padding and mode of the type is such that a copy into a register - would put it into the wrong part of the register. + /* If the type is marked as addressable (it is required + to be constructed into the stack)... */ + if (TREE_ADDRESSABLE (type)) + return true; - Which padding can't be supported depends on the byte endianness. + return false; +} - A value in a register is implicitly padded at the most significant end. - On a big-endian machine, that is the lower end in memory. - So a value padded in memory at the upper end can't go in a register. - For a little-endian machine, the reverse is true. */ +/* Another version of the TARGET_MUST_PASS_IN_STACK hook. This one + takes trailing padding of a structure into account. */ +/* ??? Should be able to merge these two by examining BLOCK_REG_PADDING. */ bool -default_must_pass_in_stack (mode, type) - enum machine_mode mode; - tree type; +must_pass_in_stack_var_size_or_pad (enum machine_mode mode, tree type) { if (!type) return false;