/* 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.
&& ! 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;
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;
&& 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);
|| (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
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)
*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;
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);
SUBREG_PROMOTED_UNSIGNED_SET (args[i].initial_value,
args[i].unsignedp);
}
-#endif
}
}
}
&& 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);
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);
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
|| !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 (caller_res), callee_mode,
+ &callee_unsignedp,
+ TREE_TYPE (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. */
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,
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 (TREE_TYPE (exp)) != BLKmode
+ && GET_MODE (target) != TYPE_MODE (TREE_TYPE (exp)))
{
- /* 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;
+
+ /* 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
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. */
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))
#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
}
}
- 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,
NO_DEFER_POP;
- if (flags & ECF_CONST)
+ if ((flags & ECF_CONST)
+ || ((flags & ECF_PURE) && ACCUMULATE_OUTGOING_ARGS))
{
rtx use;
}
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);
}
- 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;
|| (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));
/* 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)
{