/* 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, VEC(int,heap) **) ATTRIBUTE_UNUSED;
-static int contains (rtx, VEC(int,heap) **);
+static int contains (const_rtx, VEC(int,heap) **);
#ifdef HAVE_return
static void emit_return_into_block (basic_block);
#endif
#if defined(HAVE_epilogue) && defined(INCOMING_RETURN_ADDR_RTX)
static rtx keep_stack_depressed (rtx);
#endif
-static void prepare_function_start (tree);
+static void prepare_function_start (void);
static void do_clobber_return_reg (rtx, void *);
static void do_use_return_reg (rtx, void *);
static void set_insn_locators (rtx, int) ATTRIBUTE_UNUSED;
struct function *p;
if (cfun == 0)
- init_dummy_function_start ();
+ allocate_struct_function (NULL);
p = cfun;
p->outer = outer_function_chain;
lang_hooks.function.enter_nested (p);
- cfun = 0;
+ set_cfun (NULL);
}
void
{
struct function *p = outer_function_chain;
- cfun = p;
+ set_cfun (p);
outer_function_chain = p->outer;
current_function_decl = p->decl;
EXP may be a type node or an expression (whose type is tested). */
int
-aggregate_value_p (tree exp, tree fntype)
+aggregate_value_p (const_tree exp, const_tree fntype)
{
int i, regno, nregs;
rtx reg;
- tree type = (TYPE_P (exp)) ? exp : TREE_TYPE (exp);
+ const_tree type = (TYPE_P (exp)) ? exp : TREE_TYPE (exp);
/* DECL node associated with FNTYPE when relevant, which we might need to
check for by-invisible-reference returns, typically for CALL_EXPR input
EXPressions. */
- tree fndecl = NULL_TREE;
+ const_tree fndecl = NULL_TREE;
if (fntype)
switch (TREE_CODE (fntype))
return NULL_TREE;
}
\f
+/* Keep track of whether we're in a dummy function context. If we are,
+ we don't want to invoke the set_current_function hook, because we'll
+ get into trouble if the hook calls target_reinit () recursively or
+ when the initial initialization is not yet complete. */
+
+static bool in_dummy_function;
+
+/* Invoke the target hook when setting cfun. */
+
+static void
+invoke_set_current_function_hook (tree fndecl)
+{
+ if (!in_dummy_function)
+ targetm.set_current_function (fndecl);
+}
+
+/* cfun should never be set directly; use this function. */
+
+void
+set_cfun (struct function *new_cfun)
+{
+ if (cfun != new_cfun)
+ {
+ cfun = new_cfun;
+ invoke_set_current_function_hook (new_cfun ? new_cfun->decl : NULL_TREE);
+ }
+}
+
+/* Keep track of the cfun stack. */
+
+typedef struct function *function_p;
+
+DEF_VEC_P(function_p);
+DEF_VEC_ALLOC_P(function_p,heap);
+
+/* Initialized with NOGC, making this poisonous to the garbage collector. */
+
+static VEC(function_p,heap) *cfun_stack;
+
+/* Push the current cfun onto the stack, and set cfun to new_cfun. */
+
+void
+push_cfun (struct function *new_cfun)
+{
+ VEC_safe_push (function_p, heap, cfun_stack, cfun);
+ set_cfun (new_cfun);
+}
+
+/* Pop cfun from the stack. */
+
+void
+pop_cfun (void)
+{
+ set_cfun (VEC_pop (function_p, cfun_stack));
+}
/* Return value of funcdef and increase it. */
int
}
/* Allocate a function structure for FNDECL and set its contents
- to the defaults. */
+ to the defaults. Set cfun to the newly-allocated object.
+ Some of the helper functions invoked during initialization assume
+ that cfun has already been set. Therefore, assign the new object
+ directly into cfun and invoke the back end hook explicitly at the
+ very end, rather than initializing a temporary and calling set_cfun
+ on it.
+*/
void
allocate_struct_function (tree fndecl)
if (init_machine_status)
cfun->machine = (*init_machine_status) ();
- if (fndecl == NULL)
- return;
-
- DECL_STRUCT_FUNCTION (fndecl) = cfun;
- cfun->decl = fndecl;
-
- result = DECL_RESULT (fndecl);
- if (aggregate_value_p (result, fndecl))
+ if (fndecl != NULL)
{
+ DECL_STRUCT_FUNCTION (fndecl) = cfun;
+ cfun->decl = fndecl;
+
+ result = DECL_RESULT (fndecl);
+ if (aggregate_value_p (result, fndecl))
+ {
#ifdef PCC_STATIC_STRUCT_RETURN
- current_function_returns_pcc_struct = 1;
+ current_function_returns_pcc_struct = 1;
#endif
- current_function_returns_struct = 1;
+ current_function_returns_struct = 1;
+ }
+
+ current_function_stdarg
+ = (fntype
+ && TYPE_ARG_TYPES (fntype) != 0
+ && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
+ != void_type_node));
+
+ /* Assume all registers in stdarg functions need to be saved. */
+ cfun->va_list_gpr_size = VA_LIST_MAX_GPR_SIZE;
+ cfun->va_list_fpr_size = VA_LIST_MAX_FPR_SIZE;
}
- current_function_returns_pointer = POINTER_TYPE_P (TREE_TYPE (result));
+ invoke_set_current_function_hook (fndecl);
+}
- current_function_stdarg
- = (fntype
- && TYPE_ARG_TYPES (fntype) != 0
- && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
- != void_type_node));
+/* This is like allocate_struct_function, but pushes a new cfun for FNDECL
+ instead of just setting it. */
- /* Assume all registers in stdarg functions need to be saved. */
- cfun->va_list_gpr_size = VA_LIST_MAX_GPR_SIZE;
- cfun->va_list_fpr_size = VA_LIST_MAX_FPR_SIZE;
+void
+push_struct_function (tree fndecl)
+{
+ VEC_safe_push (function_p, heap, cfun_stack, cfun);
+ allocate_struct_function (fndecl);
}
/* Reset cfun, and other non-struct-function variables to defaults as
appropriate for emitting rtl at the start of a function. */
static void
-prepare_function_start (tree fndecl)
+prepare_function_start (void)
{
- if (fndecl && DECL_STRUCT_FUNCTION (fndecl))
- cfun = DECL_STRUCT_FUNCTION (fndecl);
- else
- allocate_struct_function (fndecl);
init_emit ();
init_varasm_status (cfun);
init_expr ();
/* Initialize the rtl expansion mechanism so that we can do simple things
like generate sequences. This is used to provide a context during global
- initialization of some passes. */
+ initialization of some passes. You must call expand_dummy_function_end
+ to exit this context. */
+
void
init_dummy_function_start (void)
{
- prepare_function_start (NULL);
+ gcc_assert (!in_dummy_function);
+ in_dummy_function = true;
+ push_struct_function (NULL_TREE);
+ prepare_function_start ();
}
/* Generate RTL for the start of the function SUBR (a FUNCTION_DECL tree node)
void
init_function_start (tree subr)
{
- prepare_function_start (subr);
+ if (subr && DECL_STRUCT_FUNCTION (subr))
+ set_cfun (DECL_STRUCT_FUNCTION (subr));
+ else
+ allocate_struct_function (subr);
+ prepare_function_start ();
/* Warn if this value is an aggregate type,
regardless of which calling convention we are using for it. */
void
expand_dummy_function_end (void)
{
+ gcc_assert (in_dummy_function);
+
/* End any sequences that failed to be closed due to syntax errors. */
while (in_sequence_p ())
end_sequence ();
free_after_parsing (cfun);
free_after_compilation (cfun);
- cfun = 0;
+ pop_cfun ();
+ in_dummy_function = false;
}
/* Call DOIT for each hard register used as a return value from
}
}
- /* Possibly warn about unused parameters.
- When frontend does unit-at-a-time, the warning is already
- issued at finalization time. */
- if (warn_unused_parameter
- && !lang_hooks.callgraph.expand_function)
- do_warn_unused_parameter (current_function_decl);
-
/* End any sequences that failed to be closed due to syntax errors. */
while (in_sequence_p ())
end_sequence ();
be running after reorg, SEQUENCE rtl is possible. */
static int
-contains (rtx insn, VEC(int,heap) **vec)
+contains (const_rtx insn, VEC(int,heap) **vec)
{
int i, j;
}
int
-prologue_epilogue_contains (rtx insn)
+prologue_epilogue_contains (const_rtx insn)
{
if (contains (insn, &prologue))
return 1;
}
int
-sibcall_epilogue_contains (rtx insn)
+sibcall_epilogue_contains (const_rtx insn)
{
if (sibcall_epilogue)
return contains (insn, &sibcall_epilogue);
};
static void handle_epilogue_set (rtx, struct epi_info *);
-static void update_epilogue_consts (rtx, rtx, void *);
+static void update_epilogue_consts (rtx, const_rtx, void *);
static void emit_equiv_load (struct epi_info *);
/* Modify INSN, a list of one or more insns that is part of the epilogue, to
/* Update the tracking information for registers set to constants. */
static void
-update_epilogue_consts (rtx dest, rtx x, void *data)
+update_epilogue_consts (rtx dest, const_rtx x, void *data)
{
struct epi_info *p = (struct epi_info *) data;
rtx new;
0, /* properties_destroyed */
TODO_verify_flow, /* todo_flags_start */
TODO_dump_func |
- TODO_df_finish |
+ TODO_df_verify |
+ TODO_df_finish | TODO_verify_rtl_sharing |
TODO_ggc_collect, /* todo_flags_finish */
'w' /* letter */
};