+/* Give initial reasons why inlining would fail. Those gets
+ either NULLified or usually overwritten by more precise reason
+ later. */
+static void
+initialize_inline_failed (struct cgraph_node *node)
+{
+ struct cgraph_edge *e;
+
+ for (e = node->callers; e; e = e->next_caller)
+ {
+ gcc_assert (!e->callee->global.inlined_to);
+ gcc_assert (e->inline_failed);
+ if (node->local.redefined_extern_inline)
+ e->inline_failed = N_("redefined extern inline functions are not "
+ "considered for inlining");
+ else if (!node->local.inlinable)
+ e->inline_failed = N_("function not inlinable");
+ else
+ e->inline_failed = N_("function not considered for inlining");
+ }
+}
+
+/* Rebuild call edges from current function after a passes not aware
+ of cgraph updating. */
+static void
+rebuild_cgraph_edges (void)
+{
+ basic_block bb;
+ struct cgraph_node *node = cgraph_node (current_function_decl);
+ block_stmt_iterator bsi;
+
+ cgraph_node_remove_callees (node);
+
+ node->count = ENTRY_BLOCK_PTR->count;
+
+ FOR_EACH_BB (bb)
+ for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+ {
+ tree stmt = bsi_stmt (bsi);
+ tree call = get_call_expr_in (stmt);
+ tree decl;
+
+ if (call && (decl = get_callee_fndecl (call)))
+ cgraph_create_edge (node, cgraph_node (decl), stmt,
+ bb->count,
+ bb->loop_depth);
+ }
+ initialize_inline_failed (node);
+ gcc_assert (!node->global.inlined_to);
+}
+
+struct tree_opt_pass pass_rebuild_cgraph_edges =
+{
+ NULL, /* name */
+ NULL, /* gate */
+ rebuild_cgraph_edges, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ 0, /* tv_id */
+ PROP_cfg, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ 0, /* todo_flags_finish */
+ 0 /* letter */
+};
+
+/* Verify cgraph nodes of given cgraph node. */
+void
+verify_cgraph_node (struct cgraph_node *node)
+{
+ struct cgraph_edge *e;
+ struct cgraph_node *main_clone;
+ struct function *this_cfun = DECL_STRUCT_FUNCTION (node->decl);
+ basic_block this_block;
+ block_stmt_iterator bsi;
+ bool error_found = false;
+
+ timevar_push (TV_CGRAPH_VERIFY);
+ for (e = node->callees; e; e = e->next_callee)
+ if (e->aux)
+ {
+ error ("aux field set for edge %s->%s",
+ cgraph_node_name (e->caller), cgraph_node_name (e->callee));
+ error_found = true;
+ }
+ for (e = node->callers; e; e = e->next_caller)
+ {
+ if (!e->inline_failed)
+ {
+ if (node->global.inlined_to
+ != (e->caller->global.inlined_to
+ ? e->caller->global.inlined_to : e->caller))
+ {
+ error ("inlined_to pointer is wrong");
+ error_found = true;
+ }
+ if (node->callers->next_caller)
+ {
+ error ("multiple inline callers");
+ error_found = true;
+ }
+ }
+ else
+ if (node->global.inlined_to)
+ {
+ error ("inlined_to pointer set for noninline callers");
+ error_found = true;
+ }
+ }
+ if (!node->callers && node->global.inlined_to)
+ {
+ error ("inlined_to pointer is set but no predecesors found");
+ error_found = true;
+ }
+ if (node->global.inlined_to == node)
+ {
+ error ("inlined_to pointer refers to itself");
+ error_found = true;
+ }
+
+ for (main_clone = cgraph_node (node->decl); main_clone;
+ main_clone = main_clone->next_clone)
+ if (main_clone == node)
+ break;
+ if (!node)
+ {
+ error ("node not found in DECL_ASSEMBLER_NAME hash");
+ error_found = true;
+ }
+
+ if (node->analyzed
+ && DECL_SAVED_TREE (node->decl) && !TREE_ASM_WRITTEN (node->decl)
+ && (!DECL_EXTERNAL (node->decl) || node->global.inlined_to))
+ {
+ if (this_cfun->cfg)
+ {
+ /* The nodes we're interested in are never shared, so walk
+ the tree ignoring duplicates. */
+ visited_nodes = pointer_set_create ();
+ /* Reach the trees by walking over the CFG, and note the
+ enclosing basic-blocks in the call edges. */
+ FOR_EACH_BB_FN (this_block, this_cfun)
+ for (bsi = bsi_start (this_block); !bsi_end_p (bsi); bsi_next (&bsi))
+ {
+ tree stmt = bsi_stmt (bsi);
+ tree call = get_call_expr_in (stmt);
+ tree decl;
+ if (call && (decl = get_callee_fndecl (call)))
+ {
+ struct cgraph_edge *e = cgraph_edge (node, stmt);
+ if (e)
+ {
+ if (e->aux)
+ {
+ error ("shared call_stmt:");
+ debug_generic_stmt (stmt);
+ error_found = true;
+ }
+ if (e->callee->decl != cgraph_node (decl)->decl)
+ {
+ error ("edge points to wrong declaration:");
+ debug_tree (e->callee->decl);
+ fprintf (stderr," Instead of:");
+ debug_tree (decl);
+ }
+ e->aux = (void *)1;
+ }
+ else
+ {
+ error ("missing callgraph edge for call stmt:");
+ debug_generic_stmt (stmt);
+ error_found = true;
+ }
+ }
+ }
+ pointer_set_destroy (visited_nodes);
+ visited_nodes = NULL;
+ }
+ else
+ /* No CFG available?! */
+ gcc_unreachable ();
+
+ for (e = node->callees; e; e = e->next_callee)
+ {
+ if (!e->aux)
+ {
+ error ("edge %s->%s has no corresponding call_stmt",
+ cgraph_node_name (e->caller),
+ cgraph_node_name (e->callee));
+ debug_generic_stmt (e->call_stmt);
+ error_found = true;
+ }
+ e->aux = 0;
+ }
+ }
+ if (error_found)
+ {
+ dump_cgraph_node (stderr, node);
+ internal_error ("verify_cgraph_node failed");
+ }
+ timevar_pop (TV_CGRAPH_VERIFY);
+}
+
+/* Verify whole cgraph structure. */
+void
+verify_cgraph (void)
+{
+ struct cgraph_node *node;
+
+ if (sorrycount || errorcount)
+ return;
+
+ for (node = cgraph_nodes; node; node = node->next)
+ verify_cgraph_node (node);
+}
+
+
+/* Output all variables enqueued to be assembled. */
+bool
+cgraph_varpool_assemble_pending_decls (void)
+{
+ bool changed = false;
+
+ if (errorcount || sorrycount)
+ return false;
+
+ /* EH might mark decls as needed during expansion. This should be safe since
+ we don't create references to new function, but it should not be used
+ elsewhere. */
+ cgraph_varpool_analyze_pending_decls ();
+
+ while (cgraph_varpool_nodes_queue)
+ {
+ tree decl = cgraph_varpool_nodes_queue->decl;
+ struct cgraph_varpool_node *node = cgraph_varpool_nodes_queue;
+
+ cgraph_varpool_nodes_queue = cgraph_varpool_nodes_queue->next_needed;
+ if (!TREE_ASM_WRITTEN (decl) && !node->alias && !DECL_EXTERNAL (decl))
+ {
+ assemble_variable (decl, 0, 1, 0);
+ /* Local static variables are never seen by check_global_declarations
+ so we need to output debug info by hand. */
+ if (decl_function_context (decl) && errorcount == 0 && sorrycount == 0)
+ {
+ timevar_push (TV_SYMOUT);
+ (*debug_hooks->global_decl) (decl);
+ timevar_pop (TV_SYMOUT);
+ }
+ changed = true;
+ }
+ node->next_needed = NULL;
+ }
+ return changed;
+}
+