| Index: gcc/gcc/calls.c
|
| diff --git a/gcc/gcc/calls.c b/gcc/gcc/calls.c
|
| index 16d829b9cd7f7ccb469a379662224d7319cdfe92..0b4a89ecf94adb3cd10b5977ec7e0d7e3c5803df 100644
|
| --- a/gcc/gcc/calls.c
|
| +++ b/gcc/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, 2008, 2009
|
| + 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
|
| 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"
|
| @@ -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,
|
| @@ -251,10 +256,6 @@ emit_call_1 (rtx funexp, tree fntree, tree fndecl ATTRIBUTE_UNUSED,
|
| rtx call_insn;
|
| int already_popped = 0;
|
| HOST_WIDE_INT n_popped = RETURN_POPS_ARGS (fndecl, funtype, stack_size);
|
| -#if defined (HAVE_call) && defined (HAVE_call_value)
|
| - rtx struct_value_size_rtx;
|
| - struct_value_size_rtx = GEN_INT (struct_value_size);
|
| -#endif
|
|
|
| #ifdef CALL_POPS_ARGS
|
| n_popped += CALL_POPS_ARGS (* args_so_far);
|
| @@ -336,7 +337,7 @@ emit_call_1 (rtx funexp, tree fntree, tree fndecl ATTRIBUTE_UNUSED,
|
| else
|
| emit_call_insn (GEN_SIBCALL (gen_rtx_MEM (FUNCTION_MODE, funexp),
|
| rounded_stack_size_rtx, next_arg_reg,
|
| - struct_value_size_rtx));
|
| + GEN_INT (struct_value_size)));
|
| }
|
| else
|
| #endif
|
| @@ -352,7 +353,7 @@ emit_call_1 (rtx funexp, tree fntree, tree fndecl ATTRIBUTE_UNUSED,
|
| else
|
| emit_call_insn (GEN_CALL (gen_rtx_MEM (FUNCTION_MODE, funexp),
|
| rounded_stack_size_rtx, next_arg_reg,
|
| - struct_value_size_rtx));
|
| + GEN_INT (struct_value_size)));
|
| }
|
| else
|
| #endif
|
| @@ -376,19 +377,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 +391,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;
|
| @@ -590,12 +585,9 @@ int
|
| flags_from_decl_or_type (const_tree exp)
|
| {
|
| int flags = 0;
|
| - const_tree type = exp;
|
|
|
| if (DECL_P (exp))
|
| {
|
| - type = TREE_TYPE (exp);
|
| -
|
| /* The function exp may have the `malloc' attribute. */
|
| if (DECL_IS_MALLOC (exp))
|
| flags |= ECF_MALLOC;
|
| @@ -907,7 +899,7 @@ store_unaligned_arguments_into_pseudos (struct arg_data *args, int num_actuals)
|
| }
|
|
|
| /* Fill in ARGS_SIZE and ARGS array based on the parameters found in
|
| - CALL_EXPR EXP.
|
| + CALL_EXPR EXP.
|
|
|
| NUM_ACTUALS is the total number of parameters.
|
|
|
| @@ -949,6 +941,7 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
|
| 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;
|
|
|
| @@ -1017,11 +1010,12 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
|
| if (type == error_mark_node || !COMPLETE_TYPE_P (type))
|
| args[i].tree_value = integer_zero_node, type = integer_type_node;
|
|
|
| - /* If TYPE is a transparent union, pass things the way we would
|
| - pass the first field of the union. We have already verified that
|
| - the modes are the same. */
|
| - if (TREE_CODE (type) == UNION_TYPE && TYPE_TRANSPARENT_UNION (type))
|
| - type = TREE_TYPE (TYPE_FIELDS (type));
|
| + /* If TYPE is a transparent union or record, pass things the way
|
| + we would pass the first field of the union or record. We have
|
| + already verified that the modes are the same. */
|
| + if ((TREE_CODE (type) == UNION_TYPE || TREE_CODE (type) == RECORD_TYPE)
|
| + && TYPE_TRANSPARENT_AGGR (type))
|
| + type = TREE_TYPE (first_field (type));
|
|
|
| /* Decide where to pass this arg.
|
|
|
| @@ -1054,6 +1048,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
|
| @@ -1061,7 +1056,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)
|
| @@ -1113,19 +1109,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)
|
| - : fntype))
|
| - 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;
|
| @@ -1305,29 +1297,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);
|
| @@ -1335,7 +1331,6 @@ precompute_arguments (int num_actuals, struct arg_data *args)
|
| SUBREG_PROMOTED_UNSIGNED_SET (args[i].initial_value,
|
| args[i].unsignedp);
|
| }
|
| -#endif
|
| }
|
| }
|
| }
|
| @@ -1345,7 +1340,7 @@ precompute_arguments (int num_actuals, struct arg_data *args)
|
| compute and return the final value for MUST_PREALLOCATE. */
|
|
|
| static int
|
| -finalize_must_preallocate (int must_preallocate, int num_actuals,
|
| +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.
|
| @@ -1430,7 +1425,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);
|
| @@ -1457,14 +1452,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);
|
| @@ -1548,7 +1543,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
|
| @@ -1925,6 +1920,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;
|
| @@ -2020,7 +2016,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. */
|
| @@ -2043,15 +2038,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
|
| @@ -2061,7 +2057,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;
|
| @@ -2104,7 +2100,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);
|
| @@ -2113,7 +2109,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);
|
| @@ -2284,7 +2280,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;
|
|
|
| @@ -2343,17 +2338,17 @@ expand_call (tree exp, rtx target, int ignore)
|
| tree caller_res = DECL_RESULT (current_function_decl);
|
|
|
| caller_unsignedp = TYPE_UNSIGNED (TREE_TYPE (caller_res));
|
| - caller_mode = caller_promoted_mode = DECL_MODE (caller_res);
|
| + caller_mode = DECL_MODE (caller_res);
|
| callee_unsignedp = TYPE_UNSIGNED (TREE_TYPE (funtype));
|
| - callee_mode = callee_promoted_mode = TYPE_MODE (TREE_TYPE (funtype));
|
| - if (targetm.calls.promote_function_return (TREE_TYPE (current_function_decl)))
|
| - caller_promoted_mode
|
| - = promote_mode (TREE_TYPE (caller_res), caller_mode,
|
| - &caller_unsignedp, 1);
|
| - if (targetm.calls.promote_function_return (funtype))
|
| - callee_promoted_mode
|
| - = promote_mode (TREE_TYPE (funtype), callee_mode,
|
| - &callee_unsignedp, 1);
|
| + 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
|
| @@ -2691,14 +2686,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
|
| @@ -2816,7 +2811,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,
|
| @@ -2863,12 +2858,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))
|
| @@ -2877,7 +2872,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);
|
| @@ -2927,7 +2922,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)
|
| @@ -2935,10 +2930,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)
|
| @@ -2946,9 +2941,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. */
|
| @@ -2957,22 +2952,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;
|
| @@ -3017,12 +3012,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)
|
| {
|
| rtx val = valreg;
|
| if (GET_MODE (val) != BLKmode)
|
| val = avoid_likely_spilled_reg (val);
|
| - target = copy_blkmode_from_reg (target, val, TREE_TYPE (exp));
|
| + target = copy_blkmode_from_reg (target, val, rettype);
|
|
|
| /* We can not support sibling calls for this case. */
|
| sibcall_failure = 1;
|
| @@ -3030,38 +3025,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
|
| @@ -3447,7 +3441,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. */
|
| @@ -3637,6 +3631,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))
|
| @@ -3698,7 +3693,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,
|
| @@ -3747,7 +3742,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. */
|
|
|
| @@ -3806,7 +3801,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
|
| @@ -3875,15 +3870,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);
|
| }
|
|
|
| @@ -4235,7 +4229,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;
|
| @@ -4264,7 +4259,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));
|
| @@ -4272,7 +4267,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)
|
| {
|
|
|