#include "flags.h"
#include "except.h"
#include "function.h"
-#include "insn-flags.h"
#include "expr.h"
-#include "insn-codes.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "insn-config.h"
#include "ggc.h"
#include "tm_p.h"
-#ifndef ACCUMULATE_OUTGOING_ARGS
-#define ACCUMULATE_OUTGOING_ARGS 0
-#endif
-
#ifndef TRAMPOLINE_ALIGNMENT
#define TRAMPOLINE_ALIGNMENT FUNCTION_BOUNDARY
#endif
int current_function_uses_only_leaf_regs;
/* Nonzero once virtual register instantiation has been done.
- assign_stack_local uses frame_pointer_rtx when this is nonzero. */
-static int virtuals_instantiated;
+ assign_stack_local uses frame_pointer_rtx when this is nonzero.
+ calls.c:emit_library_call_value_1 uses it to set up
+ post-instantiation libcalls. */
+int virtuals_instantiated;
/* These variables hold pointers to functions to create and destroy
target specific, per-function data structures. */
static void instantiate_decls PARAMS ((tree, int));
static void instantiate_decls_1 PARAMS ((tree, int));
static void instantiate_decl PARAMS ((rtx, HOST_WIDE_INT, int));
+static rtx instantiate_new_reg PARAMS ((rtx, HOST_WIDE_INT *));
static int instantiate_virtual_regs_1 PARAMS ((rtx *, rtx, int));
static void delete_handlers PARAMS ((void));
static void pad_to_arg_alignment PARAMS ((struct args_size *, int,
static void emit_return_into_block PARAMS ((basic_block, rtx));
#endif
static void put_addressof_into_stack PARAMS ((rtx, struct hash_table *));
-static boolean purge_addressof_1 PARAMS ((rtx *, rtx, int, int,
+static bool purge_addressof_1 PARAMS ((rtx *, rtx, int, int,
struct hash_table *));
static void purge_single_hard_subreg_set PARAMS ((rtx));
#ifdef HAVE_epilogue
struct hash_table *,
hash_table_key));
static unsigned long insns_for_mem_hash PARAMS ((hash_table_key));
-static boolean insns_for_mem_comp PARAMS ((hash_table_key, hash_table_key));
+static bool insns_for_mem_comp PARAMS ((hash_table_key, hash_table_key));
static int insns_for_mem_walk PARAMS ((rtx *, void *));
static void compute_insns_for_mem PARAMS ((rtx, rtx, struct hash_table *));
static void mark_temp_slot PARAMS ((struct temp_slot *));
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 (decl);
+ 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
end_sequence ();
}
}
-
- /* Scan the catch clauses for exception handling too. */
- push_to_full_sequence (catch_clauses, catch_clauses_last);
- fixup_var_refs_insns (catch_clauses, var, promoted_mode, unsignedp, 0);
- end_full_sequence (&catch_clauses, &catch_clauses_last);
}
\f
/* REPLACEMENTS is a pointer to a list of the struct fixup_replacement and X is
rtx insn = XEXP (insn_list, 0);
if (INSN_P (insn))
- fixup_var_refs_insn (insn, var, promoted_mode, unsignedp, 0);
+ fixup_var_refs_insn (insn, var, promoted_mode, unsignedp, 1);
insn_list = XEXP (insn_list, 1);
}
{
replacement = find_fixup_replacement (replacements, var);
if (replacement->new == 0)
- replacement->new = gen_reg_rtx (GET_MODE (var));
+ replacement->new = gen_reg_rtx (promoted_mode);
SUBREG_REG (x) = replacement->new;
return;
}
optimize_bit_field (x, insn, 0);
if (GET_CODE (SET_SRC (x)) == SIGN_EXTRACT
|| GET_CODE (SET_SRC (x)) == ZERO_EXTRACT)
- optimize_bit_field (x, insn, NULL_PTR);
+ optimize_bit_field (x, insn, 0);
/* For a paradoxical SUBREG inside a ZERO_EXTRACT, load the object
into a register and then store it back out. */
dest = XEXP (dest, 0);
if (GET_CODE (src) == SUBREG)
- src = XEXP (src, 0);
+ src = SUBREG_REG (src);
/* If VAR does not appear at the top level of the SET
just scan the lower levels of the tree. */
rtx insn;
int uncritical;
{
- int offset = SUBREG_WORD (x) * UNITS_PER_WORD;
+ int offset = SUBREG_BYTE (x);
rtx addr = XEXP (SUBREG_REG (x), 0);
enum machine_mode mode = GET_MODE (x);
rtx result;
&& ! uncritical)
abort ();
- if (BYTES_BIG_ENDIAN)
- offset += (MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
- - MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode)));
addr = plus_constant (addr, offset);
if (!flag_force_addr && memory_address_p (mode, addr))
/* Shortcut if no insns need be emitted. */
offset /= BITS_PER_UNIT;
if (GET_CODE (XEXP (bitfield, 0)) == SUBREG)
{
- offset += SUBREG_WORD (XEXP (bitfield, 0)) * UNITS_PER_WORD;
+ offset += (SUBREG_BYTE (XEXP (bitfield, 0))
+ / UNITS_PER_WORD) * UNITS_PER_WORD;
if (BYTES_BIG_ENDIAN)
offset -= (MIN (UNITS_PER_WORD,
GET_MODE_SIZE (GET_MODE (XEXP (bitfield, 0))))
{
rtx src = SET_SRC (body);
while (GET_CODE (src) == SUBREG
- && SUBREG_WORD (src) == 0)
+ && SUBREG_BYTE (src) == 0)
src = SUBREG_REG (src);
if (GET_MODE (src) != GET_MODE (memref))
src = gen_lowpart (GET_MODE (memref), SET_SRC (body));
rtx dest = SET_DEST (body);
while (GET_CODE (dest) == SUBREG
- && SUBREG_WORD (dest) == 0
+ && SUBREG_BYTE (dest) == 0
&& (GET_MODE_CLASS (GET_MODE (dest))
== GET_MODE_CLASS (GET_MODE (SUBREG_REG (dest))))
&& (GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest)))
the stack. If the function returns FALSE then the replacement could not
be made. */
-static boolean
+static bool
purge_addressof_1 (loc, insn, force, store, ht)
rtx *loc;
rtx insn;
RTX_CODE code;
int i, j;
const char *fmt;
- boolean result = true;
+ bool result = true;
/* Re-start here to avoid recursion in common cases. */
restart:
result &= purge_addressof_1 (&SET_SRC (x), insn, force, 0, ht);
return result;
}
-
- else if (code == ADDRESSOF && GET_CODE (XEXP (x, 0)) == MEM)
+ else if (code == ADDRESSOF)
{
+ rtx sub, insns;
+
+ if (GET_CODE (XEXP (x, 0)) != MEM)
+ {
+ put_addressof_into_stack (x, ht);
+ return true;
+ }
+
/* We must create a copy of the rtx because it was created by
overwriting a REG rtx which is always shared. */
- rtx sub = copy_rtx (XEXP (XEXP (x, 0), 0));
- rtx insns;
-
+ sub = copy_rtx (XEXP (XEXP (x, 0), 0));
if (validate_change (insn, loc, sub, 0)
|| validate_replace_rtx (x, sub, insn))
return true;
code did. This is especially true of
REG_RETVAL. */
- if (GET_CODE (z) == SUBREG && SUBREG_WORD (z) == 0)
+ if (GET_CODE (z) == SUBREG && SUBREG_BYTE (z) == 0)
z = SUBREG_REG (z);
if (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD
}
goto restart;
}
- give_up:;
- /* else give up and put it into the stack */
- }
-
- else if (code == ADDRESSOF)
- {
- put_addressof_into_stack (x, ht);
- return true;
- }
- else if (code == SET)
- {
- result = purge_addressof_1 (&SET_DEST (x), insn, force, 1, ht);
- result &= purge_addressof_1 (&SET_SRC (x), insn, force, 0, ht);
- return result;
}
+ give_up:
/* Scan all subexpressions. */
fmt = GET_RTX_FORMAT (code);
for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
/* Return non-zero if K1 and K2 (two REGs) are the same. */
-static boolean
+static bool
insns_for_mem_comp (k1, k2)
hash_table_key k1;
hash_table_key k2;
{
rtx reg = SET_DEST (pattern);
enum machine_mode mode = GET_MODE (SET_DEST (pattern));
- int word = 0;
-
- while (GET_CODE (reg) == SUBREG)
+ int offset = 0;
+
+ if (GET_CODE (reg) == SUBREG && GET_CODE (SUBREG_REG (reg)) == REG
+ && REGNO (SUBREG_REG (reg)) < FIRST_PSEUDO_REGISTER)
{
- word += SUBREG_WORD (reg);
+ offset = subreg_regno_offset (REGNO (SUBREG_REG (reg)),
+ GET_MODE (SUBREG_REG (reg)),
+ SUBREG_BYTE (reg),
+ GET_MODE (reg));
reg = SUBREG_REG (reg);
}
-
- if (REGNO (reg) < FIRST_PSEUDO_REGISTER)
+
+
+ if (GET_CODE (reg) == REG && REGNO (reg) < FIRST_PSEUDO_REGISTER)
{
- reg = gen_rtx_REG (mode, REGNO (reg) + word);
+ reg = gen_rtx_REG (mode, REGNO (reg) + offset);
SET_DEST (pattern) = reg;
}
}
tree t;
for (t = BLOCK_VARS (let); t; t = TREE_CHAIN (t))
- instantiate_decl (DECL_RTL (t), int_size_in_bytes (TREE_TYPE (t)),
- valid_only);
+ if (DECL_RTL_SET_P (t))
+ instantiate_decl (DECL_RTL (t),
+ int_size_in_bytes (TREE_TYPE (t)),
+ valid_only);
/* Process all subblocks. */
for (t = BLOCK_SUBBLOCKS (let); t; t = TREE_CHAIN (t))
XEXP (x, 0) = addr;
}
\f
+/* Given a piece of RTX and a pointer to a HOST_WIDE_INT, if the RTX
+ is a virtual register, return the requivalent hard register and set the
+ offset indirectly through the pointer. Otherwise, return 0. */
+
+static rtx
+instantiate_new_reg (x, poffset)
+ rtx x;
+ HOST_WIDE_INT *poffset;
+{
+ rtx new;
+ HOST_WIDE_INT offset;
+
+ if (x == virtual_incoming_args_rtx)
+ new = arg_pointer_rtx, offset = in_arg_offset;
+ else if (x == virtual_stack_vars_rtx)
+ new = frame_pointer_rtx, offset = var_offset;
+ else if (x == virtual_stack_dynamic_rtx)
+ new = stack_pointer_rtx, offset = dynamic_offset;
+ else if (x == virtual_outgoing_args_rtx)
+ new = stack_pointer_rtx, offset = out_arg_offset;
+ else if (x == virtual_cfa_rtx)
+ new = arg_pointer_rtx, offset = cfa_offset;
+ else
+ return 0;
+
+ *poffset = offset;
+ return new;
+}
+\f
/* Given a pointer to a piece of rtx and an optional pointer to the
containing object, instantiate any virtual registers present in it.
the actual register should receive the source minus the
appropriate offset. This is used, for example, in the handling
of non-local gotos. */
- if (SET_DEST (x) == virtual_incoming_args_rtx)
- new = arg_pointer_rtx, offset = -in_arg_offset;
- else if (SET_DEST (x) == virtual_stack_vars_rtx)
- new = frame_pointer_rtx, offset = -var_offset;
- else if (SET_DEST (x) == virtual_stack_dynamic_rtx)
- new = stack_pointer_rtx, offset = -dynamic_offset;
- else if (SET_DEST (x) == virtual_outgoing_args_rtx)
- new = stack_pointer_rtx, offset = -out_arg_offset;
- else if (SET_DEST (x) == virtual_cfa_rtx)
- new = arg_pointer_rtx, offset = -cfa_offset;
-
- if (new)
+ if ((new = instantiate_new_reg (SET_DEST (x), &offset)) != 0)
{
rtx src = SET_SRC (x);
+ /* We are setting the register, not using it, so the relevant
+ offset is the negative of the offset to use were we using
+ the register. */
+ offset = - offset;
instantiate_virtual_regs_1 (&src, NULL_RTX, 0);
/* The only valid sources here are PLUS or REG. Just do
/* Check for (plus (plus VIRT foo) (const_int)) first. */
if (GET_CODE (XEXP (x, 0)) == PLUS)
{
- rtx inner = XEXP (XEXP (x, 0), 0);
-
- if (inner == virtual_incoming_args_rtx)
- new = arg_pointer_rtx, offset = in_arg_offset;
- else if (inner == virtual_stack_vars_rtx)
- new = frame_pointer_rtx, offset = var_offset;
- else if (inner == virtual_stack_dynamic_rtx)
- new = stack_pointer_rtx, offset = dynamic_offset;
- else if (inner == virtual_outgoing_args_rtx)
- new = stack_pointer_rtx, offset = out_arg_offset;
- else if (inner == virtual_cfa_rtx)
- new = arg_pointer_rtx, offset = cfa_offset;
+ if ((new = instantiate_new_reg (XEXP (XEXP (x, 0), 0), &offset)))
+ {
+ instantiate_virtual_regs_1 (&XEXP (XEXP (x, 0), 1), object,
+ extra_insns);
+ new = gen_rtx_PLUS (Pmode, new, XEXP (XEXP (x, 0), 1));
+ }
else
{
loc = &XEXP (x, 0);
goto restart;
}
-
- instantiate_virtual_regs_1 (&XEXP (XEXP (x, 0), 1), object,
- extra_insns);
- new = gen_rtx_PLUS (Pmode, new, XEXP (XEXP (x, 0), 1));
}
- else if (XEXP (x, 0) == virtual_incoming_args_rtx)
- new = arg_pointer_rtx, offset = in_arg_offset;
- else if (XEXP (x, 0) == virtual_stack_vars_rtx)
- new = frame_pointer_rtx, offset = var_offset;
- else if (XEXP (x, 0) == virtual_stack_dynamic_rtx)
- new = stack_pointer_rtx, offset = dynamic_offset;
- else if (XEXP (x, 0) == virtual_outgoing_args_rtx)
- new = stack_pointer_rtx, offset = out_arg_offset;
- else if (XEXP (x, 0) == virtual_cfa_rtx)
- new = arg_pointer_rtx, offset = cfa_offset;
- else
+#ifdef POINTERS_EXTEND_UNSIGNED
+ /* If we have (plus (subreg (virtual-reg)) (const_int)), we know
+ we can commute the PLUS and SUBREG because pointers into the
+ frame are well-behaved. */
+ else if (GET_CODE (XEXP (x, 0)) == SUBREG && GET_MODE (x) == ptr_mode
+ && GET_CODE (XEXP (x, 1)) == CONST_INT
+ && 0 != (new
+ = instantiate_new_reg (SUBREG_REG (XEXP (x, 0)),
+ &offset))
+ && validate_change (object, loc,
+ plus_constant (gen_lowpart (ptr_mode,
+ new),
+ offset
+ + INTVAL (XEXP (x, 1))),
+ 0))
+ return 1;
+#endif
+ else if ((new = instantiate_new_reg (XEXP (x, 0), &offset)) == 0)
{
/* We know the second operand is a constant. Unless the
first operand is a REG (which has been already checked),
case REG:
/* Try to replace with a PLUS. If that doesn't work, compute the sum
in front of this insn and substitute the temporary. */
- if (x == virtual_incoming_args_rtx)
- new = arg_pointer_rtx, offset = in_arg_offset;
- else if (x == virtual_stack_vars_rtx)
- new = frame_pointer_rtx, offset = var_offset;
- else if (x == virtual_stack_dynamic_rtx)
- new = stack_pointer_rtx, offset = dynamic_offset;
- else if (x == virtual_outgoing_args_rtx)
- new = stack_pointer_rtx, offset = out_arg_offset;
- else if (x == virtual_cfa_rtx)
- new = arg_pointer_rtx, offset = cfa_offset;
-
- if (new)
+ if ((new = instantiate_new_reg (x, &offset)) != 0)
{
temp = plus_constant (new, offset);
if (!validate_change (object, loc, temp, 0))
|| TREE_CODE (parm) != PARM_DECL
|| passed_type == NULL)
{
- DECL_INCOMING_RTL (parm) = DECL_RTL (parm)
- = gen_rtx_MEM (BLKmode, const0_rtx);
+ SET_DECL_RTL (parm, gen_rtx_MEM (BLKmode, const0_rtx));
+ DECL_INCOMING_RTL (parm) = DECL_RTL (parm);
TREE_USED (parm) = 1;
continue;
}
and avoid the usual things like emit_move_insn that could crash. */
if (nominal_mode == VOIDmode)
{
- DECL_INCOMING_RTL (parm) = DECL_RTL (parm) = const0_rtx;
+ SET_DECL_RTL (parm, const0_rtx);
+ DECL_INCOMING_RTL (parm) = DECL_RTL (parm);
continue;
}
&& GET_CODE (XEXP (XVECEXP (entry_parm, 0, i), 0)) == REG
&& (GET_MODE (XEXP (XVECEXP (entry_parm, 0, i), 0))
== passed_mode)
- && XINT (XEXP (XVECEXP (entry_parm, 0, i), 1), 0) == 0)
+ && INTVAL (XEXP (XVECEXP (entry_parm, 0, i), 1)) == 0)
{
entry_parm = XEXP (XVECEXP (entry_parm, 0, i), 0);
DECL_INCOMING_RTL (parm) = entry_parm;
size_stored / UNITS_PER_WORD,
int_size_in_bytes (TREE_TYPE (parm)));
}
- DECL_RTL (parm) = stack_parm;
+ SET_DECL_RTL (parm, stack_parm);
}
else if (! ((! optimize
&& ! DECL_REGISTER (parm)
appropriately. */
if (passed_pointer)
{
- DECL_RTL (parm)
- = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (passed_type)), parmreg);
+ SET_DECL_RTL (parm,
+ gen_rtx_MEM (TYPE_MODE (TREE_TYPE (passed_type)),
+ parmreg));
set_mem_attributes (DECL_RTL (parm), parm, 1);
}
else
- DECL_RTL (parm) = parmreg;
-
+ {
+ SET_DECL_RTL (parm, parmreg);
+ maybe_set_unchanging (DECL_RTL (parm), parm);
+ }
+
/* Copy the value into the register. */
if (nominal_mode != passed_mode
|| promoted_nominal_mode != promoted_mode)
push_to_sequence (conversion_insns);
tempreg = convert_to_mode (nominal_mode, tempreg, unsignedp);
+ if (GET_CODE (tempreg) == SUBREG
+ && GET_MODE (tempreg) == nominal_mode
+ && GET_CODE (SUBREG_REG (tempreg)) == REG
+ && nominal_mode == passed_mode
+ && GET_MODE (SUBREG_REG (tempreg)) == GET_MODE (entry_parm)
+ && GET_MODE_SIZE (GET_MODE (tempreg))
+ < GET_MODE_SIZE (GET_MODE (entry_parm)))
+ {
+ /* The argument is already sign/zero extended, so note it
+ into the subreg. */
+ SUBREG_PROMOTED_VAR_P (tempreg) = 1;
+ SUBREG_PROMOTED_UNSIGNED_P (tempreg) = unsignedp;
+ }
+
/* TREE_USED gets set erroneously during expand_assignment. */
save_tree_used = TREE_USED (parm);
expand_assignment (parm,
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));
push_to_sequence (conversion_insns);
emit_move_insn (tempreg, DECL_RTL (parm));
- DECL_RTL (parm)
- = convert_to_mode (GET_MODE (parmreg), tempreg,
- TREE_UNSIGNED (TREE_TYPE (parm)));
+ SET_DECL_RTL (parm,
+ convert_to_mode (GET_MODE (parmreg),
+ tempreg,
+ unsigned_p));
emit_move_insn (parmreg, DECL_RTL (parm));
conversion_insns = get_insns();
did_conversion = 1;
}
else
emit_move_insn (parmreg, DECL_RTL (parm));
- DECL_RTL (parm) = parmreg;
+ SET_DECL_RTL (parm, parmreg);
/* STACK_PARM is the pointer, not the parm, and PARMREG is
now the parm. */
stack_parm = 0;
conversion_insns = get_insns ();
end_sequence ();
}
- DECL_RTL (parm) = stack_parm;
+ SET_DECL_RTL (parm, stack_parm);
}
/* If this "parameter" was the place where we are receiving the
{
tree result = DECL_RESULT (fndecl);
- DECL_RTL (result)
- = gen_rtx_MEM (DECL_MODE (result), DECL_RTL (parm));
+ SET_DECL_RTL (result,
+ gen_rtx_MEM (DECL_MODE (result), DECL_RTL (parm)));
set_mem_attributes (DECL_RTL (result), result, 1);
}
to include tree.h. Do this here so it gets done when an inlined
function gets output. */
- current_function_return_rtx = DECL_RTL (DECL_RESULT (fndecl));
+ current_function_return_rtx
+ = (DECL_RTL_SET_P (DECL_RESULT (fndecl))
+ ? DECL_RTL (DECL_RESULT (fndecl)) : NULL_RTX);
}
\f
/* Indicate whether REGNO is an incoming argument to the current function
/* Make sure first insn is a note even if we don't want linenums.
This makes sure the first insn will never be deleted.
Also, final expects a note to appear there. */
- emit_note (NULL_PTR, NOTE_INSN_DELETED);
+ emit_note (NULL, NOTE_INSN_DELETED);
/* Set flags used by final.c. */
if (aggregate_value_p (DECL_RESULT (subr)))
else
cleanup_label = 0;
- /* Make the label for return statements to jump to, if this machine
- does not have a one-instruction return and uses an epilogue,
- or if it returns a structure, or if it has parm cleanups. */
-#ifdef HAVE_return
- if (cleanup_label == 0 && HAVE_return
- && ! current_function_instrument_entry_exit
- && ! current_function_returns_pcc_struct
- && ! (current_function_returns_struct && ! optimize))
- return_label = 0;
- else
- return_label = gen_label_rtx ();
-#else
+ /* Make the label for return statements to jump to. Do not special
+ case machines with special return instructions -- they will be
+ handled later during jump, ifcvt, or epilogue creation. */
return_label = gen_label_rtx ();
-#endif
/* Initialize rtx used to return the value. */
/* Do this before assign_parms so that we copy the struct value address
}
if (value_address)
{
- DECL_RTL (DECL_RESULT (subr))
- = gen_rtx_MEM (DECL_MODE (DECL_RESULT (subr)), value_address);
+ SET_DECL_RTL (DECL_RESULT (subr),
+ gen_rtx_MEM (DECL_MODE (DECL_RESULT (subr)),
+ value_address));
set_mem_attributes (DECL_RTL (DECL_RESULT (subr)),
DECL_RESULT (subr), 1);
}
}
else if (DECL_MODE (DECL_RESULT (subr)) == VOIDmode)
/* If return mode is void, this decl rtl should not be used. */
- DECL_RTL (DECL_RESULT (subr)) = 0;
- else if (parms_have_cleanups || current_function_instrument_entry_exit)
+ SET_DECL_RTL (DECL_RESULT (subr), NULL_RTX);
+ else if (parms_have_cleanups
+ || current_function_instrument_entry_exit
+ || (flag_exceptions && USING_SJLJ_EXCEPTIONS))
{
/* If function will end with cleanup code for parms,
compute the return values into a pseudo reg,
mode = promote_mode (type, mode, &unsignedp, 1);
#endif
- DECL_RTL (DECL_RESULT (subr)) = gen_reg_rtx (mode);
+ SET_DECL_RTL (DECL_RESULT (subr), gen_reg_rtx (mode));
+ /* Needed because we may need to move this to memory
+ in case it's a named return value whose address is taken. */
+ DECL_REGISTER (DECL_RESULT (subr)) = 1;
}
else
- /* Scalar, returned in a register. */
{
- DECL_RTL (DECL_RESULT (subr))
- = hard_function_value (TREE_TYPE (DECL_RESULT (subr)), subr, 1);
+ /* Scalar, returned in a register. */
+ SET_DECL_RTL (DECL_RESULT (subr),
+ hard_function_value (TREE_TYPE (DECL_RESULT (subr)),
+ subr, 1));
/* Mark this reg as the function's return value. */
if (GET_CODE (DECL_RTL (DECL_RESULT (subr))) == REG)
The move is supposed to make sdb output more accurate. */
/* Indicate the beginning of the function body,
as opposed to parm setup. */
- emit_note (NULL_PTR, NOTE_INSN_FUNCTION_BEG);
+ emit_note (NULL, NOTE_INSN_FUNCTION_BEG);
if (GET_CODE (get_last_insn ()) != NOTE)
- emit_note (NULL_PTR, NOTE_INSN_DELETED);
+ emit_note (NULL, NOTE_INSN_DELETED);
parm_birth_insn = get_last_insn ();
context_display = 0;
Pmode);
}
+#ifdef PROFILE_HOOK
+ if (profile_flag)
+ PROFILE_HOOK (profile_label_no);
+#endif
+
/* After the display initializations is where the tail-recursion label
should go, if we end up needing one. Ensure we have a NOTE here
since some things (like trampolines) get placed before this. */
- tail_recursion_reentry = emit_note (NULL_PTR, NOTE_INSN_DELETED);
+ tail_recursion_reentry = emit_note (NULL, NOTE_INSN_DELETED);
/* Evaluate now the sizes of any types declared among the arguments. */
for (tem = nreverse (get_pending_sizes ()); tem; tem = TREE_CHAIN (tem))
/* Mark the end of the function body.
If control reaches this insn, the function can drop through
without returning a value. */
- emit_note (NULL_PTR, NOTE_INSN_FUNCTION_END);
+ emit_note (NULL, NOTE_INSN_FUNCTION_END);
/* Must mark the last line number note in the function, so that the test
coverage code can avoid counting the last line twice. This just tells
already exists a copy of this note somewhere above. This line number
note is still needed for debugging though, so we can't delete it. */
if (flag_test_coverage)
- emit_note (NULL_PTR, NOTE_INSN_REPEATED_LINE_NUMBER);
+ emit_note (NULL, NOTE_INSN_REPEATED_LINE_NUMBER);
/* Output a linenumber for the end of the function.
SDB depends on this. */
emit_line_note_force (filename, line);
+ /* Before the return label (if any), clobber the return
+ registers so that they are not propogated live to the rest of
+ the function. This can only happen with functions that drop
+ through; if there had been a return statement, there would
+ have either been a return rtx, or a jump to the return label. */
+ {
+ rtx before, after;
+
+ before = get_last_insn ();
+ clobber_return_register ();
+ after = get_last_insn ();
+
+ if (before != after)
+ cfun->x_clobber_return_insn = after;
+ }
+
/* Output the label for the actual return from the function,
if one is expected. This happens either because a function epilogue
is used instead of a return instruction, or because a return was done
with a goto in order to run local cleanups, or because of pcc-style
structure returning. */
-
if (return_label)
- {
- rtx before, after;
-
- /* Before the return label, clobber the return registers so that
- they are not propogated live to the rest of the function. This
- can only happen with functions that drop through; if there had
- been a return statement, there would have either been a return
- rtx, or a jump to the return label. */
-
- before = get_last_insn ();
- clobber_return_register ();
- after = get_last_insn ();
-
- if (before != after)
- cfun->x_clobber_return_insn = after;
-
- emit_label (return_label);
- }
+ emit_label (return_label);
/* C++ uses this. */
if (end_bindings)
expand_end_bindings (0, 0, 0);
- /* Now handle any leftover exception regions that may have been
- created for the parameters. */
- {
- rtx last = get_last_insn ();
- rtx label;
-
- expand_leftover_cleanups ();
-
- /* If there are any catch_clauses remaining, output them now. */
- emit_insns (catch_clauses);
- catch_clauses = catch_clauses_last = NULL_RTX;
- /* If the above emitted any code, may sure we jump around it. */
- if (last != get_last_insn ())
- {
- label = gen_label_rtx ();
- last = emit_jump_insn_after (gen_jump (label), last);
- last = emit_barrier_after (last);
- emit_label (label);
- }
- }
-
if (current_function_instrument_entry_exit)
{
rtx fun = DECL_RTL (current_function_decl);
Pmode);
}
+ /* Let except.c know where it should emit the call to unregister
+ the function context for sjlj exceptions. */
+ if (flag_exceptions && USING_SJLJ_EXCEPTIONS)
+ sjlj_emit_function_exit_after (get_last_insn ());
+
/* If we had calls to alloca, and this machine needs
an accurate stack pointer to exit the function,
insert some code to save and restore the stack pointer. */
/* If scalar return value was computed in a pseudo-reg, or was a named
return value that got dumped to the stack, copy that to the hard
return register. */
- if (DECL_RTL (DECL_RESULT (current_function_decl)) != 0)
+ if (DECL_RTL_SET_P (DECL_RESULT (current_function_decl)))
{
tree decl_result = DECL_RESULT (current_function_decl);
rtx decl_rtl = DECL_RTL (decl_result);
convert_move (real_decl_rtl, decl_rtl, unsignedp);
}
+ else if (GET_CODE (real_decl_rtl) == PARALLEL)
+ emit_group_load (real_decl_rtl, decl_rtl,
+ int_size_in_bytes (TREE_TYPE (decl_result)),
+ TYPE_ALIGN (TREE_TYPE (decl_result)));
else
emit_move_insn (real_decl_rtl, decl_rtl);
current_function_return_rtx = outgoing;
}
+ /* If this is an implementation of throw, do what's necessary to
+ communicate between __builtin_eh_return and the epilogue. */
+ expand_eh_return ();
+
/* ??? This should no longer be necessary since stupid is no longer with
us, but there are some parts of the compiler (eg reload_combine, and
sh mach_dep_reorg) that still try and compute their own lifetime info
instead of using the general framework. */
use_return_register ();
- /* If this is an implementation of __throw, do what's necessary to
- communicate between __builtin_eh_return and the epilogue. */
- expand_eh_return ();
-
/* Output a return insn if we are using one.
Otherwise, let the rtl chain end here, to drop through
into the epilogue. */
there are line number notes before where we inserted the
prologue we should move them, and (2) we should generate a
note before the end of the first basic block, if there isn't
- one already there. */
+ one already there.
+
+ ??? This behaviour is completely broken when dealing with
+ multiple entry functions. We simply place the note always
+ into first basic block and let alternate entry points
+ to be missed.
+ */
for (insn = prologue_end; insn; insn = prev)
{
/* Find the last line number note in the first block. */
for (insn = BASIC_BLOCK (0)->end;
- insn != prologue_end;
+ insn != prologue_end && insn;
insn = PREV_INSN (insn))
if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
break;
BLOCK_HEAD (0) = next;
remove_insn (note);
+ /* Avoid placing note between CODE_LABEL and BASIC_BLOCK note. */
+ if (GET_CODE (insn) == CODE_LABEL)
+ insn = NEXT_INSN (insn);
add_insn_after (note, insn);
}
}