/* Expands front end tree to back end RTL for GCC.
Copyright (C) 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
- 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+ 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
This file is part of GCC.
static int all_blocks (tree, tree *);
static tree *get_block_vector (tree, int *);
extern tree debug_find_var_in_block_tree (tree, tree);
-/* We always define `record_insns' even if its not used so that we
+/* We always define `record_insns' even if it's not used so that we
can always export `prologue_epilogue_contains'. */
static void record_insns (rtx, varray_type *) ATTRIBUTE_UNUSED;
static int contains (rtx, varray_type);
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)
{
rtx first_insn = get_insns ();
struct sequence_stack *stack = seq_stack;
tree rtl_exps = rtl_expr_chain;
+ int save_volatile_ok = volatile_ok;
/* If there's a hash table, it must record all uses of VAR. */
if (ht)
return;
}
+ /* Volatile is valid in MEMs because all we're doing in changing the
+ address inside. */
+ volatile_ok = 1;
fixup_var_refs_insns (first_insn, var, promoted_mode, unsignedp,
stack == 0, may_share);
end_sequence ();
}
}
+
+ volatile_ok = save_volatile_ok;
}
\f
/* REPLACEMENTS is a pointer to a list of the struct fixup_replacement and X is
RTX_UNCHANGING_P (XEXP (r, 0)) = RTX_UNCHANGING_P (reg);
PUT_CODE (reg, MEM);
+ MEM_VOLATILE_P (reg) = 0;
MEM_ATTRS (reg) = 0;
XEXP (reg, 0) = r;
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)
{
/* This can only happen during reload. Clear the same flag bits as
reload. */
- MEM_VOLATILE_P (reg) = 0;
RTX_UNCHANGING_P (reg) = 0;
MEM_IN_STRUCT_P (reg) = 0;
MEM_SCALAR_P (reg) = 0;
- MEM_ATTRS (reg) = 0;
fixup_var_refs (reg, GET_MODE (reg), 0, reg, 0);
}
return true;
}
purge_addressof_replacements
- = gen_rtx (EXPR_LIST, VOIDmode, XEXP (x, 0),
- gen_rtx_EXPR_LIST (VOIDmode, sub,
- purge_addressof_replacements));
+ = gen_rtx_EXPR_LIST (VOIDmode, XEXP (x, 0),
+ gen_rtx_EXPR_LIST (VOIDmode, sub,
+ purge_addressof_replacements));
return true;
}
goto restart;
return 0;
regno = REGNO (reg);
- nregs = HARD_REGNO_NREGS (regno, TYPE_MODE (type));
+ nregs = hard_regno_nregs[regno][TYPE_MODE (type)];
for (i = 0; i < nregs; i++)
if (! call_used_regs[regno + i])
return 1;
/* 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);
#else
- INIT_CUMULATIVE_ARGS (args_so_far, fntype, NULL_RTX, fndecl);
+ INIT_CUMULATIVE_ARGS (args_so_far, fntype, NULL_RTX, fndecl, -1);
#endif
/* We haven't yet found an argument that we must push and pretend the
int in_regs;
int partial = 0;
int pretend_bytes = 0;
+ int loaded_in_reg = 0;
/* Set LAST_NAMED if this is last named arg before last
anonymous args. */
/* Set NAMED_ARG if this arg should be treated as a named arg. For
most machines, if this is a varargs/stdarg function, then we treat
the last named arg as if it were anonymous too. */
- named_arg = targetm.calls.strict_argument_naming (&args_so_far) ? 1 : ! last_named;
+ named_arg = (targetm.calls.strict_argument_naming (&args_so_far)
+ ? 1 : !last_named);
if (TREE_TYPE (parm) == error_mark_node
/* This can happen after weird syntax errors
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;
entry_parm = stack_parm;
/* Record permanently how this parm was passed. */
- DECL_INCOMING_RTL (parm) = entry_parm;
+ set_decl_incoming_rtl (parm, entry_parm);
/* If there is actually space on the stack for this parm,
count it in stack_args_size; otherwise set stack_parm to 0
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);
}
&& INTVAL (XEXP (XVECEXP (entry_parm, 0, i), 1)) == 0)
{
entry_parm = XEXP (XVECEXP (entry_parm, 0, i), 0);
- DECL_INCOMING_RTL (parm) = entry_parm;
+ set_decl_incoming_rtl (parm, entry_parm);
break;
}
}
emit_group_store (parmreg, entry_parm, TREE_TYPE (parm),
int_size_in_bytes (TREE_TYPE (parm)));
SET_DECL_RTL (parm, parmreg);
+ loaded_in_reg = 1;
if (regno >= max_parm_reg)
{
Handle calls that pass values in multiple non-contiguous
locations. The Irix 6 ABI has examples of this. */
if (GET_CODE (entry_parm) == REG
- || GET_CODE (entry_parm) == PARALLEL)
+ || (GET_CODE (entry_parm) == PARALLEL
+ && (!loaded_in_reg || !optimize)))
{
int size = int_size_in_bytes (TREE_TYPE (parm));
int size_stored = CEIL_ROUND (size, UNITS_PER_WORD);
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)))
{
- SET_DECL_RTL (parm,
- gen_rtx_CONCAT (DECL_MODE (parm),
- DECL_RTL (fnargs),
- DECL_RTL (TREE_CHAIN (fnargs))));
- DECL_INCOMING_RTL (parm)
- = 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);
}
else
{
SET_DECL_RTL (parm, DECL_RTL (fnargs));
- DECL_INCOMING_RTL (parm) = DECL_INCOMING_RTL (fnargs);
+ set_decl_incoming_rtl (parm, DECL_INCOMING_RTL (fnargs));
}
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 ();
- init_emit ();
- init_expr ();
- init_varasm_status (cfun);
- (*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 ();
+ init_varasm_status (cfun);
+ init_expr ();
cse_not_expected = ! optimize;
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),
}
}
-/* Set the specified locator to the insn chain. */
+/* Set the locator of the insn chain starting at INSN to LOC. */
static void
set_insn_locators (rtx insn, int loc)
{
&& !REGNO_REG_SET_P (EXIT_BLOCK_PTR->global_live_at_start,
regno)
&& !refers_to_regno_p (regno,
- regno + HARD_REGNO_NREGS (regno,
- Pmode),
+ regno + hard_regno_nregs[regno]
+ [Pmode],
info.equiv_reg_src, NULL)
&& info.const_equiv[regno] == 0)
break;
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. */
#endif
#ifdef HAVE_prologue
+ /* This is probably all useless now that we use locators. */
if (prologue_end)
{
rtx insn, prev;
/* 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));
}
}
VARRAY_INT_INIT (sibcall_epilogue, 0, "sibcall_epilogue");
}
+/* Returns the name of the current function. */
+const char *
+current_function_name (void)
+{
+ return lang_hooks.decl_printable_name (cfun->decl, 2);
+}
+
#include "gt-function.h"