X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Fcalls.c;h=a6a071a09f80f22d243eca2bdda980bc16953b54;hp=ccefb54992c224088005ee2c6f86bcc603a40adf;hb=f8cfcdd05b74f4abbbf3d6c35d5d5b8881ee7d0e;hpb=e9ec9980e93e717db5eb841f8a60c1dd51f3fe9d diff --git a/gcc/calls.c b/gcc/calls.c index ccefb54992c..a6a071a09f8 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, 2004 Free Software Foundation, Inc. + 1999, 2000, 2001, 2002, 2003, 2004, 2005 + Free Software Foundation, Inc. This file is part of GCC. @@ -64,6 +65,9 @@ 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; @@ -115,10 +119,7 @@ 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 (tree, int); -static int calls_function_1 (tree, int); +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, @@ -146,132 +147,15 @@ 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 *, - int); -static tree fix_unsafe_tree (tree); -static bool shift_returned_value (tree, rtx *); + 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 (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 (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 (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 and blocks can contain calls. - Blocks were handled above. */ - if (! IS_EXPR_CODE_CLASS (class)) - 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. @@ -283,8 +167,6 @@ rtx prepare_call_address (rtx funexp, rtx static_chain_value, rtx *call_fusage, int reg_parm_seen, int sibcallp) { - funexp = protect_from_queue (funexp, 0); - /* 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) @@ -303,6 +185,7 @@ prepare_call_address (rtx funexp, rtx static_chain_value, 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 (REG_P (static_chain_rtx)) @@ -471,7 +354,7 @@ emit_call_1 (rtx funexp, tree fntree, tree fndecl ATTRIBUTE_UNUSED, } else #endif - abort (); + gcc_unreachable (); /* Find the call we just emitted. */ call_insn = last_call_insn (); @@ -512,9 +395,6 @@ emit_call_1 (rtx funexp, tree fntree, tree fndecl ATTRIBUTE_UNUSED, 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) { @@ -552,7 +432,7 @@ emit_call_1 (rtx funexp, tree fntree, tree fndecl ATTRIBUTE_UNUSED, if (rounded_stack_size != 0) { - if (ecf_flags & (ECF_SP_DEPRESSED | ECF_NORETURN | ECF_LONGJMP)) + 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 @@ -583,7 +463,7 @@ emit_call_1 (rtx funexp, tree fntree, tree fndecl ATTRIBUTE_UNUSED, 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. */ @@ -600,7 +480,7 @@ special_function_p (tree fndecl, int flags) 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 + && (DECL_CONTEXT (fndecl) == NULL_TREE || TREE_CODE (DECL_CONTEXT (fndecl)) == TRANSLATION_UNIT_DECL) && TREE_PUBLIC (fndecl)) { @@ -642,7 +522,7 @@ special_function_p (tree fndecl, int 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")) @@ -652,13 +532,13 @@ special_function_p (tree fndecl, int flags) else if (tname[0] == 'l' && tname[1] == 'o' && ! strcmp (tname, "longjmp")) - flags |= ECF_LONGJMP; + 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 (tree fndecl) @@ -705,10 +585,17 @@ flags_from_decl_or_type (tree exp) 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; + if (DECL_IS_NOVOPS (exp)) + flags |= ECF_NOVOPS; + if (TREE_NOTHROW (exp)) flags |= ECF_NOTHROW; @@ -764,7 +651,8 @@ call_expr_flags (tree t) Set REG_PARM_SEEN if we encounter a register parameter. */ static void -precompute_register_parameters (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; @@ -782,10 +670,6 @@ precompute_register_parameters (int num_actuals, struct arg_data *args, int *reg 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 @@ -803,6 +687,17 @@ precompute_register_parameters (int num_actuals, struct arg_data *args, int *reg 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. @@ -811,13 +706,13 @@ precompute_register_parameters (int num_actuals, struct arg_data *args, int *reg register parameters. This is to avoid reload conflicts while loading the parameters registers. */ - 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) - || 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); } } @@ -942,10 +837,19 @@ store_unaligned_arguments_into_pseudos (struct arg_data *args, int num_actuals) < (unsigned int) MIN (BIGGEST_ALIGNMENT, BITS_PER_WORD))) { int bytes = int_size_in_bytes (TREE_TYPE (args[i].tree_value)); - int nregs = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD; int endian_correction = 0; - args[i].n_aligned_regs = args[i].partial ? args[i].partial : nregs; + 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 = xmalloc (sizeof (rtx) * args[i].n_aligned_regs); /* Structures smaller than a word are normally aligned to the @@ -971,7 +875,7 @@ store_unaligned_arguments_into_pseudos (struct arg_data *args, int num_actuals) args[i].aligned_regs[j] = reg; word = extract_bit_field (word, bitsize, 0, 1, NULL_RTX, - word_mode, word_mode, BITS_PER_WORD); + word_mode, word_mode); /* There is no need to restrict this code to loading items in TYPE_ALIGN sized hunks. The bitfield instructions can @@ -988,7 +892,7 @@ store_unaligned_arguments_into_pseudos (struct arg_data *args, int num_actuals) bytes -= bitsize / BITS_PER_UNIT; store_bit_field (reg, bitsize, endian_correction, word_mode, - word, BITS_PER_WORD); + word); } } } @@ -1012,7 +916,7 @@ store_unaligned_arguments_into_pseudos (struct arg_data *args, int num_actuals) and may be modified by this routine. OLD_PENDING_ADJ, MUST_PREALLOCATE and FLAGS are pointers to integer - flags which may may be modified by this routine. + flags which may may be modified by this routine. MAY_TAILCALL is cleared if we encounter an invisible pass-by-reference that requires allocation of stack space. @@ -1083,7 +987,7 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED, 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 @@ -1093,64 +997,33 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED, with those made by function.c. */ /* See if this argument should be passed by invisible reference. */ - if (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. */ + 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 -#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 - ) + || (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); - - /* 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 (args[i].tree_value) - || !TREE_STATIC (args[i].tree_value))) + /* 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 = 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); - *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 { @@ -1184,12 +1057,15 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED, 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; } } @@ -1215,14 +1091,12 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED, 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 @@ -1314,8 +1188,7 @@ compute_argument_block_size (int reg_parm_stack_space, /* 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); } @@ -1372,58 +1245,42 @@ precompute_arguments (int flags, int num_actuals, struct arg_data *args) int i; /* If this is a libcall, then precompute all arguments so that we do not - get extraneous instructions emitted as part of the libcall sequence. - - If this target defines ACCUMULATE_OUTGOING_ARGS to true, then we must - precompute all arguments that contain function calls. Otherwise, - computing arguments for a subcall may clobber arguments for this call. - - If this target defines ACCUMULATE_OUTGOING_ARGS to false, then we only - need to precompute arguments that change the stack pointer, such as calls - to alloca, and calls that do not pop all of their arguments. */ + 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); + 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); - } + /* 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 @@ -1505,6 +1362,7 @@ compute_argument_addresses (struct arg_data *args, rtx argblock, int num_actuals 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) @@ -1517,9 +1375,18 @@ compute_argument_addresses (struct arg_data *args, rtx argblock, int 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)); @@ -1528,9 +1395,9 @@ compute_argument_addresses (struct arg_data *args, rtx argblock, int 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 @@ -1575,7 +1442,6 @@ rtx_for_function_call (tree fndecl, tree addr) push_temp_slots (); funexp = expand_expr (addr, NULL_RTX, VOIDmode, 0); pop_temp_slots (); /* FUNEXP can't be BLKmode. */ - emit_queue (); } return funexp; } @@ -1612,8 +1478,13 @@ load_register_parameters (struct arg_data *args, int num_actuals, we just use a normal move insn. This value can be zero if the argument is a zero size structure with no fields. */ nregs = -1; - if (partial) - nregs = partial; + 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)); @@ -1626,11 +1497,7 @@ load_register_parameters (struct arg_data *args, int num_actuals, locations. The Irix 6 ABI has examples of this. */ if (GET_CODE (reg) == PARALLEL) - { - tree type = TREE_TYPE (args[i].tree_value); - emit_group_load (reg, args[i].value, type, - int_size_in_bytes (type)); - } + 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, @@ -1655,8 +1522,9 @@ load_register_parameters (struct arg_data *args, int num_actuals, 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_binop (word_mode, ashl_optab, reg, - GEN_INT (shift), reg, 1, OPTAB_WIDEN); + x = expand_shift (LSHIFT_EXPR, word_mode, reg, + build_int_cst (NULL_TREE, shift), + reg, 1); if (x != reg) emit_move_insn (reg, x); } @@ -1688,11 +1556,13 @@ load_register_parameters (struct arg_data *args, int num_actuals, 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; - optab dir = BYTES_BIG_ENDIAN ? lshr_optab : ashl_optab; + enum tree_code dir = BYTES_BIG_ENDIAN ? RSHIFT_EXPR + : LSHIFT_EXPR; emit_move_insn (x, tem); - x = expand_binop (word_mode, dir, x, GEN_INT (shift), - ri, 1, OPTAB_WIDEN); + x = expand_shift (dir, word_mode, x, + build_int_cst (NULL_TREE, shift), + ri, 1); if (x != ri) emit_move_insn (ri, x); } @@ -1713,8 +1583,8 @@ load_register_parameters (struct arg_data *args, int num_actuals, 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); + else if (nregs > 0) + use_regs (call_fusage, REGNO (reg), nregs); } } } @@ -1731,14 +1601,14 @@ load_register_parameters (struct arg_data *args, int num_actuals, static int combine_pending_stack_adjustment_and_call (int unadjusted_args_size, struct args_size *args_size, - int preferred_unit_stack_boundary) + 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) @@ -1873,68 +1743,27 @@ check_sibcall_argument_overlap (rtx insn, struct arg_data *arg, int mark_stored_ return insn != NULL_RTX; } -static tree -fix_unsafe_tree (tree t) -{ - switch (unsafe_for_reeval (t)) - { - case 0: /* Safe. */ - break; - - case 1: /* Mildly unsafe. */ - t = unsave_expr (t); - break; - - 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; - - default: - abort (); - } - return t; -} - - -/* If function value *VALUE was returned at the most significant end of a - register, shift it towards the least significant end and convert it to - TYPE's mode. Return true and update *VALUE if some action was needed. +/* 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. */ - TYPE is the type of the function's return value, which is known not - to have mode BLKmode. */ - -static bool -shift_returned_value (tree type, rtx *value) +bool +shift_return_value (enum machine_mode mode, bool left_p, rtx value) { - if (targetm.calls.return_in_msb (type)) - { - HOST_WIDE_INT shift; + HOST_WIDE_INT shift; - shift = (GET_MODE_BITSIZE (GET_MODE (*value)) - - BITS_PER_UNIT * int_size_in_bytes (type)); - if (shift > 0) - { - /* Shift the value into the low part of the register. */ - *value = expand_binop (GET_MODE (*value), lshr_optab, *value, - GEN_INT (shift), 0, 1, OPTAB_WIDEN); - - /* Truncate it to the type's mode, or its integer equivalent. - This is subject to TRULY_NOOP_TRUNCATION. */ - *value = convert_to_mode (int_mode_for_mode (TYPE_MODE (type)), - *value, 0); - - /* Now convert it to the final form. */ - *value = gen_lowpart (TYPE_MODE (type), *value); - return true; - } - } - return false; + 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; + + /* 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; } /* Remove all REG_EQUIV notes found in the insn chain. */ @@ -1961,45 +1790,6 @@ purge_reg_equiv_notes (void) } } -/* Clear RTX_UNCHANGING_P flag of incoming argument MEMs. */ - -static void -purge_mem_unchanging_flag (rtx x) -{ - RTX_CODE code; - int i, j; - const char *fmt; - - if (x == NULL_RTX) - return; - - code = GET_CODE (x); - - if (code == MEM) - { - if (RTX_UNCHANGING_P (x) - && (XEXP (x, 0) == current_function_internal_arg_pointer - || (GET_CODE (XEXP (x, 0)) == PLUS - && XEXP (XEXP (x, 0), 0) == - current_function_internal_arg_pointer - && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT))) - RTX_UNCHANGING_P (x) = 0; - return; - } - - /* Scan all subexpressions. */ - fmt = GET_RTX_FORMAT (code); - for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++) - { - if (*fmt == 'e') - purge_mem_unchanging_flag (XEXP (x, i)); - else if (*fmt == 'E') - for (j = 0; j < XVECLEN (x, i); j++) - purge_mem_unchanging_flag (XVECEXP (x, i, j)); - } -} - - /* Generate all the code for a function call and return an rtx for its value. Store the value in TARGET (specified as an rtx) if convenient. @@ -2117,9 +1907,9 @@ expand_call (tree exp, rtx target, int 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. */ @@ -2208,7 +1998,7 @@ expand_call (tree exp, rtx target, int ignore) structure_value_addr = expand_expr (return_arg, NULL_RTX, VOIDmode, EXPAND_NORMAL); } - else if (target && GET_CODE (target) == MEM) + else if (target && MEM_P (target)) structure_value_addr = XEXP (target, 0); else { @@ -2236,8 +2026,7 @@ expand_call (tree exp, rtx target, int 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); /* Munge the tree to split complex arguments into their imaginary @@ -2266,7 +2055,7 @@ expand_call (tree exp, rtx target, int ignore) || (ACCUMULATE_OUTGOING_ARGS && stack_arg_under_construction && structure_value_addr == virtual_outgoing_args_rtx) - ? copy_addr_to_reg (convert_memory_address + ? copy_addr_to_reg (convert_memory_address (Pmode, structure_value_addr)) : structure_value_addr); @@ -2372,25 +2161,13 @@ expand_call (tree exp, rtx target, int 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. + 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. - - If current_nesting_level () == 0, we're being called after - the function body has been expanded. This can happen when - setting up trampolines in expand_function_end. */ if (currently_expanding_call++ != 0 || !flag_optimize_sibling_calls - || !rtx_equal_function_value_matters - || current_nesting_level () == 0 - || any_pending_cleanups () || args_size.var || lookup_stmt_eh_region (exp) >= 0) try_tail_call = 0; @@ -2413,7 +2190,7 @@ expand_call (tree exp, rtx target, int ignore) || !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 @@ -2431,52 +2208,6 @@ expand_call (tree exp, rtx target, int ignore) || !lang_hooks.decls.ok_for_sibcall (fndecl)) try_tail_call = 0; - if (try_tail_call) - { - 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); - } - /* 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 ()) - try_tail_call = 0; - } - - /* Ensure current function's preferred stack boundary is at least what we need. We don't have to increase alignment for recursive functions. */ @@ -2488,8 +2219,6 @@ expand_call (tree exp, rtx target, int 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. */ @@ -2498,7 +2227,7 @@ expand_call (tree exp, rtx target, int ignore) int sibcall_failure = 0; /* We want to emit any pending stack adjustments before the tail recursion "call". That way we know any adjustment after the tail - recursion call can be ignored if we indeed use the tail + recursion call can be ignored if we indeed use the tail call expansion. */ int save_pending_stack_adjust = 0; int save_stack_pointer_delta = 0; @@ -2507,10 +2236,6 @@ expand_call (tree exp, rtx target, int 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; @@ -2532,15 +2257,6 @@ expand_call (tree exp, rtx target, int 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 @@ -2915,7 +2631,7 @@ expand_call (tree exp, rtx target, int ignore) structure value. */ if (pass != 0 && structure_value_addr && ! structure_value_addr_parm) { - structure_value_addr + structure_value_addr = convert_memory_address (Pmode, structure_value_addr); emit_move_insn (struct_value, force_reg (Pmode, @@ -2932,9 +2648,6 @@ expand_call (tree exp, rtx target, int ignore) 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 (); @@ -2954,8 +2667,8 @@ expand_call (tree exp, rtx target, int 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, exp, fndecl, funtype, unadjusted_args_size, @@ -2963,6 +2676,20 @@ expand_call (tree exp, rtx target, int ignore) 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 @@ -2978,7 +2705,7 @@ expand_call (tree exp, rtx target, int ignore) /* Expansion of block moves possibly introduced a loop that may not appear inside libcall block. */ for (insn = insns; insn; insn = NEXT_INSN (insn)) - if (GET_CODE (insn) == JUMP_INSN) + if (JUMP_P (insn)) failed = true; if (failed) @@ -2999,12 +2726,12 @@ expand_call (tree exp, rtx target, int ignore) end_sequence (); if (flag_unsafe_math_optimizations && fndecl - && DECL_BUILT_IN (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), + note = gen_rtx_fmt_e (SQRT, + GET_MODE (temp), args[0].initial_value); else { @@ -3015,7 +2742,7 @@ expand_call (tree exp, rtx target, int ignore) 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, @@ -3056,19 +2783,18 @@ expand_call (tree exp, rtx target, int 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); @@ -3083,27 +2809,14 @@ expand_call (tree exp, rtx target, int ignore) } } - if (flags & ECF_LONGJMP) - current_function_calls_longjmp = 1; - /* 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 ()) - { - 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)), @@ -3133,7 +2846,6 @@ expand_call (tree exp, rtx target, int ignore) | TYPE_QUAL_CONST)); target = assign_temp (nt, 0, 1, 1); - preserve_temp_slots (target); } if (! rtx_equal_p (target, valreg)) @@ -3158,7 +2870,7 @@ expand_call (tree exp, rtx target, int ignore) /* 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 (GET_CODE (target) == MEM) + if (MEM_P (target)) sibcall_failure = 1; } else if (TYPE_MODE (TREE_TYPE (exp)) == BLKmode) @@ -3169,45 +2881,40 @@ expand_call (tree exp, rtx target, int ignore) sibcall_failure = 1; } else - { - if (shift_returned_value (TREE_TYPE (exp), &valreg)) - sibcall_failure = 1; - - target = copy_to_reg (valreg); - } + target = copy_to_reg (valreg); if (targetm.calls.promote_function_return(funtype)) { - /* 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; - - /* 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); + } } /* If size of args is variable or this was a constructor call for a stack @@ -3218,6 +2925,7 @@ expand_call (tree exp, rtx target, int 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; @@ -3265,30 +2973,6 @@ expand_call (tree exp, rtx target, int ignore) 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 (); - } - - /* If this function is returning into a memory location marked as - readonly, it means it is initializing that location. We normally treat - functions as not clobbering such locations, so we need to specify that - this one does. We do this by adding the appropriate CLOBBER to the - CALL_INSN function usage list. This cannot be done by emitting a - standalone CLOBBER after the call because the latter would be ignored - by at least the delay slot scheduling pass. We do this now instead of - adding to call_fusage before the call to emit_call_1 because TARGET - may be modified in the meantime. */ - if (structure_value_addr != 0 && target != 0 - && GET_CODE (target) == MEM && RTX_UNCHANGING_P (target)) - add_function_usage_to - (last_call_insn (), - gen_rtx_EXPR_LIST (VOIDmode, gen_rtx_CLOBBER (VOIDmode, target), - NULL_RTX)); - insns = get_insns (); end_sequence (); @@ -3317,10 +3001,9 @@ expand_call (tree exp, rtx target, int ignore) normal_call_insns = insns; /* Verify that we've deallocated all the stack we used. */ - if (! (flags & (ECF_NORETURN | ECF_LONGJMP)) - && 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, @@ -3351,7 +3034,6 @@ expand_call (tree exp, rtx target, int ignore) clear_pending_stack_adjust (); emit_insn (gen_rtx_CLOBBER (VOIDmode, stack_pointer_rtx)); emit_move_insn (virtual_stack_dynamic_rtx, stack_pointer_rtx); - save_stack_pointer (); } return target; @@ -3370,37 +3052,12 @@ expand_call (tree exp, rtx target, int ignore) void fixup_tail_calls (void) { - rtx insn; - tree arg; - purge_reg_equiv_notes (); - - /* A sibling call sequence also may invalidate RTX_UNCHANGING_P - flag of some incoming arguments MEM RTLs, because it can write into - those slots. We clear all those bits now. - - This is (slight) overkill, we could keep track of which arguments - we actually write into. */ - for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) - { - if (INSN_P (insn)) - purge_mem_unchanging_flag (PATTERN (insn)); - } - - /* Similarly, invalidate RTX_UNCHANGING_P for any incoming - arguments passed in registers. */ - for (arg = DECL_ARGUMENTS (current_function_decl); - arg; - arg = TREE_CHAIN (arg)) - { - if (REG_P (DECL_RTL (arg))) - RTX_UNCHANGING_P (DECL_RTL (arg)) = false; - } } /* Traverse an argument list in VALUES and expand all complex arguments into their components. */ -tree +static tree split_complex_values (tree values) { tree p; @@ -3454,7 +3111,7 @@ split_complex_values (tree values) /* Traverse a list of TYPES and expand all complex types into their components. */ -tree +static tree split_complex_types (tree types) { tree p; @@ -3581,9 +3238,6 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, 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; @@ -3611,7 +3265,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, 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); @@ -3658,10 +3312,11 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx 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 (!REG_P (addr) && GET_CODE (addr) != MEM + if (!REG_P (addr) && !MEM_P (addr) && ! (CONSTANT_P (addr) && LEGITIMATE_CONSTANT_P (addr))) addr = force_operand (addr, NULL_RTX); @@ -3670,10 +3325,8 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, 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 @@ -3699,28 +3352,19 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, /* 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 (); - - /* 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 (!REG_P (val) && 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. */ @@ -3740,25 +3384,14 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, 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), 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), @@ -3772,19 +3405,14 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, 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 @@ -3795,8 +3423,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, argvec[count].partial, NULL_TREE, &args_size, &argvec[count].locate); - if (argvec[count].locate.size.var) - abort (); + gcc_assert (!argvec[count].locate.size.var); if (argvec[count].reg == 0 || argvec[count].partial != 0 || reg_parm_stack_space > 0) @@ -4017,6 +3644,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, 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; @@ -4024,7 +3652,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, /* 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, NULL_TREE, 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); @@ -4059,8 +3687,8 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, ? 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 (); @@ -4084,19 +3712,18 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, 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); @@ -4128,7 +3755,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, if (GET_CODE (valreg) == PARALLEL) { temp = gen_reg_rtx (outmode); - emit_group_store (temp, valreg, NULL_TREE, + emit_group_store (temp, valreg, NULL_TREE, GET_MODE_SIZE (outmode)); valreg = temp; } @@ -4220,7 +3847,6 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, 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 @@ -4373,11 +3999,10 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags, 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) @@ -4497,27 +4122,16 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags, } else { - /* PUSH_ROUNDING has no effect on us, because - emit_push_insn for BLKmode is careful to avoid it. */ - if (reg && GET_CODE (reg) == PARALLEL) - { - /* Use the size of the elt to compute excess. */ - rtx elt = XEXP (XVECEXP (reg, 0, 0), 0); - excess = (arg->locate.size.constant - - int_size_in_bytes (TREE_TYPE (pval)) - + partial * GET_MODE_SIZE (GET_MODE (elt))); - } - else - excess = (arg->locate.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. */ @@ -4532,7 +4146,7 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags, } } - 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->locate.offset areas overlap. */ @@ -4549,8 +4163,8 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags, i = INTVAL (XEXP (XEXP (x, 0), 1)); /* expand_call should ensure this. */ - if (arg->locate.offset.var || GET_CODE (size_rtx) != CONST_INT) - abort (); + gcc_assert (!arg->locate.offset.var + && GET_CODE (size_rtx) == CONST_INT); if (arg->locate.offset.constant > i) { @@ -4582,6 +4196,14 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags, 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) @@ -4592,10 +4214,6 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags, 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. */ @@ -4606,24 +4224,33 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags, 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 (enum machine_mode mode, tree type) +must_pass_in_stack_var_size_or_pad (enum machine_mode mode, tree type) { if (!type) return false;