outer_function_chain = p;
p->fixup_var_refs_queue = 0;
- (*lang_hooks.function.enter_nested) (p);
+ lang_hooks.function.enter_nested (p);
cfun = 0;
}
restore_emit_status (p);
- (*lang_hooks.function.leave_nested) (p);
+ lang_hooks.function.leave_nested (p);
/* Finish doing put_var_into_stack for any of our variables which became
addressable during the nested function. If only one entry has to be
/* f->varasm is used by code generation. */
/* f->eh->eh_return_stub_label is used by code generation. */
- (*lang_hooks.function.final) (f);
+ lang_hooks.function.final (f);
f->stmt = NULL;
}
/* Allow the target to (possibly) increase the alignment of this
stack slot. */
- type = (*lang_hooks.types.type_for_mode) (mode, 0);
+ type = lang_hooks.types.type_for_mode (mode, 0);
if (type)
alignment = LOCAL_ALIGNMENT (type, alignment);
align = GET_MODE_ALIGNMENT (mode);
if (! type)
- type = (*lang_hooks.types.type_for_mode) (mode, 0);
+ type = lang_hooks.types.type_for_mode (mode, 0);
if (type)
align = LOCAL_ALIGNMENT (type, align);
mode = TYPE_MODE (type);
#ifndef PROMOTE_FOR_CALL_ONLY
- unsignedp = TREE_UNSIGNED (type);
+ unsignedp = TYPE_UNSIGNED (type);
#endif
if (mode == BLKmode || memory_required)
void
put_var_into_stack (tree decl, int rescan)
{
- rtx reg;
+ rtx orig_reg, reg;
enum machine_mode promoted_mode, decl_mode;
struct function *function = 0;
tree context;
context = decl_function_context (decl);
/* Get the current rtl used for this object and its original mode. */
- reg = (TREE_CODE (decl) == SAVE_EXPR
- ? SAVE_EXPR_RTL (decl)
- : DECL_RTL_IF_SET (decl));
+ orig_reg = reg = (TREE_CODE (decl) == SAVE_EXPR
+ ? SAVE_EXPR_RTL (decl)
+ : DECL_RTL_IF_SET (decl));
/* No need to do anything if decl has no rtx yet
since in that case caller is setting TREE_ADDRESSABLE
&& GET_CODE (XEXP (reg, 0)) == REG
&& REGNO (XEXP (reg, 0)) > LAST_VIRTUAL_REGISTER)
{
- reg = XEXP (reg, 0);
+ orig_reg = reg = XEXP (reg, 0);
decl_mode = promoted_mode = GET_MODE (reg);
}
else
put_reg_into_stack (function, reg, TREE_TYPE (decl), promoted_mode,
decl_mode, volatilep, 0, usedp, 0);
+
+ /* If this was previously a MEM but we've removed the ADDRESSOF,
+ set this address into that MEM so we always use the same
+ rtx for this variable. */
+ if (orig_reg != reg && GET_CODE (orig_reg) == MEM)
+ XEXP (orig_reg, 0) = XEXP (reg, 0);
}
else if (GET_CODE (reg) == CONCAT)
{
to the whole CONCAT, lest we do double fixups for the latter
references. */
enum machine_mode part_mode = GET_MODE (XEXP (reg, 0));
- tree part_type = (*lang_hooks.types.type_for_mode) (part_mode, 0);
+ tree part_type = lang_hooks.types.type_for_mode (part_mode, 0);
rtx lopart = XEXP (reg, 0);
rtx hipart = XEXP (reg, 1);
#ifdef FRAME_GROWS_DOWNWARD
static void
put_reg_into_stack (struct function *function, rtx reg, tree type,
- enum machine_mode promoted_mode, enum machine_mode decl_mode,
- int volatile_p, unsigned int original_regno, int used_p, htab_t ht)
+ enum machine_mode promoted_mode,
+ enum machine_mode decl_mode, int volatile_p,
+ unsigned int original_regno, int used_p, htab_t ht)
{
struct function *func = function ? function : cfun;
rtx new = 0;
regno = REGNO (reg);
if (regno < func->x_max_parm_reg)
- new = func->x_parm_reg_stack_loc[regno];
+ {
+ if (!func->x_parm_reg_stack_loc)
+ abort ();
+ new = func->x_parm_reg_stack_loc[regno];
+ }
if (new == 0)
new = assign_stack_local_1 (decl_mode, GET_MODE_SIZE (decl_mode), 0, func);
schedule_fixup_var_refs (struct function *function, rtx reg, tree type,
enum machine_mode promoted_mode, htab_t ht)
{
- int unsigned_p = type ? TREE_UNSIGNED (type) : 0;
+ int unsigned_p = type ? TYPE_UNSIGNED (type) : 0;
if (function != 0)
{
if (rescan
&& (TREE_USED (decl) || (DECL_P (decl) && DECL_INITIAL (decl) != 0)))
- fixup_var_refs (reg, GET_MODE (reg), TREE_UNSIGNED (type), reg, 0);
+ fixup_var_refs (reg, GET_MODE (reg), TYPE_UNSIGNED (type), reg, 0);
}
else if (rescan)
{
/* Total space needed so far for args on the stack,
given as a constant and a tree-expression. */
struct args_size stack_args_size;
+ HOST_WIDE_INT extra_pretend_bytes = 0;
tree fntype = TREE_TYPE (fndecl);
tree fnargs = DECL_ARGUMENTS (fndecl), orig_fnargs;
/* This is used for the arg pointer when referring to stack args. */
max_parm_reg = LAST_VIRTUAL_REGISTER + 1;
parm_reg_stack_loc = ggc_alloc_cleared (max_parm_reg * sizeof (rtx));
- if (SPLIT_COMPLEX_ARGS)
+ /* If the target wants to split complex arguments into scalars, do so. */
+ if (targetm.calls.split_complex_arg)
fnargs = split_complex_args (fnargs);
#ifdef REG_PARM_STACK_SPACE
-#ifdef MAYBE_REG_PARM_STACK_SPACE
- reg_parm_stack_space = MAYBE_REG_PARM_STACK_SPACE;
-#else
reg_parm_stack_space = REG_PARM_STACK_SPACE (fndecl);
#endif
-#endif
#ifdef INIT_CUMULATIVE_INCOMING_ARGS
INIT_CUMULATIVE_INCOMING_ARGS (args_so_far, fntype, NULL_RTX);
if (targetm.calls.promote_function_args (TREE_TYPE (fndecl)))
{
/* Compute the mode in which the arg is actually extended to. */
- unsignedp = TREE_UNSIGNED (passed_type);
- promoted_mode = promote_mode (passed_type, promoted_mode, &unsignedp, 1);
+ unsignedp = TYPE_UNSIGNED (passed_type);
+ promoted_mode = promote_mode (passed_type, promoted_mode,
+ &unsignedp, 1);
}
/* Let machine desc say which reg (if any) the parm arrives in.
partial = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, promoted_mode,
passed_type, named_arg);
if (partial
-#ifndef MAYBE_REG_PARM_STACK_SPACE
/* The caller might already have allocated stack space
for the register parameters. */
- && reg_parm_stack_space == 0
-#endif
- )
+ && reg_parm_stack_space == 0)
{
/* Part of this argument is passed in registers and part
is passed on the stack. Ask the prologue code to extend
bits. We must preserve this invariant by rounding
CURRENT_FUNCTION_PRETEND_ARGS_SIZE up to a stack
boundary. */
+
+ /* We assume at most one partial arg, and it must be the first
+ argument on the stack. */
+ if (extra_pretend_bytes || current_function_pretend_args_size)
+ abort ();
+
pretend_bytes = partial * UNITS_PER_WORD;
current_function_pretend_args_size
= CEIL_ROUND (pretend_bytes, STACK_BYTES);
- /* If PRETEND_BYTES != CURRENT_FUNCTION_PRETEND_ARGS_SIZE,
- insert the padding before the start of the first pretend
- argument. */
- stack_args_size.constant
- = (current_function_pretend_args_size - pretend_bytes);
+ /* We want to align relative to the actual stack pointer, so
+ don't include this in the stack size until later. */
+ extra_pretend_bytes = current_function_pretend_args_size;
}
}
#endif
locate_and_pad_parm (promoted_mode, passed_type, in_regs,
entry_parm ? partial : 0, fndecl,
&stack_args_size, &locate);
+ /* Adjust offsets to include the pretend args. */
+ locate.slot_offset.constant += extra_pretend_bytes - pretend_bytes;
+ locate.offset.constant += extra_pretend_bytes - pretend_bytes;
{
rtx offset_rtx;
if (entry_parm == stack_parm
|| (GET_CODE (entry_parm) == PARALLEL
&& XEXP (XVECEXP (entry_parm, 0, 0), 0) == NULL_RTX)
-#if defined (REG_PARM_STACK_SPACE) && ! defined (MAYBE_REG_PARM_STACK_SPACE)
+#if defined (REG_PARM_STACK_SPACE)
/* On some machines, even if a parm value arrives in a register
- there is still an (uninitialized) stack slot allocated for it.
-
- ??? When MAYBE_REG_PARM_STACK_SPACE is defined, we can't tell
- whether this parameter already has a stack slot allocated,
- because an arg block exists only if current_function_args_size
- is larger than some threshold, and we haven't calculated that
- yet. So, for now, we just assume that stack slots never exist
- in this case. */
+ there is still an (uninitialized) stack slot allocated
+ for it. */
|| REG_PARM_STACK_SPACE (fndecl) > 0
#endif
)
{
- stack_args_size.constant += pretend_bytes + locate.size.constant;
+ stack_args_size.constant += locate.size.constant;
if (locate.size.var)
ADD_PARM_SIZE (stack_args_size, locate.size.var);
}
rtx parmreg;
unsigned int regno, regnoi = 0, regnor = 0;
- unsignedp = TREE_UNSIGNED (TREE_TYPE (parm));
+ unsignedp = TYPE_UNSIGNED (TREE_TYPE (parm));
promoted_nominal_mode
= promote_mode (TREE_TYPE (parm), nominal_mode, &unsignedp, 0);
if (GET_MODE (parmreg) != GET_MODE (DECL_RTL (parm)))
{
rtx tempreg = gen_reg_rtx (GET_MODE (DECL_RTL (parm)));
- int unsigned_p = TREE_UNSIGNED (TREE_TYPE (parm));
+ int unsigned_p = TYPE_UNSIGNED (TREE_TYPE (parm));
push_to_sequence (conversion_insns);
emit_move_insn (tempreg, DECL_RTL (parm));
SET_DECL_RTL (parm,
push_to_sequence (conversion_insns);
entry_parm = convert_to_mode (nominal_mode, tempreg,
- TREE_UNSIGNED (TREE_TYPE (parm)));
+ TYPE_UNSIGNED (TREE_TYPE (parm)));
if (stack_parm)
/* ??? This may need a big-endian conversion on sparc64. */
stack_parm = adjust_address (stack_parm, nominal_mode, 0);
}
}
- if (SPLIT_COMPLEX_ARGS && fnargs != orig_fnargs)
+ if (targetm.calls.split_complex_arg && fnargs != orig_fnargs)
{
for (parm = orig_fnargs; parm; parm = TREE_CHAIN (parm))
{
- if (TREE_CODE (TREE_TYPE (parm)) == COMPLEX_TYPE)
+ if (TREE_CODE (TREE_TYPE (parm)) == COMPLEX_TYPE
+ && targetm.calls.split_complex_arg (TREE_TYPE (parm)))
{
- rtx tmp;
-
- SET_DECL_RTL (parm,
- gen_rtx_CONCAT (DECL_MODE (parm),
- DECL_RTL (fnargs),
- DECL_RTL (TREE_CHAIN (fnargs))));
- tmp = gen_rtx_CONCAT (DECL_MODE (parm),
- DECL_INCOMING_RTL (fnargs),
- DECL_INCOMING_RTL (TREE_CHAIN (fnargs)));
+ rtx tmp, real, imag;
+ enum machine_mode inner = GET_MODE_INNER (DECL_MODE (parm));
+
+ real = DECL_RTL (fnargs);
+ imag = DECL_RTL (TREE_CHAIN (fnargs));
+ if (inner != GET_MODE (real))
+ {
+ real = gen_lowpart_SUBREG (inner, real);
+ imag = gen_lowpart_SUBREG (inner, imag);
+ }
+ tmp = gen_rtx_CONCAT (DECL_MODE (parm), real, imag);
+ SET_DECL_RTL (parm, tmp);
+
+ real = DECL_INCOMING_RTL (fnargs);
+ imag = DECL_INCOMING_RTL (TREE_CHAIN (fnargs));
+ if (inner != GET_MODE (real))
+ {
+ real = gen_lowpart_SUBREG (inner, real);
+ imag = gen_lowpart_SUBREG (inner, imag);
+ }
+ tmp = gen_rtx_CONCAT (DECL_MODE (parm), real, imag);
set_decl_incoming_rtl (parm, tmp);
fnargs = TREE_CHAIN (fnargs);
}
last_parm_insn = get_last_insn ();
+ /* We have aligned all the args, so add space for the pretend args. */
+ stack_args_size.constant += extra_pretend_bytes;
current_function_args_size = stack_args_size.constant;
/* Adjust function incoming argument size for alignment and
minimum length. */
#ifdef REG_PARM_STACK_SPACE
-#ifndef MAYBE_REG_PARM_STACK_SPACE
current_function_args_size = MAX (current_function_args_size,
REG_PARM_STACK_SPACE (fndecl));
#endif
-#endif
current_function_args_size
= ((current_function_args_size + STACK_BYTES - 1)
/* Before allocating memory, check for the common case of no complex. */
for (p = args; p; p = TREE_CHAIN (p))
- if (TREE_CODE (TREE_TYPE (p)) == COMPLEX_TYPE)
- goto found;
+ {
+ tree type = TREE_TYPE (p);
+ if (TREE_CODE (type) == COMPLEX_TYPE
+ && targetm.calls.split_complex_arg (type))
+ goto found;
+ }
return args;
found:
for (p = args; p; p = TREE_CHAIN (p))
{
tree type = TREE_TYPE (p);
- if (TREE_CODE (type) == COMPLEX_TYPE)
+ if (TREE_CODE (type) == COMPLEX_TYPE
+ && targetm.calls.split_complex_arg (type))
{
tree decl;
tree subtype = TREE_TYPE (type);
&& TYPE_MODE (DECL_ARG_TYPE (arg)) == TYPE_MODE (TREE_TYPE (arg)))
{
enum machine_mode mode = TYPE_MODE (TREE_TYPE (arg));
- int unsignedp = TREE_UNSIGNED (TREE_TYPE (arg));
+ int unsignedp = TYPE_UNSIGNED (TREE_TYPE (arg));
mode = promote_mode (TREE_TYPE (arg), mode, &unsignedp, 1);
if (mode == GET_MODE (DECL_INCOMING_RTL (arg))
int part_size_in_regs;
#ifdef REG_PARM_STACK_SPACE
-#ifdef MAYBE_REG_PARM_STACK_SPACE
- reg_parm_stack_space = MAYBE_REG_PARM_STACK_SPACE;
-#else
reg_parm_stack_space = REG_PARM_STACK_SPACE (fndecl);
-#endif
/* If we have found a stack parm before we reach the end of the
area reserved for registers, skip that area. */
flow.c that the entire aggregate was initialized.
Unions are troublesome because members may be shorter. */
&& ! AGGREGATE_TYPE_P (TREE_TYPE (decl))
- && DECL_RTL (decl) != 0
+ && DECL_RTL_SET_P (decl)
&& GET_CODE (DECL_RTL (decl)) == REG
/* Global optimizations can make it difficult to determine if a
particular variable has been initialized. However, a VAR_DECL
decl, decl);
if (extra_warnings
&& TREE_CODE (decl) == VAR_DECL
- && DECL_RTL (decl) != 0
+ && DECL_RTL_SET_P (decl)
&& GET_CODE (DECL_RTL (decl)) == REG
&& regno_clobbered_at_setjmp (REGNO (DECL_RTL (decl))))
warning ("%Jvariable '%D' might be clobbered by `longjmp' or `vfork'",
init_stmt_for_function ();
init_eh_for_function ();
- (*lang_hooks.function.init) (cfun);
+ lang_hooks.function.init (cfun);
if (init_machine_status)
cfun->machine = (*init_machine_status) ();
if (fndecl == NULL)
return;
- DECL_SAVED_INSNS (fndecl) = cfun;
+ DECL_STRUCT_FUNCTION (fndecl) = cfun;
cfun->decl = fndecl;
result = DECL_RESULT (fndecl);
static void
prepare_function_start (tree fndecl)
{
- if (fndecl && DECL_SAVED_INSNS (fndecl))
- cfun = DECL_SAVED_INSNS (fndecl);
+ if (fndecl && DECL_STRUCT_FUNCTION (fndecl))
+ cfun = DECL_STRUCT_FUNCTION (fndecl);
else
allocate_struct_function (fndecl);
init_emit ();
clear_pending_stack_adjust ();
do_pending_stack_adjust ();
+ /* @@@ This is a kludge. We want to ensure that instructions that
+ may trap are not moved into the epilogue by scheduling, because
+ we don't always emit unwind information for the epilogue.
+ However, not all machine descriptions define a blockage insn, so
+ emit an ASM_INPUT to act as one. */
+ if (flag_non_call_exceptions)
+ emit_insn (gen_rtx_ASM_INPUT (VOIDmode, ""));
+
/* Mark the end of the function body.
If control reaches this insn, the function can drop through
without returning a value. */
extension. */
if (GET_MODE (real_decl_rtl) != GET_MODE (decl_rtl))
{
- int unsignedp = TREE_UNSIGNED (TREE_TYPE (decl_result));
+ int unsignedp = TYPE_UNSIGNED (TREE_TYPE (decl_result));
if (targetm.calls.promote_function_return (TREE_TYPE (current_function_decl)))
promote_mode (TREE_TYPE (decl_result), GET_MODE (decl_rtl),
update_epilogue_consts (rtx dest, rtx x, void *data)
{
struct epi_info *p = (struct epi_info *) data;
+ rtx new;
if (GET_CODE (dest) != REG || REGNO (dest) >= FIRST_PSEUDO_REGISTER)
return;
- else if (GET_CODE (x) == CLOBBER || ! rtx_equal_p (dest, SET_DEST (x))
- || GET_CODE (SET_SRC (x)) != CONST_INT)
+
+ /* If we are either clobbering a register or doing a partial set,
+ show we don't know the value. */
+ else if (GET_CODE (x) == CLOBBER || ! rtx_equal_p (dest, SET_DEST (x)))
p->const_equiv[REGNO (dest)] = 0;
- else
+
+ /* If we are setting it to a constant, record that constant. */
+ else if (GET_CODE (SET_SRC (x)) == CONST_INT)
p->const_equiv[REGNO (dest)] = SET_SRC (x);
+
+ /* If this is a binary operation between a register we have been tracking
+ and a constant, see if we can compute a new constant value. */
+ else if (ARITHMETIC_P (SET_SRC (x))
+ && GET_CODE (XEXP (SET_SRC (x), 0)) == REG
+ && REGNO (XEXP (SET_SRC (x), 0)) < FIRST_PSEUDO_REGISTER
+ && p->const_equiv[REGNO (XEXP (SET_SRC (x), 0))] != 0
+ && GET_CODE (XEXP (SET_SRC (x), 1)) == CONST_INT
+ && 0 != (new = simplify_binary_operation
+ (GET_CODE (SET_SRC (x)), GET_MODE (dest),
+ p->const_equiv[REGNO (XEXP (SET_SRC (x), 0))],
+ XEXP (SET_SRC (x), 1)))
+ && GET_CODE (new) == CONST_INT)
+ p->const_equiv[REGNO (dest)] = new;
+
+ /* Otherwise, we can't do anything with this value. */
+ else
+ p->const_equiv[REGNO (dest)] = 0;
}
/* Emit an insn to do the load shown in p->equiv_reg_src, if needed. */
/* Similarly, move any line notes that appear after the epilogue.
There is no need, however, to be quite so anal about the existence
- of such a note. */
+ of such a note. Also move the NOTE_INSN_FUNCTION_END and (possibly)
+ NOTE_INSN_FUNCTION_BEG notes, as those can be relevant for debug
+ info generation. */
for (insn = epilogue_end; insn; insn = next)
{
next = NEXT_INSN (insn);
- if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
+ if (GET_CODE (insn) == NOTE
+ && (NOTE_LINE_NUMBER (insn) > 0
+ || NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG
+ || NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_END))
reorder_insns (insn, insn, PREV_INSN (epilogue_end));
}
}
const char *
current_function_name (void)
{
- return (*lang_hooks.decl_printable_name) (cfun->decl, 2);
+ return lang_hooks.decl_printable_name (cfun->decl, 2);
}
#include "gt-function.h"