static FILE *cgraph_dump_file;
+static GTY (()) tree static_ctors;
+static GTY (()) tree static_dtors;
+
+/* When target does not have ctors and dtors, we call all constructor
+ and destructor by special initialization/destruction function
+ recognized by collect2.
+
+ When we are going to build this function, collect all constructors and
+ destructors and turn them into normal functions. */
+
+static void
+record_cdtor_fn (tree fndecl)
+{
+ if (targetm.have_ctors_dtors)
+ return;
+
+ if (DECL_STATIC_CONSTRUCTOR (fndecl))
+ {
+ static_ctors = tree_cons (NULL_TREE, fndecl, static_ctors);
+ DECL_STATIC_CONSTRUCTOR (fndecl) = 0;
+ cgraph_mark_reachable_node (cgraph_node (fndecl));
+ }
+ if (DECL_STATIC_DESTRUCTOR (fndecl))
+ {
+ static_dtors = tree_cons (NULL_TREE, fndecl, static_dtors);
+ DECL_STATIC_DESTRUCTOR (fndecl) = 0;
+ cgraph_mark_reachable_node (cgraph_node (fndecl));
+ }
+}
+
+/* Synthesize a function which calls all the global ctors or global
+ dtors in this file. This is only used for targets which do not
+ support .ctors/.dtors sections. */
+static void
+build_cdtor (int method_type, tree cdtors)
+{
+ tree body = 0;
+
+ if (!cdtors)
+ return;
+
+ for (; cdtors; cdtors = TREE_CHAIN (cdtors))
+ append_to_statement_list (build_function_call_expr (TREE_VALUE (cdtors), 0),
+ &body);
+
+ cgraph_build_static_cdtor (method_type, body, DEFAULT_INIT_PRIORITY);
+}
+
+/* Generate functions to call static constructors and destructors
+ for targets that do not support .ctors/.dtors sections. These
+ functions have magic names which are detected by collect2. */
+
+static void
+cgraph_build_cdtor_fns (void)
+{
+ if (!targetm.have_ctors_dtors)
+ {
+ build_cdtor ('I', static_ctors);
+ static_ctors = NULL_TREE;
+ build_cdtor ('D', static_dtors);
+ static_dtors = NULL_TREE;
+ }
+ else
+ {
+ gcc_assert (!static_ctors);
+ gcc_assert (!static_dtors);
+ }
+}
+
/* Determine if function DECL is needed. That is, visible to something
either outside this translation unit, something magic in the system
configury, or (if not doing unit-at-a-time) to something we havn't
&& TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))
return true;
+ /* With -fkeep-inline-functions we are keeping all inline functions except
+ for extern inline ones. */
+ if (flag_keep_inline_functions
+ && DECL_DECLARED_INLINE_P (decl)
+ && !DECL_EXTERNAL (decl)
+ && !lookup_attribute ("always_inline", DECL_ATTRIBUTES (decl)))
+ return true;
+
/* If we decided it was needed before, but at the time we didn't have
the body of the function available, then it's still needed. We have
to go back and re-check its dependencies now. */
push_cfun (DECL_STRUCT_FUNCTION (fndecl));
current_function_decl = fndecl;
node->local.inlinable = tree_inlinable_function_p (fndecl);
- node->local.self_insns = estimate_num_insns (fndecl);
+ node->local.self_insns = estimate_num_insns (fndecl,
+ &eni_inlining_weights);
node->local.disregard_inline_limits
= lang_hooks.tree_inlining.disregard_inline_limits (fndecl);
/* Inlining characteristics are maintained by the
if (node->local.finalized)
cgraph_reset_node (node);
+ node->pid = cgraph_max_pid ++;
notice_global_symbol (decl);
node->decl = decl;
node->local.finalized = true;
node->lowered = DECL_STRUCT_FUNCTION (decl)->cfg != NULL;
+ record_cdtor_fn (node->decl);
if (node->nested)
lower_nested_functions (decl);
gcc_assert (!node->nested);
/* If not unit at a time, then we need to create the call graph
now, so that called functions can be queued and emitted now. */
if (!flag_unit_at_a_time)
- {
- cgraph_analyze_function (node);
- cgraph_decide_inlining_incrementally (node, false);
- }
+ cgraph_analyze_function (node);
if (decide_is_function_needed (node, decl))
cgraph_mark_needed_node (node);
error ("caller edge count is negative");
error_found = true;
}
+ if (e->frequency < 0)
+ {
+ error ("caller edge frequency is negative");
+ error_found = true;
+ }
+ if (e->frequency > CGRAPH_FREQ_MAX)
+ {
+ error ("caller edge frequency is too large");
+ error_found = true;
+ }
if (!e->inline_failed)
{
if (node->global.inlined_to
push_cfun (DECL_STRUCT_FUNCTION (decl));
cgraph_lower_function (node);
- node->local.estimated_self_stack_size = estimated_stack_frame_size ();
- node->global.estimated_stack_size = node->local.estimated_self_stack_size;
- node->global.stack_frame_offset = 0;
- node->local.inlinable = tree_inlinable_function_p (decl);
- if (!flag_unit_at_a_time)
- node->local.self_insns = estimate_num_insns (decl);
- if (node->local.inlinable)
- node->local.disregard_inline_limits
- = lang_hooks.tree_inlining.disregard_inline_limits (decl);
- if (flag_really_no_inline && !node->local.disregard_inline_limits)
- node->local.inlinable = 0;
- /* Inlining characteristics are maintained by the cgraph_mark_inline. */
- node->global.insns = node->local.self_insns;
if (!flag_unit_at_a_time)
{
bitmap_obstack_initialize (NULL);
/* Process CGRAPH_NODES_NEEDED queue, analyze each function (and transitively
each reachable functions) and build cgraph.
The function can be called multiple times after inserting new nodes
- into beggining of queue. Just the new part of queue is re-scanned then. */
+ into beginning of queue. Just the new part of queue is re-scanned then. */
static void
cgraph_analyze_functions (void)
static void
cgraph_expand_function (struct cgraph_node *node)
{
+ enum debug_info_type save_write_symbols = NO_DEBUG;
+ const struct gcc_debug_hooks *save_debug_hooks = NULL;
tree decl = node->decl;
/* We ought to not compile any inline clones. */
gcc_assert (node->lowered);
+ if (DECL_IGNORED_P (decl))
+ {
+ save_write_symbols = write_symbols;
+ write_symbols = NO_DEBUG;
+ save_debug_hooks = debug_hooks;
+ debug_hooks = &do_nothing_debug_hooks;
+ }
+
/* Generate RTL for the body of DECL. */
lang_hooks.callgraph.expand_function (decl);
/* ??? Can happen with nested function of extern inline. */
gcc_assert (TREE_ASM_WRITTEN (node->decl));
+ if (DECL_IGNORED_P (decl))
+ {
+ write_symbols = save_write_symbols;
+ debug_hooks = save_debug_hooks;
+ }
+
current_function_decl = NULL;
if (!cgraph_preserve_function_body_p (node->decl))
{
#ifdef ENABLE_CHECKING
verify_cgraph ();
#endif
+
+ /* Call functions declared with the "constructor" or "destructor"
+ attribute. */
+ cgraph_build_cdtor_fns ();
if (!flag_unit_at_a_time)
{
cgraph_assemble_pending_functions ();
{
case 'I':
DECL_STATIC_CONSTRUCTOR (decl) = 1;
+ decl_init_priority_insert (decl, priority);
break;
case 'D':
DECL_STATIC_DESTRUCTOR (decl) = 1;
+ decl_fini_priority_insert (decl, priority);
break;
default:
gcc_unreachable ();
cgraph_add_new_function (decl, false);
cgraph_mark_needed_node (cgraph_node (decl));
-
- if (targetm.have_ctors_dtors)
- {
- void (*fn) (rtx, int);
-
- if (which == 'I')
- fn = targetm.asm_out.constructor;
- else
- fn = targetm.asm_out.destructor;
- fn (XEXP (DECL_RTL (decl), 0), priority);
- }
}
void
for (e = new_version->callers; e; e = e->next_caller)
/* Update the call expr on the edges
to call the new version. */
- TREE_OPERAND (TREE_OPERAND (get_call_expr_in (e->call_stmt), 0), 0) = new_version->decl;
+ TREE_OPERAND (CALL_EXPR_FN (get_call_expr_in (e->call_stmt)), 0) = new_version->decl;
}
also cloned. */
for (e = old_version->callees;e; e=e->next_callee)
{
- new_e = cgraph_clone_edge (e, new_version, e->call_stmt, 0, e->loop_nest, true);
+ new_e = cgraph_clone_edge (e, new_version, e->call_stmt, 0, e->frequency,
+ e->loop_nest, true);
new_e->count = e->count;
}
/* Fix recursive calls.
{
struct cgraph_edge *e;
- first_clone = cgraph_clone_node (node, node->count, 0, false);
+ first_clone = cgraph_clone_node (node, node->count, 0, CGRAPH_FREQ_BASE,
+ false);
first_clone->needed = 0;
first_clone->reachable = 1;
/* Recursively clone all bodies. */
#endif
return first_clone;
}
+
+#include "gt-cgraphunit.h"