X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fcalls.c;h=13167a620a4e8db26642caf9993fe985c27d962e;hb=f96d34f19f87467b4ca672d423857405c2913bc6;hp=a3d35b3bf5c334e3abb4891e0ecb17228d72693d;hpb=590c31668736f0790e7e8a2e2811a29f2a7112bc;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/calls.c b/gcc/calls.c index a3d35b3bf5c..13167a620a4 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -1,6 +1,6 @@ /* 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, 2005, 2006, 2007 + 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. This file is part of GCC. @@ -39,6 +39,7 @@ along with GCC; see the file COPYING3. If not see #include "sbitmap.h" #include "langhooks.h" #include "target.h" +#include "debug.h" #include "cgraph.h" #include "except.h" #include "dbgcnt.h" @@ -132,11 +133,11 @@ 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, struct arg_data *); -static int compute_argument_block_size (int, struct args_size *, tree, int); +static int compute_argument_block_size (int, struct args_size *, tree, tree, int); static void initialize_argument_information (int, struct arg_data *, struct args_size *, int, tree, tree, - tree, CUMULATIVE_ARGS *, int, + tree, tree, CUMULATIVE_ARGS *, int, rtx *, int *, int *, int *, bool *, bool); static void compute_argument_addresses (struct arg_data *, rtx, int); @@ -166,7 +167,7 @@ static void restore_fixed_argument_area (rtx, rtx, int, int); CALL_INSN_FUNCTION_USAGE information. */ rtx -prepare_call_address (rtx funexp, rtx static_chain_value, +prepare_call_address (tree fndecl, rtx funexp, rtx static_chain_value, rtx *call_fusage, int reg_parm_seen, int sibcallp) { /* Make a valid memory address and copy constants through pseudo-regs, @@ -187,11 +188,15 @@ prepare_call_address (rtx funexp, rtx static_chain_value, if (static_chain_value != 0) { + rtx chain; + + gcc_assert (fndecl); + chain = targetm.calls.static_chain (fndecl, false); 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)) - use_reg (call_fusage, static_chain_rtx); + emit_move_insn (chain, static_chain_value); + if (REG_P (chain)) + use_reg (call_fusage, chain); } return funexp; @@ -238,7 +243,7 @@ prepare_call_address (rtx funexp, rtx static_chain_value, denote registers used by the called function. */ static void -emit_call_1 (rtx funexp, tree fntree, tree fndecl ATTRIBUTE_UNUSED, +emit_call_1 (rtx funexp, tree fntree ATTRIBUTE_UNUSED, tree fndecl ATTRIBUTE_UNUSED, tree funtype ATTRIBUTE_UNUSED, HOST_WIDE_INT stack_size ATTRIBUTE_UNUSED, HOST_WIDE_INT rounded_stack_size, @@ -376,19 +381,8 @@ emit_call_1 (rtx funexp, tree fntree, tree fndecl ATTRIBUTE_UNUSED, if (ecf_flags & ECF_LOOPING_CONST_OR_PURE) RTL_LOOPING_CONST_OR_PURE_CALL_P (call_insn) = 1; - /* If this call can't throw, attach a REG_EH_REGION reg note to that - effect. */ - if (ecf_flags & ECF_NOTHROW) - add_reg_note (call_insn, REG_EH_REGION, const0_rtx); - else - { - int rn = lookup_expr_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) - add_reg_note (call_insn, REG_EH_REGION, GEN_INT (rn)); - } + /* Create a nothrow REG_EH_REGION note, if needed. */ + make_reg_eh_region_note (call_insn, ecf_flags, 0); if (ecf_flags & ECF_NORETURN) add_reg_note (call_insn, REG_NORETURN, const0_rtx); @@ -401,6 +395,11 @@ emit_call_1 (rtx funexp, tree fntree, tree fndecl ATTRIBUTE_UNUSED, SIBLING_CALL_P (call_insn) = ((ecf_flags & ECF_SIBCALL) != 0); + /* Record debug information for virtual calls. */ + if (flag_enable_icf_debug && fndecl == NULL) + (*debug_hooks->virtual_call_token) (CALL_EXPR_FN (fntree), + INSN_UID (call_insn)); + /* Restore this now, so that we do defer pops for this call's args if the context of the call as a whole permits. */ inhibit_defer_pop = old_inhibit_defer_pop; @@ -498,10 +497,14 @@ special_function_p (const_tree fndecl, int flags) && ! strcmp (name, "__builtin_alloca")))) flags |= ECF_MAY_BE_ALLOCA; - /* Disregard prefix _, __ or __x. */ + /* Disregard prefix _, __, __x or __builtin_. */ if (name[0] == '_') { - if (name[1] == '_' && name[2] == 'x') + if (name[1] == '_' + && name[2] == 'b' + && !strncmp (name + 3, "uiltin_", 7)) + tname += 10; + else if (name[1] == '_' && name[2] == 'x') tname += 3; else if (name[1] == '_') tname += 2; @@ -837,7 +840,8 @@ store_unaligned_arguments_into_pseudos (struct arg_data *args, int num_actuals) for (i = 0; i < num_actuals; i++) if (args[i].reg != 0 && ! args[i].pass_on_stack && args[i].mode == BLKmode - && (TYPE_ALIGN (TREE_TYPE (args[i].tree_value)) + && MEM_P (args[i].value) + && (MEM_ALIGN (args[i].value) < (unsigned int) MIN (BIGGEST_ALIGNMENT, BITS_PER_WORD))) { int bytes = int_size_in_bytes (TREE_TYPE (args[i].tree_value)); @@ -937,13 +941,14 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED, struct args_size *args_size, int n_named_args ATTRIBUTE_UNUSED, tree exp, tree struct_value_addr_value, - tree fndecl, + tree fndecl, tree fntype, 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) { + location_t loc = EXPR_LOCATION (exp); /* 1 if scanning parms front to back, -1 if scanning back to front. */ int inc; @@ -991,7 +996,6 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED, && targetm.calls.split_complex_arg (argtype)) { tree subtype = TREE_TYPE (argtype); - arg = save_expr (arg); args[j].tree_value = build1 (REALPART_EXPR, subtype, arg); j += inc; args[j].tree_value = build1 (IMAGPART_EXPR, subtype, arg); @@ -1050,6 +1054,7 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED, || (callee_copies && !TREE_ADDRESSABLE (type) && (base = get_base_address (args[i].tree_value)) + && TREE_CODE (base) != SSA_NAME && (!DECL_P (base) || MEM_P (DECL_RTL (base))))) { /* We can't use sibcalls if a callee-copied argument is @@ -1057,7 +1062,8 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED, 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); + args[i].tree_value = build_fold_addr_expr_loc (loc, + args[i].tree_value); type = TREE_TYPE (args[i].tree_value); if (*ecf_flags & ECF_CONST) @@ -1109,17 +1115,15 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED, *ecf_flags &= ~(ECF_PURE | ECF_LOOPING_CONST_OR_PURE); args[i].tree_value - = build_fold_addr_expr (make_tree (type, copy)); + = build_fold_addr_expr_loc (loc, make_tree (type, copy)); type = TREE_TYPE (args[i].tree_value); *may_tailcall = false; } } - mode = TYPE_MODE (type); unsignedp = TYPE_UNSIGNED (type); - - if (targetm.calls.promote_function_args (fndecl ? TREE_TYPE (fndecl) : 0)) - mode = promote_mode (type, mode, &unsignedp, 1); + mode = promote_function_mode (type, TYPE_MODE (type), &unsignedp, + fndecl ? TREE_TYPE (fndecl) : fntype, 0); args[i].unsignedp = unsignedp; args[i].mode = mode; @@ -1204,6 +1208,7 @@ static int compute_argument_block_size (int reg_parm_stack_space, struct args_size *args_size, tree fndecl ATTRIBUTE_UNUSED, + tree fntype ATTRIBUTE_UNUSED, int preferred_stack_boundary ATTRIBUTE_UNUSED) { int unadjusted_args_size = args_size->constant; @@ -1241,7 +1246,7 @@ compute_argument_block_size (int reg_parm_stack_space, /* The area corresponding to register parameters is not to count in the size of the block we need. So make the adjustment. */ - if (! OUTGOING_REG_PARM_STACK_SPACE ((!fndecl ? NULL_TREE : TREE_TYPE (fndecl)))) + if (! OUTGOING_REG_PARM_STACK_SPACE ((!fndecl ? fntype : TREE_TYPE (fndecl)))) args_size->var = size_binop (MINUS_EXPR, args_size->var, ssize_int (reg_parm_stack_space)); @@ -1262,7 +1267,7 @@ compute_argument_block_size (int reg_parm_stack_space, args_size->constant = MAX (args_size->constant, reg_parm_stack_space); - if (! OUTGOING_REG_PARM_STACK_SPACE ((!fndecl ? NULL_TREE : TREE_TYPE (fndecl)))) + if (! OUTGOING_REG_PARM_STACK_SPACE ((!fndecl ? fntype : TREE_TYPE (fndecl)))) args_size->constant -= reg_parm_stack_space; } return unadjusted_args_size; @@ -1298,29 +1303,33 @@ precompute_arguments (int num_actuals, struct arg_data *args) for (i = 0; i < num_actuals; i++) { + tree type; enum machine_mode mode; if (TREE_CODE (args[i].tree_value) != CALL_EXPR) continue; /* If this is an addressable type, we cannot pre-evaluate it. */ - gcc_assert (!TREE_ADDRESSABLE (TREE_TYPE (args[i].tree_value))); + type = TREE_TYPE (args[i].tree_value); + gcc_assert (!TREE_ADDRESSABLE (type)); args[i].initial_value = args[i].value = expand_normal (args[i].tree_value); - mode = TYPE_MODE (TREE_TYPE (args[i].tree_value)); + mode = TYPE_MODE (type); if (mode != args[i].mode) { + int unsignedp = args[i].unsignedp; 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) + && GET_MODE_CLASS (args[i].mode) == MODE_INT + && promote_mode (type, mode, &unsignedp) != args[i].mode) { args[i].initial_value = gen_lowpart_SUBREG (mode, args[i].value); @@ -1328,7 +1337,6 @@ precompute_arguments (int num_actuals, struct arg_data *args) SUBREG_PROMOTED_UNSIGNED_SET (args[i].initial_value, args[i].unsignedp); } -#endif } } } @@ -1423,7 +1431,7 @@ compute_argument_addresses (struct arg_data *args, rtx argblock, int num_actuals && args[i].partial == 0) continue; - if (GET_CODE (offset) == CONST_INT) + if (CONST_INT_P (offset)) addr = plus_constant (arg_reg, INTVAL (offset)); else addr = gen_rtx_PLUS (Pmode, arg_reg, offset); @@ -1450,14 +1458,14 @@ compute_argument_addresses (struct arg_data *args, rtx argblock, int num_actuals boundary = args[i].locate.boundary; if (args[i].locate.where_pad != downward) align = boundary; - else if (GET_CODE (offset) == CONST_INT) + else if (CONST_INT_P (offset)) { align = INTVAL (offset) * BITS_PER_UNIT | boundary; align = align & -align; } set_mem_align (args[i].stack, align); - if (GET_CODE (slot_offset) == CONST_INT) + if (CONST_INT_P (slot_offset)) addr = plus_constant (arg_reg, INTVAL (slot_offset)); else addr = gen_rtx_PLUS (Pmode, arg_reg, slot_offset); @@ -1541,7 +1549,7 @@ mem_overlaps_already_clobbered_arg_p (rtx addr, unsigned HOST_WIDE_INT size) i = 0; else if (GET_CODE (addr) == PLUS && XEXP (addr, 0) == crtl->args.internal_arg_pointer - && GET_CODE (XEXP (addr, 1)) == CONST_INT) + && CONST_INT_P (XEXP (addr, 1))) i = INTVAL (XEXP (addr, 1)); /* Return true for arg pointer based indexed addressing. */ else if (GET_CODE (addr) == PLUS @@ -1918,6 +1926,7 @@ expand_call (tree exp, rtx target, int ignore) /* Data type of the function. */ tree funtype; tree type_arg_types; + tree rettype; /* Declaration of the function being called, or 0 if the function is computed (not known by name). */ tree fndecl = 0; @@ -2013,7 +2022,6 @@ expand_call (tree exp, rtx target, int ignore) int old_stack_pointer_delta = 0; rtx call_fusage; - tree p = CALL_EXPR_FN (exp); tree addr = CALL_EXPR_FN (exp); int i; /* The alignment of the stack, in bits. */ @@ -2036,15 +2044,16 @@ expand_call (tree exp, rtx target, int ignore) } else { - fntype = TREE_TYPE (TREE_TYPE (p)); + fntype = TREE_TYPE (TREE_TYPE (addr)); flags |= flags_from_decl_or_type (fntype); } + rettype = TREE_TYPE (exp); struct_value = targetm.calls.struct_value_rtx (fntype, 0); /* Warn if this value is an aggregate type, regardless of which calling convention we are using for it. */ - if (AGGREGATE_TYPE_P (TREE_TYPE (exp))) + if (AGGREGATE_TYPE_P (rettype)) warning (OPT_Waggregate_return, "function call has aggregate value"); /* If the result of a non looping pure or const function call is @@ -2054,7 +2063,7 @@ expand_call (tree exp, rtx target, int ignore) if ((flags & (ECF_CONST | ECF_PURE)) && (!(flags & ECF_LOOPING_CONST_OR_PURE)) && (ignore || target == const0_rtx - || TYPE_MODE (TREE_TYPE (exp)) == VOIDmode)) + || TYPE_MODE (rettype) == VOIDmode)) { bool volatilep = false; tree arg; @@ -2076,17 +2085,17 @@ expand_call (tree exp, rtx target, int ignore) } #ifdef REG_PARM_STACK_SPACE - reg_parm_stack_space = REG_PARM_STACK_SPACE (fndecl); + reg_parm_stack_space = REG_PARM_STACK_SPACE (!fndecl ? fntype : fndecl); #endif - if (! OUTGOING_REG_PARM_STACK_SPACE ((!fndecl ? NULL_TREE : TREE_TYPE (fndecl))) + if (! OUTGOING_REG_PARM_STACK_SPACE ((!fndecl ? fntype : TREE_TYPE (fndecl))) && reg_parm_stack_space > 0 && PUSH_ARGS) must_preallocate = 1; /* Set up a place to return a structure. */ /* Cater to broken compilers. */ - if (aggregate_value_p (exp, fndecl)) + if (aggregate_value_p (exp, (!fndecl ? fntype : fndecl))) { /* This call returns a big structure. */ flags &= ~(ECF_CONST | ECF_PURE | ECF_LOOPING_CONST_OR_PURE); @@ -2097,7 +2106,7 @@ expand_call (tree exp, rtx target, int ignore) } #else /* not PCC_STATIC_STRUCT_RETURN */ { - struct_value_size = int_size_in_bytes (TREE_TYPE (exp)); + struct_value_size = int_size_in_bytes (rettype); if (target && MEM_P (target) && CALL_EXPR_RETURN_SLOT_OPT (exp)) structure_value_addr = XEXP (target, 0); @@ -2106,7 +2115,7 @@ expand_call (tree exp, rtx target, int ignore) /* For variable-sized objects, we must be called with a target specified. If we were to allocate space on the stack here, we would have no way of knowing when to free it. */ - rtx d = assign_temp (TREE_TYPE (exp), 0, 1, 1); + rtx d = assign_temp (rettype, 0, 1, 1); mark_temp_addr_taken (d); structure_value_addr = XEXP (d, 0); @@ -2243,7 +2252,7 @@ expand_call (tree exp, rtx target, int ignore) arguments into ARGS_SIZE, etc. */ initialize_argument_information (num_actuals, args, &args_size, n_named_args, exp, - structure_value_addr_value, fndecl, + structure_value_addr_value, fndecl, fntype, &args_so_far, reg_parm_stack_space, &old_stack_level, &old_pending_adj, &must_preallocate, &flags, @@ -2277,7 +2286,6 @@ expand_call (tree exp, rtx target, int ignore) if (currently_expanding_call++ != 0 || !flag_optimize_sibling_calls || args_size.var - || lookup_expr_eh_region (exp) >= 0 || dbg_cnt (tail_call) == false) try_tail_call = 0; @@ -2294,6 +2302,12 @@ expand_call (tree exp, rtx target, int ignore) It does not seem worth the effort since few optimizable sibling calls will return a structure. */ || structure_value_addr != NULL_RTX +#ifdef REG_PARM_STACK_SPACE + /* If outgoing reg parm stack space changes, we can not do sibcall. */ + || (OUTGOING_REG_PARM_STACK_SPACE (funtype) + != OUTGOING_REG_PARM_STACK_SPACE (TREE_TYPE (current_function_decl))) + || (reg_parm_stack_space != REG_PARM_STACK_SPACE (fndecl)) +#endif /* Check whether the target is able to optimize the call into a sibcall. */ || !targetm.function_ok_for_sibcall (fndecl, exp) @@ -2320,6 +2334,37 @@ expand_call (tree exp, rtx target, int ignore) || !lang_hooks.decls.ok_for_sibcall (fndecl)) try_tail_call = 0; + /* Check if caller and callee disagree in promotion of function + return value. */ + if (try_tail_call) + { + enum machine_mode caller_mode, caller_promoted_mode; + enum machine_mode callee_mode, callee_promoted_mode; + int caller_unsignedp, callee_unsignedp; + tree caller_res = DECL_RESULT (current_function_decl); + + caller_unsignedp = TYPE_UNSIGNED (TREE_TYPE (caller_res)); + caller_mode = DECL_MODE (caller_res); + callee_unsignedp = TYPE_UNSIGNED (TREE_TYPE (funtype)); + callee_mode = TYPE_MODE (TREE_TYPE (funtype)); + caller_promoted_mode + = promote_function_mode (TREE_TYPE (caller_res), caller_mode, + &caller_unsignedp, + TREE_TYPE (current_function_decl), 1); + callee_promoted_mode + = promote_function_mode (TREE_TYPE (funtype), callee_mode, + &callee_unsignedp, + funtype, 1); + if (caller_mode != VOIDmode + && (caller_promoted_mode != callee_promoted_mode + || ((caller_mode != caller_promoted_mode + || callee_mode != callee_promoted_mode) + && (caller_unsignedp != callee_unsignedp + || GET_MODE_BITSIZE (caller_mode) + < GET_MODE_BITSIZE (callee_mode))))) + try_tail_call = 0; + } + /* Ensure current function's preferred stack boundary is at least what we need. Stack alignment may also increase preferred stack boundary. */ @@ -2403,7 +2448,7 @@ expand_call (tree exp, rtx target, int ignore) unadjusted_args_size = compute_argument_block_size (reg_parm_stack_space, &adjusted_args_size, - fndecl, + fndecl, fntype, (pass == 0 ? 0 : preferred_stack_boundary)); @@ -2479,7 +2524,7 @@ expand_call (tree exp, rtx target, int ignore) /* Since we will be writing into the entire argument area, the map must be allocated for its entire size, not just the part that is the responsibility of the caller. */ - if (! OUTGOING_REG_PARM_STACK_SPACE ((!fndecl ? NULL_TREE : TREE_TYPE (fndecl)))) + if (! OUTGOING_REG_PARM_STACK_SPACE ((!fndecl ? fntype : TREE_TYPE (fndecl)))) needed += reg_parm_stack_space; #ifdef ARGS_GROW_DOWNWARD @@ -2578,7 +2623,7 @@ expand_call (tree exp, rtx target, int ignore) { rtx push_size = GEN_INT (adjusted_args_size.constant - + (OUTGOING_REG_PARM_STACK_SPACE ((!fndecl ? NULL + + (OUTGOING_REG_PARM_STACK_SPACE ((!fndecl ? fntype : TREE_TYPE (fndecl))) ? 0 : reg_parm_stack_space)); if (old_stack_level == 0) @@ -2647,14 +2692,14 @@ expand_call (tree exp, rtx target, int ignore) /* Figure out the register where the value, if any, will come back. */ valreg = 0; - if (TYPE_MODE (TREE_TYPE (exp)) != VOIDmode + if (TYPE_MODE (rettype) != VOIDmode && ! structure_value_addr) { if (pcc_struct_value) - valreg = hard_function_value (build_pointer_type (TREE_TYPE (exp)), + valreg = hard_function_value (build_pointer_type (rettype), fndecl, NULL, (pass == 0)); else - valreg = hard_function_value (TREE_TYPE (exp), fndecl, fntype, + valreg = hard_function_value (rettype, fndecl, fntype, (pass == 0)); /* If VALREG is a PARALLEL whose first member has a zero @@ -2695,26 +2740,28 @@ expand_call (tree exp, rtx target, int ignore) but we do preallocate space here if they want that. */ for (i = 0; i < num_actuals; i++) - if (args[i].reg == 0 || args[i].pass_on_stack) - { - rtx before_arg = get_last_insn (); - - if (store_one_arg (&args[i], argblock, flags, - adjusted_args_size.var != 0, - reg_parm_stack_space) - || (pass == 0 - && 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 (args[i].reg == 0 || args[i].pass_on_stack) + { + rtx before_arg = get_last_insn (); + + if (store_one_arg (&args[i], argblock, flags, + adjusted_args_size.var != 0, + reg_parm_stack_space) + || (pass == 0 + && check_sibcall_argument_overlap (before_arg, + &args[i], 1))) + sibcall_failure = 1; + } + + if (((flags & ECF_CONST) + || ((flags & ECF_PURE) && ACCUMULATE_OUTGOING_ARGS)) + && args[i].stack) + call_fusage = gen_rtx_EXPR_LIST (VOIDmode, + gen_rtx_USE (VOIDmode, + args[i].stack), + call_fusage); + } /* If we have a parm that is passed in registers but not in memory and whose alignment does not permit a direct copy into registers, @@ -2749,7 +2796,7 @@ expand_call (tree exp, rtx target, int ignore) /* If register arguments require space on the stack and stack space was not preallocated, allocate stack space here for arguments passed in registers. */ - if (OUTGOING_REG_PARM_STACK_SPACE ((!fndecl ? NULL_TREE : TREE_TYPE (fndecl))) + if (OUTGOING_REG_PARM_STACK_SPACE ((!fndecl ? fntype : TREE_TYPE (fndecl))) && !ACCUMULATE_OUTGOING_ARGS && must_preallocate == 0 && reg_parm_stack_space > 0) anti_adjust_stack (GEN_INT (reg_parm_stack_space)); @@ -2770,7 +2817,7 @@ expand_call (tree exp, rtx target, int ignore) } after_args = get_last_insn (); - funexp = prepare_call_address (funexp, static_chain_value, + funexp = prepare_call_address (fndecl, funexp, static_chain_value, &call_fusage, reg_parm_seen, pass == 0); load_register_parameters (args, num_actuals, &call_fusage, flags, @@ -2817,12 +2864,12 @@ expand_call (tree exp, rtx target, int ignore) 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))) + && TYPE_MODE (rettype) != BLKmode + && targetm.calls.return_in_msb (rettype)) { - if (shift_return_value (TYPE_MODE (TREE_TYPE (exp)), false, valreg)) + if (shift_return_value (TYPE_MODE (rettype), false, valreg)) sibcall_failure = 1; - valreg = gen_rtx_REG (TYPE_MODE (TREE_TYPE (exp)), REGNO (valreg)); + valreg = gen_rtx_REG (TYPE_MODE (rettype), REGNO (valreg)); } if (pass && (flags & ECF_MALLOC)) @@ -2831,7 +2878,7 @@ expand_call (tree exp, rtx target, int ignore) rtx last, insns; /* The return value from a malloc-like function is a pointer. */ - if (TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE) + if (TREE_CODE (rettype) == POINTER_TYPE) mark_reg_pointer (temp, BIGGEST_ALIGNMENT); emit_move_insn (temp, valreg); @@ -2881,7 +2928,7 @@ expand_call (tree exp, rtx target, int ignore) /* If value type not void, return an rtx for the value. */ - if (TYPE_MODE (TREE_TYPE (exp)) == VOIDmode + if (TYPE_MODE (rettype) == VOIDmode || ignore) target = const0_rtx; else if (structure_value_addr) @@ -2889,10 +2936,10 @@ expand_call (tree exp, rtx target, int ignore) if (target == 0 || !MEM_P (target)) { target - = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (exp)), - memory_address (TYPE_MODE (TREE_TYPE (exp)), + = gen_rtx_MEM (TYPE_MODE (rettype), + memory_address (TYPE_MODE (rettype), structure_value_addr)); - set_mem_attributes (target, exp, 1); + set_mem_attributes (target, rettype, 1); } } else if (pcc_struct_value) @@ -2900,9 +2947,9 @@ expand_call (tree exp, rtx target, int ignore) /* This is the special C++ case where we need to know what the true target was. We take care to never use this value more than once in one expression. */ - target = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (exp)), + target = gen_rtx_MEM (TYPE_MODE (rettype), copy_to_reg (valreg)); - set_mem_attributes (target, exp, 1); + set_mem_attributes (target, rettype, 1); } /* Handle calls that return values in multiple non-contiguous locations. The Irix 6 ABI has examples of this. */ @@ -2911,22 +2958,22 @@ expand_call (tree exp, rtx target, int ignore) if (target == 0) { /* This will only be assigned once, so it can be readonly. */ - tree nt = build_qualified_type (TREE_TYPE (exp), - (TYPE_QUALS (TREE_TYPE (exp)) + tree nt = build_qualified_type (rettype, + (TYPE_QUALS (rettype) | TYPE_QUAL_CONST)); target = assign_temp (nt, 0, 1, 1); } if (! rtx_equal_p (target, valreg)) - emit_group_store (target, valreg, TREE_TYPE (exp), - int_size_in_bytes (TREE_TYPE (exp))); + emit_group_store (target, valreg, rettype, + int_size_in_bytes (rettype)); /* We can not support sibling calls for this case. */ sibcall_failure = 1; } else if (target - && GET_MODE (target) == TYPE_MODE (TREE_TYPE (exp)) + && GET_MODE (target) == TYPE_MODE (rettype) && GET_MODE (target) == GET_MODE (valreg)) { bool may_overlap = false; @@ -2971,9 +3018,12 @@ expand_call (tree exp, rtx target, int ignore) sibcall_failure = 1; } } - else if (TYPE_MODE (TREE_TYPE (exp)) == BLKmode) + else if (TYPE_MODE (rettype) == BLKmode) { - target = copy_blkmode_from_reg (target, valreg, TREE_TYPE (exp)); + rtx val = valreg; + if (GET_MODE (val) != BLKmode) + val = avoid_likely_spilled_reg (val); + target = copy_blkmode_from_reg (target, val, rettype); /* We can not support sibling calls for this case. */ sibcall_failure = 1; @@ -2981,38 +3031,37 @@ expand_call (tree exp, rtx target, int ignore) else target = copy_to_reg (avoid_likely_spilled_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 (rettype) != BLKmode + && GET_MODE (target) != TYPE_MODE (rettype)) { - /* 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 = rettype; + int unsignedp = TYPE_UNSIGNED (type); + int offset = 0; + enum machine_mode pmode; + + /* Ensure we promote as expected, and get the new unsignedness. */ + pmode = promote_function_mode (type, TYPE_MODE (type), &unsignedp, + funtype, 1); + 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)))) { - 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); + 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 @@ -3229,6 +3278,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, /* Todo, choose the correct decl type of orgfun. Sadly this information isn't present here, so we default to native calling abi here. */ tree fndecl ATTRIBUTE_UNUSED = NULL_TREE; /* library calls default to host calling abi ? */ + tree fntype ATTRIBUTE_UNUSED = NULL_TREE; /* library calls default to host calling abi ? */ int inc; int count; rtx argblock = 0; @@ -3397,7 +3447,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, for (; count < nargs; count++) { rtx val = va_arg (p, rtx); - enum machine_mode mode = va_arg (p, enum machine_mode); + enum machine_mode mode = (enum machine_mode) va_arg (p, int); /* 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. */ @@ -3486,7 +3536,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, args_size.constant = MAX (args_size.constant, reg_parm_stack_space); - if (! OUTGOING_REG_PARM_STACK_SPACE ((!fndecl ? NULL_TREE : TREE_TYPE (fndecl)))) + if (! OUTGOING_REG_PARM_STACK_SPACE ((!fndecl ? fntype : TREE_TYPE (fndecl)))) args_size.constant -= reg_parm_stack_space; if (args_size.constant > crtl->outgoing_args_size) @@ -3511,7 +3561,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, /* Since we will be writing into the entire argument area, the map must be allocated for its entire size, not just the part that is the responsibility of the caller. */ - if (! OUTGOING_REG_PARM_STACK_SPACE ((!fndecl ? NULL_TREE : TREE_TYPE (fndecl)))) + if (! OUTGOING_REG_PARM_STACK_SPACE ((!fndecl ? fntype : TREE_TYPE (fndecl)))) needed += reg_parm_stack_space; #ifdef ARGS_GROW_DOWNWARD @@ -3587,6 +3637,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, rtx val = argvec[argnum].value; rtx reg = argvec[argnum].reg; int partial = argvec[argnum].partial; + unsigned int parm_align = argvec[argnum].locate.boundary; int lower_bound = 0, upper_bound = 0, i; if (! (reg != 0 && partial == 0)) @@ -3599,10 +3650,10 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, #ifdef ARGS_GROW_DOWNWARD /* stack_slot is negative, but we want to index stack_usage_map with positive values. */ - upper_bound = -argvec[argnum].locate.offset.constant + 1; + upper_bound = -argvec[argnum].locate.slot_offset.constant + 1; lower_bound = upper_bound - argvec[argnum].locate.size.constant; #else - lower_bound = argvec[argnum].locate.offset.constant; + lower_bound = argvec[argnum].locate.slot_offset.constant; upper_bound = lower_bound + argvec[argnum].locate.size.constant; #endif @@ -3648,7 +3699,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, } } - emit_push_insn (val, mode, NULL_TREE, NULL_RTX, PARM_BOUNDARY, + emit_push_insn (val, mode, NULL_TREE, NULL_RTX, parm_align, partial, reg, 0, argblock, GEN_INT (argvec[argnum].locate.offset.constant), reg_parm_stack_space, @@ -3661,7 +3712,8 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, NO_DEFER_POP; - if (flags & ECF_CONST) + if ((flags & ECF_CONST) + || ((flags & ECF_PURE) && ACCUMULATE_OUTGOING_ARGS)) { rtx use; @@ -3696,7 +3748,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, else argnum = 0; - fun = prepare_call_address (fun, NULL, &call_fusage, 0, 0); + fun = prepare_call_address (NULL, fun, NULL, &call_fusage, 0, 0); /* Now load any reg parms into their regs. */ @@ -3755,7 +3807,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, cse'ing of library calls could delete a call and leave the pop. */ NO_DEFER_POP; valreg = (mem_value == 0 && outmode != VOIDmode - ? hard_libcall_value (outmode) : NULL_RTX); + ? hard_libcall_value (outmode, orgfun) : NULL_RTX); /* Stack must be properly aligned now. */ gcc_assert (!(stack_pointer_delta @@ -3824,15 +3876,14 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, } else { - /* Convert to the proper mode if PROMOTE_MODE has been active. */ + /* Convert to the proper mode if a promotion has been active. */ if (GET_MODE (valreg) != outmode) { int unsignedp = TYPE_UNSIGNED (tfom); - gcc_assert (targetm.calls.promote_function_return (tfom)); - gcc_assert (promote_mode (tfom, outmode, &unsignedp, 0) + gcc_assert (promote_function_mode (tfom, outmode, &unsignedp, + fndecl ? TREE_TYPE (fndecl) : fntype, 1) == GET_MODE (valreg)); - valreg = convert_modes (outmode, GET_MODE (valreg), valreg, 0); } @@ -4184,7 +4235,8 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags, - int_size_in_bytes (TREE_TYPE (pval)) + partial); size_rtx = expand_expr (size_in_bytes (TREE_TYPE (pval)), - NULL_RTX, TYPE_MODE (sizetype), 0); + NULL_RTX, TYPE_MODE (sizetype), + EXPAND_NORMAL); } parm_align = arg->locate.boundary; @@ -4213,7 +4265,7 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags, || (GET_CODE (XEXP (x, 0)) == PLUS && XEXP (XEXP (x, 0), 0) == crtl->args.internal_arg_pointer - && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)) + && CONST_INT_P (XEXP (XEXP (x, 0), 1)))) { if (XEXP (x, 0) != crtl->args.internal_arg_pointer) i = INTVAL (XEXP (XEXP (x, 0), 1)); @@ -4221,7 +4273,7 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags, /* expand_call should ensure this. */ gcc_assert (!arg->locate.offset.var && arg->locate.size.var == 0 - && GET_CODE (size_rtx) == CONST_INT); + && CONST_INT_P (size_rtx)); if (arg->locate.offset.constant > i) {