/* 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.
#include "sbitmap.h"
#include "langhooks.h"
#include "target.h"
+#include "debug.h"
#include "cgraph.h"
#include "except.h"
#include "dbgcnt.h"
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,
if (GET_CODE (funexp) != SYMBOL_REF)
/* If we are using registers for parameters, force the
function address into a register now. */
- funexp = ((SMALL_REGISTER_CLASSES && reg_parm_seen)
+ funexp = ((reg_parm_seen
+ && targetm.small_register_classes_for_mode_p (FUNCTION_MODE))
? force_not_mem (memory_address (FUNCTION_MODE, funexp))
: memory_address (FUNCTION_MODE, funexp));
else if (! sibcallp)
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;
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);
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
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
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;
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;
&& args[i].mode != BLKmode
&& rtx_cost (args[i].value, SET, optimize_insn_for_speed_p ())
> COSTS_N_INSNS (1)
- && ((SMALL_REGISTER_CLASSES && *reg_parm_seen)
+ && ((*reg_parm_seen
+ && targetm.small_register_classes_for_mode_p (args[i].mode))
|| optimize))
args[i].value = copy_to_mode_reg (args[i].mode, args[i].value);
}
}
/* 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.
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.
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.
/* Set up a place to return a structure. */
/* Cater to broken compilers. */
- if (aggregate_value_p (exp, (!fndecl ? fntype : fndecl)))
+ if (aggregate_value_p (exp, fntype))
{
/* This call returns a big structure. */
flags &= ~(ECF_CONST | ECF_PURE | ECF_LOOPING_CONST_OR_PURE);
}
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,
}
else if (TYPE_MODE (rettype) == BLKmode)
{
- target = copy_blkmode_from_reg (target, valreg, rettype);
+ 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;
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. */