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) |
{ |