#include "hash.h"
#include "ggc.h"
#include "tm_p.h"
+#include "integrate.h"
#ifndef TRAMPOLINE_ALIGNMENT
#define TRAMPOLINE_ALIGNMENT FUNCTION_BOUNDARY
if (decl)
{
tree type = TREE_TYPE (decl);
+ enum machine_mode decl_mode
+ = (TREE_CODE (decl) == SAVE_EXPR ? TYPE_MODE (TREE_TYPE (decl))
+ : DECL_MODE (decl));
- PUT_MODE (reg, DECL_MODE (decl));
+ PUT_MODE (reg, decl_mode);
MEM_VOLATILE_P (reg) = TREE_SIDE_EFFECTS (decl);
MEM_SET_IN_STRUCT_P (reg, AGGREGATE_TYPE_P (type));
MEM_ALIAS_SET (reg) = get_alias_set (decl);
\f
extern struct obstack permanent_obstack;
+/* The PENDING_SIZES represent the sizes of variable-sized types.
+ Create RTL for the various sizes now (using temporary variables),
+ so that we can refer to the sizes from the RTL we are generating
+ for the current function. The PENDING_SIZES are a TREE_LIST. The
+ TREE_VALUE of each node is a SAVE_EXPR. */
+
+void
+expand_pending_sizes (pending_sizes)
+ tree pending_sizes;
+{
+ tree tem;
+
+ /* Evaluate now the sizes of any types declared among the arguments. */
+ for (tem = pending_sizes; tem; tem = TREE_CHAIN (tem))
+ {
+ expand_expr (TREE_VALUE (tem), const0_rtx, VOIDmode,
+ EXPAND_MEMORY_USE_BAD);
+ /* Flush the queue in case this parameter declaration has
+ side-effects. */
+ emit_queue ();
+ }
+}
+
/* Start the RTL for a new function, and set variables used for
emitting RTL.
SUBR is the FUNCTION_DECL node.
else if (DECL_MODE (DECL_RESULT (subr)) == VOIDmode)
/* If return mode is void, this decl rtl should not be used. */
SET_DECL_RTL (DECL_RESULT (subr), NULL_RTX);
- else if (parms_have_cleanups
- || current_function_instrument_entry_exit
- || (flag_exceptions && USING_SJLJ_EXCEPTIONS))
+ else
{
- /* If function will end with cleanup code for parms, compute the
- return values into a pseudo reg, which we will copy into the
- true return register after the cleanups are done. */
+ /* Compute the return values into a pseudo reg, which we will copy
+ into the true return register after the cleanups are done. */
/* In order to figure out what mode to use for the pseudo, we
figure out what the mode of the eventual return register will
= hard_function_value (TREE_TYPE (DECL_RESULT (subr)),
subr, 1);
- /* Since we know the return value is not an aggregate, we should
- have a REG here. */
- if (!REG_P (hard_reg))
- abort ();
-
- /* Create the pseudo. */
- SET_DECL_RTL (DECL_RESULT (subr),
- gen_reg_rtx (GET_MODE (hard_reg)));
- /* 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. */
- 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)
+ /* Structures that are returned in registers are not aggregate_value_p,
+ so we may see a PARALLEL. Don't play pseudo games with this. */
+ if (! REG_P (hard_reg))
+ SET_DECL_RTL (DECL_RESULT (subr), hard_reg);
+ else
{
- REG_FUNCTION_VALUE_P (DECL_RTL (DECL_RESULT (subr))) = 1;
+ /* Create the pseudo. */
+ SET_DECL_RTL (DECL_RESULT (subr), gen_reg_rtx (GET_MODE (hard_reg)));
+
/* 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;
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))
- {
- expand_expr (TREE_VALUE (tem), const0_rtx, VOIDmode,
- EXPAND_MEMORY_USE_BAD);
- /* Flush the queue in case this parameter declaration has
- side-effects. */
- emit_queue ();
- }
+ expand_pending_sizes (nreverse (get_pending_sizes ()));
/* Make sure there is a line number after the function entry setup code. */
force_next_line_note ();
void *arg;
{
rtx outgoing = current_function_return_rtx;
- int pcc;
if (! outgoing)
return;
- pcc = (current_function_returns_struct
- || current_function_returns_pcc_struct);
-
- if ((GET_CODE (outgoing) == REG
- && REGNO (outgoing) >= FIRST_PSEUDO_REGISTER)
- || pcc)
- {
- tree type = TREE_TYPE (DECL_RESULT (current_function_decl));
-
- /* A PCC-style return returns a pointer to the memory in which
- the structure is stored. */
- if (pcc)
- type = build_pointer_type (type);
-
-#ifdef FUNCTION_OUTGOING_VALUE
- outgoing = FUNCTION_OUTGOING_VALUE (type, current_function_decl);
-#else
- outgoing = FUNCTION_VALUE (type, current_function_decl);
-#endif
- /* If this is a BLKmode structure being returned in registers, then use
- the mode computed in expand_return. */
- if (GET_MODE (outgoing) == BLKmode)
- PUT_MODE (outgoing, GET_MODE (current_function_return_rtx));
- REG_FUNCTION_VALUE_P (outgoing) = 1;
- }
-
if (GET_CODE (outgoing) == REG)
(*doit) (outgoing, arg);
else if (GET_CODE (outgoing) == PARALLEL)
clobber_return_register ()
{
diddle_return_value (do_clobber_return_reg, NULL);
+
+ /* In case we do use pseudo to return value, clobber it too. */
+ 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);
+ if (REG_P (decl_rtl) && REGNO (decl_rtl) >= FIRST_PSEUDO_REGISTER)
+ {
+ do_clobber_return_reg (decl_rtl, NULL);
+ }
+ }
}
static void
int end_bindings;
{
tree link;
+ rtx clobber_after;
#ifdef TRAMPOLINE_TEMPLATE
static rtx initial_trampoline;
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;
- }
+ have either been a return rtx, or a jump to the return label.
+
+ We delay actual code generation after the current_function_value_rtx
+ is computed. */
+ clobber_after = get_last_insn ();
/* Output the label for the actual return from the function,
if one is expected. This happens either because a function epilogue
communicate between __builtin_eh_return and the epilogue. */
expand_eh_return ();
+ /* Emit the actual code to clobber return register. */
+ {
+ rtx seq, after;
+
+ start_sequence ();
+ clobber_return_register ();
+ seq = gen_sequence ();
+ end_sequence ();
+
+ after = emit_insn_after (seq, clobber_after);
+
+ if (clobber_after != after)
+ cfun->x_clobber_return_insn = after;
+ }
+
/* ??? 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
ggc_mark_rtx (p->x_nonlocal_goto_handler_labels);
ggc_mark_rtx (p->x_nonlocal_goto_stack_level);
ggc_mark_tree (p->x_nonlocal_labels);
+
+ mark_hard_reg_initial_vals (p);
}
/* Mark the function chain ARG (which is really a struct function **)