* cgraphunit.c: Update toplevel comment.
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 25 Apr 2012 16:31:42 +0000 (16:31 +0000)
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 25 Apr 2012 16:31:42 +0000 (16:31 +0000)
(tree_rest_of_compilation): Merge into cgraph_expand_function.
(cgraph_analyze_function): Make static.
(cgraph_decide_is_function_needed): Make static.
(cgraph_add_new_function): Use expand_function instead of
rest_of_compilation.
(clone_of_p, verify_edge_count_and_frequency, cgraph_debug_gimple_stmt,
verify_edge_corresponds_to_fndecl, verify_cgraph_node, verify_cgraph):
Move to cgraph.c
(cgraph_inline_p): Remove.
(cgraph_preserve_function_body_p): Move to ipa-inline-transform.
(init_cgraph): Add comment.
* cgraphbuild.c (record_reference, mark_address, mark_load,
mark_store): Do not call analyze_expr hook.
* cgraph.c: Update toplevel comment.
(clone_of_p, verify_edge_count_and_frequency, cgraph_debug_gimple_stmt,
verify_edge_corresponds_to_fndecl, verify_cgraph_node, verify_cgraph):
Move fere from cgraphunit.c
(cgraph_mark_force_output_node): Move to cgraph.h
* cgraph.h: Reorder so the comments match the function placement.
(cgraph_analyze_function, cgraph_decide_is_function_needed): Remove.
(cgraph_mark_force_output_node): Move here from cgraph.c
* tree.c (free_lang_data): Do not clear analyze_expr hook.
* ipa-inline-transform.c (preserve_function_body_p): New function.
(inline_transform): Update.
* langhooks.c (lhd_callgraph_analyze_expr): Remove.
* langhooks.h (lang_hooks_for_callgraph): Remove.
(lang_hooks): Remove callgraph.
* tree-inline.c (expand_call_inline): Do not use cgraph_inline_p.
* varpool.c: Remove out of date comment.
* langhooks-def.h (lhd_callgraph_analyze_expr): Remove.
(LANG_HOOKS_CALLGRAPH_ANALYZE_EXPR): Remove.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@186832 138bc75d-0d04-0410-961f-82ee72b054a4

12 files changed:
gcc/ChangeLog
gcc/cgraph.c
gcc/cgraph.h
gcc/cgraphbuild.c
gcc/cgraphunit.c
gcc/ipa-inline-transform.c
gcc/langhooks-def.h
gcc/langhooks.c
gcc/langhooks.h
gcc/tree-inline.c
gcc/tree.c
gcc/varpool.c

index 99203ff..51fefab 100644 (file)
@@ -1,5 +1,40 @@
 2012-04-25  Jan Hubicka  <jh@suse.cz>
 
+       * cgraphunit.c: Update toplevel comment.
+       (tree_rest_of_compilation): Merge into cgraph_expand_function.
+       (cgraph_analyze_function): Make static.
+       (cgraph_decide_is_function_needed): Make static.
+       (cgraph_add_new_function): Use expand_function instead of
+       rest_of_compilation.
+       (clone_of_p, verify_edge_count_and_frequency, cgraph_debug_gimple_stmt,
+       verify_edge_corresponds_to_fndecl, verify_cgraph_node, verify_cgraph):
+       Move to cgraph.c
+       (cgraph_inline_p): Remove.
+       (cgraph_preserve_function_body_p): Move to ipa-inline-transform.
+       (init_cgraph): Add comment.
+       * cgraphbuild.c (record_reference, mark_address, mark_load,
+       mark_store): Do not call analyze_expr hook.
+       * cgraph.c: Update toplevel comment.
+       (clone_of_p, verify_edge_count_and_frequency, cgraph_debug_gimple_stmt,
+       verify_edge_corresponds_to_fndecl, verify_cgraph_node, verify_cgraph):
+       Move fere from cgraphunit.c
+       (cgraph_mark_force_output_node): Move to cgraph.h
+       * cgraph.h: Reorder so the comments match the function placement.
+       (cgraph_analyze_function, cgraph_decide_is_function_needed): Remove.
+       (cgraph_mark_force_output_node): Move here from cgraph.c
+       * tree.c (free_lang_data): Do not clear analyze_expr hook.
+       * ipa-inline-transform.c (preserve_function_body_p): New function.
+       (inline_transform): Update.
+       * langhooks.c (lhd_callgraph_analyze_expr): Remove.
+       * langhooks.h (lang_hooks_for_callgraph): Remove.
+       (lang_hooks): Remove callgraph.
+       * tree-inline.c (expand_call_inline): Do not use cgraph_inline_p.
+       * varpool.c: Remove out of date comment.
+       * langhooks-def.h (lhd_callgraph_analyze_expr): Remove.
+       (LANG_HOOKS_CALLGRAPH_ANALYZE_EXPR): Remove.
+
+2012-04-25  Jan Hubicka  <jh@suse.cz>
+
        PR middle-end/53089 
        * cgraphunit.c (referred_to_p): Move ahead in file to avoid forward declaration.
        (cgraph_finalize_function): Finalize them here.
index 298a030..e689d10 100644 (file)
@@ -21,56 +21,8 @@ along with GCC; see the file COPYING3.  If not see
 
 /*  This file contains basic routines manipulating call graph
 
-The callgraph:
-
-    The call-graph is data structure designed for intra-procedural optimization
-    but it is also used in non-unit-at-a-time compilation to allow easier code
-    sharing.
-
-    The call-graph consist of nodes and edges represented via linked lists.
-    Each function (external or not) corresponds to the unique node.
-
-    The mapping from declarations to call-graph nodes is done using hash table
-    based on DECL_UID.  The call-graph nodes are created lazily using
-    cgraph_node function when called for unknown declaration.
-
-    The callgraph at the moment does not represent all indirect calls or calls
-    from other compilation units.  Flag NEEDED is set for each node that may be
-    accessed in such an invisible way and it shall be considered an entry point
-    to the callgraph.
-
-    On the other hand, the callgraph currently does contain some edges for
-    indirect calls with unknown callees which can be accessed through
-    indirect_calls field of a node.  It should be noted however that at the
-    moment only calls which are potential candidates for indirect inlining are
-    added there.
-
-    Interprocedural information:
-
-      Callgraph is place to store data needed for interprocedural optimization.
-      All data structures are divided into three components: local_info that
-      is produced while analyzing the function, global_info that is result
-      of global walking of the callgraph on the end of compilation and
-      rtl_info used by RTL backend to propagate data from already compiled
-      functions to their callers.
-
-      Moreover, each node has a uid which can be used to keep information in
-      on-the-side arrays.  UIDs are reused and therefore reasonably dense.
-
-    Inlining plans:
-
-      The function inlining information is decided in advance and maintained
-      in the callgraph as so called inline plan.
-      For each inlined call, the callee's node is cloned to represent the
-      new function copy produced by inliner.
-      Each inlined call gets a unique corresponding clone node of the callee
-      and the data structure is updated while inlining is performed, so
-      the clones are eliminated and their callee edges redirected to the
-      caller.
-
-      Each edge has "inline_failed" field.  When the field is set to NULL,
-      the call will be inlined.  When it is non-NULL it contains a reason
-      why inlining wasn't performed.  */
+    The call-graph is a data structure designed for intra-procedural optimization.
+    It represents a multi-graph where nodes are functions and edges are call sites. */
 
 #include "config.h"
 #include "system.h"
@@ -100,6 +52,7 @@ The callgraph:
 #include "lto-streamer.h"
 #include "ipa-inline.h"
 #include "cfgloop.h"
+#include "gimple-pretty-print.h"
 
 const char * const ld_plugin_symbol_resolution_names[]=
 {
@@ -1472,16 +1425,6 @@ cgraph_remove_node_and_inline_clones (struct cgraph_node *node, struct cgraph_no
   return found;
 }
 
-/* Likewise indicate that a node is needed, i.e. reachable via some
-   external means.  */
-
-void
-cgraph_mark_force_output_node (struct cgraph_node *node)
-{
-  node->symbol.force_output = 1;
-  gcc_assert (!node->global.inlined_to);
-}
-
 /* Likewise indicate that a node is having address taken.  */
 
 void
@@ -2672,4 +2615,401 @@ collect_callers_of_node (struct cgraph_node *node)
   return redirect_callers;
 }
 
+/* Return TRUE if NODE2 is equivalent to NODE or its clone.  */
+static bool
+clone_of_p (struct cgraph_node *node, struct cgraph_node *node2)
+{
+  node = cgraph_function_or_thunk_node (node, NULL);
+  node2 = cgraph_function_or_thunk_node (node2, NULL);
+  while (node != node2 && node2)
+    node2 = node2->clone_of;
+  return node2 != NULL;
+}
+
+/* Verify edge E count and frequency.  */
+
+static bool
+verify_edge_count_and_frequency (struct cgraph_edge *e)
+{
+  bool error_found = false;
+  if (e->count < 0)
+    {
+      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 (gimple_has_body_p (e->caller->symbol.decl)
+      && !e->caller->global.inlined_to
+      /* FIXME: Inline-analysis sets frequency to 0 when edge is optimized out.
+        Remove this once edges are actualy removed from the function at that time.  */
+      && (e->frequency
+         || (inline_edge_summary_vec
+             && ((VEC_length(inline_edge_summary_t, inline_edge_summary_vec)
+                 <= (unsigned) e->uid)
+                 || !inline_edge_summary (e)->predicate)))
+      && (e->frequency
+         != compute_call_stmt_bb_frequency (e->caller->symbol.decl,
+                                            gimple_bb (e->call_stmt))))
+    {
+      error ("caller edge frequency %i does not match BB frequency %i",
+            e->frequency,
+            compute_call_stmt_bb_frequency (e->caller->symbol.decl,
+                                            gimple_bb (e->call_stmt)));
+      error_found = true;
+    }
+  return error_found;
+}
+
+/* Switch to THIS_CFUN if needed and print STMT to stderr.  */
+static void
+cgraph_debug_gimple_stmt (struct function *this_cfun, gimple stmt)
+{
+  /* debug_gimple_stmt needs correct cfun */
+  if (cfun != this_cfun)
+    set_cfun (this_cfun);
+  debug_gimple_stmt (stmt);
+}
+
+/* Verify that call graph edge E corresponds to DECL from the associated
+   statement.  Return true if the verification should fail.  */
+
+static bool
+verify_edge_corresponds_to_fndecl (struct cgraph_edge *e, tree decl)
+{
+  struct cgraph_node *node;
+
+  if (!decl || e->callee->global.inlined_to)
+    return false;
+  node = cgraph_get_node (decl);
+
+  /* We do not know if a node from a different partition is an alias or what it
+     aliases and therefore cannot do the former_clone_of check reliably.  */
+  if (!node || node->symbol.in_other_partition)
+    return false;
+  node = cgraph_function_or_thunk_node (node, NULL);
+
+  if ((e->callee->former_clone_of != node->symbol.decl
+       && (!node->same_body_alias
+          || e->callee->former_clone_of != node->thunk.alias))
+      /* IPA-CP sometimes redirect edge to clone and then back to the former
+        function.  This ping-pong has to go, eventually.  */
+      && (node != cgraph_function_or_thunk_node (e->callee, NULL))
+      && !clone_of_p (node, e->callee)
+      /* If decl is a same body alias of some other decl, allow e->callee to be
+        a clone of a clone of that other decl too.  */
+      && (!node->same_body_alias
+         || !clone_of_p (cgraph_get_node (node->thunk.alias), e->callee)))
+    return true;
+  else
+    return false;
+}
+
+/* Verify cgraph nodes of given cgraph node.  */
+DEBUG_FUNCTION void
+verify_cgraph_node (struct cgraph_node *node)
+{
+  struct cgraph_edge *e;
+  struct function *this_cfun = DECL_STRUCT_FUNCTION (node->symbol.decl);
+  basic_block this_block;
+  gimple_stmt_iterator gsi;
+  bool error_found = false;
+
+  if (seen_error ())
+    return;
+
+  timevar_push (TV_CGRAPH_VERIFY);
+  error_found |= verify_symtab_base ((symtab_node) node);
+  for (e = node->callees; e; e = e->next_callee)
+    if (e->aux)
+      {
+       error ("aux field set for edge %s->%s",
+              identifier_to_locale (cgraph_node_name (e->caller)),
+              identifier_to_locale (cgraph_node_name (e->callee)));
+       error_found = true;
+      }
+  if (node->count < 0)
+    {
+      error ("execution count is negative");
+      error_found = true;
+    }
+  if (node->global.inlined_to && node->symbol.externally_visible)
+    {
+      error ("externally visible inline clone");
+      error_found = true;
+    }
+  if (node->global.inlined_to && node->symbol.address_taken)
+    {
+      error ("inline clone with address taken");
+      error_found = true;
+    }
+  if (node->global.inlined_to && node->symbol.force_output)
+    {
+      error ("inline clone is forced to output");
+      error_found = true;
+    }
+  for (e = node->indirect_calls; e; e = e->next_callee)
+    {
+      if (e->aux)
+       {
+         error ("aux field set for indirect edge from %s",
+                identifier_to_locale (cgraph_node_name (e->caller)));
+         error_found = true;
+       }
+      if (!e->indirect_unknown_callee
+         || !e->indirect_info)
+       {
+         error ("An indirect edge from %s is not marked as indirect or has "
+                "associated indirect_info, the corresponding statement is: ",
+                identifier_to_locale (cgraph_node_name (e->caller)));
+         cgraph_debug_gimple_stmt (this_cfun, e->call_stmt);
+         error_found = true;
+       }
+    }
+  for (e = node->callers; e; e = e->next_caller)
+    {
+      if (verify_edge_count_and_frequency (e))
+       error_found = true;
+      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;
+         }
+    }
+  for (e = node->indirect_calls; e; e = e->next_callee)
+    if (verify_edge_count_and_frequency (e))
+      error_found = true;
+  if (!node->callers && node->global.inlined_to)
+    {
+      error ("inlined_to pointer is set but no predecessors found");
+      error_found = true;
+    }
+  if (node->global.inlined_to == node)
+    {
+      error ("inlined_to pointer refers to itself");
+      error_found = true;
+    }
+
+  if (node->clone_of)
+    {
+      struct cgraph_node *n;
+      for (n = node->clone_of->clones; n; n = n->next_sibling_clone)
+        if (n == node)
+         break;
+      if (!n)
+       {
+         error ("node has wrong clone_of");
+         error_found = true;
+       }
+    }
+  if (node->clones)
+    {
+      struct cgraph_node *n;
+      for (n = node->clones; n; n = n->next_sibling_clone)
+        if (n->clone_of != node)
+         break;
+      if (n)
+       {
+         error ("node has wrong clone list");
+         error_found = true;
+       }
+    }
+  if ((node->prev_sibling_clone || node->next_sibling_clone) && !node->clone_of)
+    {
+       error ("node is in clone list but it is not clone");
+       error_found = true;
+    }
+  if (!node->prev_sibling_clone && node->clone_of && node->clone_of->clones != node)
+    {
+      error ("node has wrong prev_clone pointer");
+      error_found = true;
+    }
+  if (node->prev_sibling_clone && node->prev_sibling_clone->next_sibling_clone != node)
+    {
+      error ("double linked list of clones corrupted");
+      error_found = true;
+    }
+
+  if (node->analyzed && node->alias)
+    {
+      bool ref_found = false;
+      int i;
+      struct ipa_ref *ref;
+
+      if (node->callees)
+       {
+         error ("Alias has call edges");
+          error_found = true;
+       }
+      for (i = 0; ipa_ref_list_reference_iterate (&node->symbol.ref_list,
+                                                 i, ref); i++)
+       if (ref->use != IPA_REF_ALIAS)
+         {
+           error ("Alias has non-alias reference");
+           error_found = true;
+         }
+       else if (ref_found)
+         {
+           error ("Alias has more than one alias reference");
+           error_found = true;
+         }
+       else
+         ref_found = true;
+       if (!ref_found)
+         {
+           error ("Analyzed alias has no reference");
+           error_found = true;
+         }
+    }
+  if (node->analyzed && node->thunk.thunk_p)
+    {
+      if (!node->callees)
+       {
+         error ("No edge out of thunk node");
+          error_found = true;
+       }
+      else if (node->callees->next_callee)
+       {
+         error ("More than one edge out of thunk node");
+          error_found = true;
+       }
+      if (gimple_has_body_p (node->symbol.decl))
+        {
+         error ("Thunk is not supposed to have body");
+          error_found = true;
+        }
+    }
+  else if (node->analyzed && gimple_has_body_p (node->symbol.decl)
+           && !TREE_ASM_WRITTEN (node->symbol.decl)
+           && (!DECL_EXTERNAL (node->symbol.decl) || node->global.inlined_to)
+           && !flag_wpa)
+    {
+      if (this_cfun->cfg)
+       {
+         /* The nodes we're interested in are never shared, so walk
+            the tree ignoring duplicates.  */
+         struct pointer_set_t *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 (gsi = gsi_start_bb (this_block);
+                 !gsi_end_p (gsi);
+                 gsi_next (&gsi))
+             {
+               gimple stmt = gsi_stmt (gsi);
+               if (is_gimple_call (stmt))
+                 {
+                   struct cgraph_edge *e = cgraph_edge (node, stmt);
+                   tree decl = gimple_call_fndecl (stmt);
+                   if (e)
+                     {
+                       if (e->aux)
+                         {
+                           error ("shared call_stmt:");
+                           cgraph_debug_gimple_stmt (this_cfun, stmt);
+                           error_found = true;
+                         }
+                       if (!e->indirect_unknown_callee)
+                         {
+                           if (verify_edge_corresponds_to_fndecl (e, decl))
+                             {
+                               error ("edge points to wrong declaration:");
+                               debug_tree (e->callee->symbol.decl);
+                               fprintf (stderr," Instead of:");
+                               debug_tree (decl);
+                               error_found = true;
+                             }
+                         }
+                       else if (decl)
+                         {
+                           error ("an indirect edge with unknown callee "
+                                  "corresponding to a call_stmt with "
+                                  "a known declaration:");
+                           error_found = true;
+                           cgraph_debug_gimple_stmt (this_cfun, e->call_stmt);
+                         }
+                       e->aux = (void *)1;
+                     }
+                   else if (decl)
+                     {
+                       error ("missing callgraph edge for call stmt:");
+                       cgraph_debug_gimple_stmt (this_cfun, stmt);
+                       error_found = true;
+                     }
+                 }
+             }
+         pointer_set_destroy (visited_nodes);
+       }
+      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",
+                    identifier_to_locale (cgraph_node_name (e->caller)),
+                    identifier_to_locale (cgraph_node_name (e->callee)));
+             cgraph_debug_gimple_stmt (this_cfun, e->call_stmt);
+             error_found = true;
+           }
+         e->aux = 0;
+       }
+      for (e = node->indirect_calls; e; e = e->next_callee)
+       {
+         if (!e->aux)
+           {
+             error ("an indirect edge from %s has no corresponding call_stmt",
+                    identifier_to_locale (cgraph_node_name (e->caller)));
+             cgraph_debug_gimple_stmt (this_cfun, 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.  */
+DEBUG_FUNCTION void
+verify_cgraph (void)
+{
+  struct cgraph_node *node;
+
+  if (seen_error ())
+    return;
+
+  FOR_EACH_FUNCTION (node)
+    verify_cgraph_node (node);
+}
 #include "gt-cgraph.h"
index df74d51..652556f 100644 (file)
@@ -574,37 +574,9 @@ bool cgraph_for_node_and_aliases (struct cgraph_node *,
                                  bool (*) (struct cgraph_node *, void *),
                                  void *, bool);
 VEC (cgraph_edge_p, heap) * collect_callers_of_node (struct cgraph_node *node);
-
-
-/* In cgraphunit.c  */
-extern FILE *cgraph_dump_file;
-void cgraph_finalize_function (tree, bool);
-void cgraph_analyze_function (struct cgraph_node *);
-void cgraph_finalize_compilation_unit (void);
-void cgraph_optimize (void);
-void cgraph_mark_force_output_node (struct cgraph_node *);
-void cgraph_mark_address_taken_node (struct cgraph_node *);
-bool cgraph_inline_p (struct cgraph_edge *, cgraph_inline_failed_t *reason);
-bool cgraph_preserve_function_body_p (struct cgraph_node *);
 void verify_cgraph (void);
 void verify_cgraph_node (struct cgraph_node *);
-void cgraph_build_static_cdtor (char which, tree body, int priority);
-void cgraph_reset_static_var_maps (void);
-void init_cgraph (void);
-struct cgraph_node * cgraph_copy_node_for_versioning (struct cgraph_node *,
-               tree, VEC(cgraph_edge_p,heap)*, bitmap);
-struct cgraph_node *cgraph_function_versioning (struct cgraph_node *,
-                                               VEC(cgraph_edge_p,heap)*,
-                                               VEC(ipa_replace_map_p,gc)*,
-                                               bitmap, bool, bitmap,
-                                               basic_block, const char *);
-void tree_function_versioning (tree, tree, VEC (ipa_replace_map_p,gc)*,
-                              bool, bitmap, bool, bitmap, basic_block);
-void record_references_in_initializer (tree, bool);
-bool cgraph_process_new_functions (void);
-void cgraph_process_same_body_aliases (void);
-
-bool cgraph_decide_is_function_needed (struct cgraph_node *, tree);
+void cgraph_mark_address_taken_node (struct cgraph_node *);
 
 typedef void (*cgraph_edge_hook)(struct cgraph_edge *, void *);
 typedef void (*cgraph_node_hook)(struct cgraph_node *, void *);
@@ -631,10 +603,31 @@ struct cgraph_2node_hook_list *cgraph_add_node_duplication_hook (cgraph_2node_ho
 void cgraph_remove_node_duplication_hook (struct cgraph_2node_hook_list *);
 gimple cgraph_redirect_edge_call_stmt_to_callee (struct cgraph_edge *);
 bool cgraph_propagate_frequency (struct cgraph_node *node);
+
+/* In cgraphunit.c  */
+extern FILE *cgraph_dump_file;
+void cgraph_finalize_function (tree, bool);
+void cgraph_finalize_compilation_unit (void);
+void cgraph_optimize (void);
+void init_cgraph (void);
+struct cgraph_node * cgraph_copy_node_for_versioning (struct cgraph_node *,
+               tree, VEC(cgraph_edge_p,heap)*, bitmap);
+struct cgraph_node *cgraph_function_versioning (struct cgraph_node *,
+                                               VEC(cgraph_edge_p,heap)*,
+                                               VEC(ipa_replace_map_p,gc)*,
+                                               bitmap, bool, bitmap,
+                                               basic_block, const char *);
+void tree_function_versioning (tree, tree, VEC (ipa_replace_map_p,gc)*,
+                              bool, bitmap, bool, bitmap, basic_block);
+bool cgraph_process_new_functions (void);
+void cgraph_process_same_body_aliases (void);
+
+
 /* In cgraphbuild.c  */
 unsigned int rebuild_cgraph_edges (void);
 void cgraph_rebuild_references (void);
 int compute_call_stmt_bb_frequency (tree, basic_block bb);
+void record_references_in_initializer (tree, bool);
 
 /* In ipa.c  */
 bool cgraph_remove_unreachable_nodes (bool, FILE *);
@@ -646,6 +639,7 @@ void cgraph_node_set_remove (cgraph_node_set, struct cgraph_node *);
 void dump_cgraph_node_set (FILE *, cgraph_node_set);
 void debug_cgraph_node_set (cgraph_node_set);
 void free_cgraph_node_set (cgraph_node_set);
+void cgraph_build_static_cdtor (char which, tree body, int priority);
 
 varpool_node_set varpool_node_set_new (void);
 varpool_node_set_iterator varpool_node_set_find (varpool_node_set,
@@ -1284,4 +1278,14 @@ decl_is_tm_clone (const_tree fndecl)
     return n->tm_clone;
   return false;
 }
+
+/* Likewise indicate that a node is needed, i.e. reachable via some
+   external means.  */
+
+static inline void
+cgraph_mark_force_output_node (struct cgraph_node *node)
+{
+  node->symbol.force_output = 1;
+  gcc_checking_assert (!node->global.inlined_to);
+}
 #endif  /* GCC_CGRAPH_H  */
index 445a392..a847980 100644 (file)
@@ -85,8 +85,6 @@ record_reference (tree *tp, int *walk_subtrees, void *data)
       if (TREE_CODE (decl) == VAR_DECL)
        {
          struct varpool_node *vnode = varpool_node (decl);
-         if (lang_hooks.callgraph.analyze_expr)
-           lang_hooks.callgraph.analyze_expr (&decl, walk_subtrees);
          ipa_record_reference ((symtab_node)ctx->varpool_node,
                                (symtab_node)vnode,
                                IPA_REF_ADDR, NULL);
@@ -102,9 +100,6 @@ record_reference (tree *tp, int *walk_subtrees, void *data)
          *walk_subtrees = 0;
          break;
        }
-
-      if ((unsigned int) TREE_CODE (t) >= LAST_AND_UNUSED_TREE_CODE)
-       return lang_hooks.callgraph.analyze_expr (tp, walk_subtrees);
       break;
     }
 
@@ -239,10 +234,7 @@ mark_address (gimple stmt, tree addr, void *data)
           && (TREE_STATIC (addr) || DECL_EXTERNAL (addr)))
     {
       struct varpool_node *vnode = varpool_node (addr);
-      int walk_subtrees;
 
-      if (lang_hooks.callgraph.analyze_expr)
-       lang_hooks.callgraph.analyze_expr (&addr, &walk_subtrees);
       ipa_record_reference ((symtab_node)data,
                            (symtab_node)vnode,
                            IPA_REF_ADDR, stmt);
@@ -271,10 +263,7 @@ mark_load (gimple stmt, tree t, void *data)
           && (TREE_STATIC (t) || DECL_EXTERNAL (t)))
     {
       struct varpool_node *vnode = varpool_node (t);
-      int walk_subtrees;
 
-      if (lang_hooks.callgraph.analyze_expr)
-       lang_hooks.callgraph.analyze_expr (&t, &walk_subtrees);
       ipa_record_reference ((symtab_node)data,
                            (symtab_node)vnode,
                            IPA_REF_LOAD, stmt);
@@ -292,10 +281,7 @@ mark_store (gimple stmt, tree t, void *data)
       && (TREE_STATIC (t) || DECL_EXTERNAL (t)))
     {
       struct varpool_node *vnode = varpool_node (t);
-      int walk_subtrees;
 
-      if (lang_hooks.callgraph.analyze_expr)
-       lang_hooks.callgraph.analyze_expr (&t, &walk_subtrees);
       ipa_record_reference ((symtab_node)data,
                            (symtab_node)vnode,
                            IPA_REF_STORE, stmt);
index a58cd08..60ccc82 100644 (file)
@@ -1,4 +1,4 @@
-/* Callgraph based interprocedural optimizations.
+/* Driver of optimization process
    Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
    2011, 2012 Free Software Foundation, Inc.
    Contributed by Jan Hubicka
@@ -19,11 +19,10 @@ You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
 
-/* This module implements main driver of compilation process as well as
-   few basic interprocedural optimizers.
+/* This module implements main driver of compilation process.
 
    The main scope of this file is to act as an interface in between
-   tree based frontends and the backend (and middle end)
+   tree based frontends and the backend.
 
    The front-end is supposed to use following functionality:
 
@@ -45,66 +44,115 @@ along with GCC; see the file COPYING3.  If not see
       This function is called once (source level) compilation unit is finalized
       and it will no longer change.
 
-      In the call-graph construction and local function analysis takes
-      place here.  Bodies of unreachable functions are released to
-      conserve memory usage.
+      The symbol table is constructed starting from the trivially needed
+      symbols finalized by the frontend.  Functions are lowered into
+      GIMPLE representation and callgraph/reference lists are constructed.
+      Those are used to discover other neccesary functions and variables.
+
+      At the end the bodies of unreachable functions are removed.
 
       The function can be called multiple times when multiple source level
-      compilation units are combined (such as in C frontend)
+      compilation units are combined.
 
     - cgraph_optimize
 
-      In this unit-at-a-time compilation the intra procedural analysis takes
-      place here.  In particular the static functions whose address is never
-      taken are marked as local.  Backend can then use this information to
-      modify calling conventions, do better inlining or similar optimizations.
+      This passes control to the back-end.  Optimizations are performed and
+      final assembler is generated.  This is done in the following way. Note
+      that with link time optimization the process is split into three
+      stages (compile time, linktime analysis and parallel linktime as
+      indicated bellow).
+
+      Compile time:
+
+       1) Inter-procedural optimization.
+          (ipa_passes)
+
+          This part is further split into:
+
+          a) early optimizations. These are local passes executed in
+             the topological order on the callgraph.
+
+             The purpose of early optimiations is to optimize away simple
+             things that may otherwise confuse IP analysis. Very simple
+             propagation across the callgraph is done i.e. to discover
+             functions without side effects and simple inlining is performed.
+
+          b) early small interprocedural passes.
+
+             Those are interprocedural passes executed only at compilation
+             time.  These include, for exmaple, transational memory lowering,
+             unreachable code removal and other simple transformations.
+
+          c) IP analysis stage.  All interprocedural passes do their
+             analysis.
+
+             Interprocedural passes differ from small interprocedural
+             passes by their ability to operate across whole program
+             at linktime.  Their analysis stage is performed early to
+             both reduce linking times and linktime memory usage by    
+             not having to represent whole program in memory.
+
+          d) LTO sreaming.  When doing LTO, everything important gets
+             streamed into the object file.
+
+       Compile time and or linktime analysis stage (WPA):
+
+             At linktime units gets streamed back and symbol table is
+             merged.  Function bodies are not streamed in and not
+             available.
+          e) IP propagation stage.  All IP passes execute their
+             IP propagation. This is done based on the earlier analysis
+             without having function bodies at hand.
+          f) Ltrans streaming.  When doing WHOPR LTO, the program
+             is partitioned and streamed into multple object files.
+
+       Compile time and/or parallel linktime stage (ltrans)
 
-    - cgraph_mark_needed_node
-    - varpool_mark_needed_node
+             Each of the object files is streamed back and compiled
+             separately.  Now the function bodies becomes available
+             again.
 
-      When function or variable is referenced by some hidden way the call-graph
-      data structure must be updated accordingly by this function.
-      There should be little need to call this function and all the references
-      should be made explicit to cgraph code.  At present these functions are
-      used by C++ frontend to explicitly mark the keyed methods.
+        2) Virtual clone materialization
+           (cgraph_materialize_clone)
 
-    - analyze_expr callback
+           IP passes can produce copies of existing functoins (such
+           as versioned clones or inline clones) without actually
+           manipulating their bodies by creating virtual clones in
+           the callgraph. At this time the virtual clones are
+           turned into real functions
+        3) IP transformation
 
-      This function is responsible for lowering tree nodes not understood by
-      generic code into understandable ones or alternatively marking
-      callgraph and varpool nodes referenced by the as needed.
+           All IP passes transform function bodies based on earlier
+           decision of the IP propagation.
 
-      ??? On the tree-ssa genericizing should take place here and we will avoid
-      need for these hooks (replacing them by genericizing hook)
+        4) late small IP passes
 
-        Analyzing of all functions is deferred
-       to cgraph_finalize_compilation_unit and expansion into cgraph_optimize.
+           Simple IP passes working within single program partition.
 
-       In cgraph_finalize_compilation_unit the reachable functions are
-       analyzed.  During analysis the call-graph edges from reachable
-       functions are constructed and their destinations are marked as
-       reachable.  References to functions and variables are discovered too
-       and variables found to be needed output to the assembly file.  Via
-       mark_referenced call in assemble_variable functions referenced by
-       static variables are noticed too.
+        5) Expansion
+           (cgraph_expand_all_functions)
 
-       The intra-procedural information is produced and its existence
-       indicated by global_info_ready.  Once this flag is set it is impossible
-       to change function from !reachable to reachable and thus
-       assemble_variable no longer call mark_referenced.
+           At this stage functions that needs to be output into
+           assembler are identified and compiled in topological order
+        6) Output of variables and aliases
+           Now it is known what variable references was not optimized
+           out and thus all variables are output to the file.
 
-       Finally the call-graph is topologically sorted and all reachable functions
-       that has not been completely inlined or are not external are output.
+           Note that with -fno-toplevel-reorder passes 5 and 6
+           are combined together in cgraph_output_in_order.  
 
-       ??? It is possible that reference to function or variable is optimized
-       out.  We can not deal with this nicely because topological order is not
-       suitable for it.  For tree-ssa we may consider another pass doing
-       optimization and re-discovering reachable functions.
+   Finally there are functions to manipulate the callgraph from
+   backend.
+    - cgraph_add_new_function is used to add backend produced
+      functions introduced after the unit is finalized.
+      The functions are enqueue for later processing and inserted
+      into callgraph with cgraph_process_new_functions.
 
-       ??? Reorganize code so variables are output very last and only if they
-       really has been referenced by produced code, so we catch more cases
-       where reference has been optimized out.  */
+    - cgraph_function_versioning
 
+      produces a copy of function into new one (a version)
+      and apply simple transformations
+*/
 
 #include "config.h"
 #include "system.h"
@@ -124,8 +172,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "target.h"
 #include "cgraph.h"
 #include "diagnostic.h"
-#include "tree-pretty-print.h"
-#include "gimple-pretty-print.h"
 #include "timevar.h"
 #include "params.h"
 #include "fibheap.h"
@@ -136,6 +182,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-iterator.h"
 #include "tree-pass.h"
 #include "tree-dump.h"
+#include "gimple-pretty-print.h"
 #include "output.h"
 #include "coverage.h"
 #include "plugin.h"
@@ -154,7 +201,7 @@ static void cgraph_expand_all_functions (void);
 static void cgraph_mark_functions_to_output (void);
 static void cgraph_expand_function (struct cgraph_node *);
 static void cgraph_output_pending_asms (void);
-static void tree_rest_of_compilation (struct cgraph_node *);
+static void cgraph_analyze_function (struct cgraph_node *);
 
 FILE *cgraph_dump_file;
 
@@ -166,7 +213,7 @@ static GTY (()) tree vtable_entry_type;
    and differs from later logic removing unnecesary functions that can
    take into account results of analysis, whole program info etc.  */
 
-bool
+static bool
 cgraph_decide_is_function_needed (struct cgraph_node *node, tree decl)
 {
   /* If the user told us it is used, then it must be so.  */
@@ -470,8 +517,8 @@ cgraph_add_new_function (tree fndecl, bool lowered)
        if (!gimple_in_ssa_p (DECL_STRUCT_FUNCTION (fndecl)))
          execute_pass_list (pass_early_local_passes.pass.sub);
        bitmap_obstack_release (NULL);
-       tree_rest_of_compilation (node);
        pop_cfun ();
+       cgraph_expand_function (node);
        current_function_decl = NULL;
        break;
 
@@ -486,404 +533,6 @@ cgraph_add_new_function (tree fndecl, bool lowered)
     DECL_FUNCTION_PERSONALITY (fndecl) = lang_hooks.eh_personality ();
 }
 
-/* Return TRUE if NODE2 is equivalent to NODE or its clone.  */
-static bool
-clone_of_p (struct cgraph_node *node, struct cgraph_node *node2)
-{
-  node = cgraph_function_or_thunk_node (node, NULL);
-  node2 = cgraph_function_or_thunk_node (node2, NULL);
-  while (node != node2 && node2)
-    node2 = node2->clone_of;
-  return node2 != NULL;
-}
-
-/* Verify edge E count and frequency.  */
-
-static bool
-verify_edge_count_and_frequency (struct cgraph_edge *e)
-{
-  bool error_found = false;
-  if (e->count < 0)
-    {
-      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 (gimple_has_body_p (e->caller->symbol.decl)
-      && !e->caller->global.inlined_to
-      /* FIXME: Inline-analysis sets frequency to 0 when edge is optimized out.
-        Remove this once edges are actualy removed from the function at that time.  */
-      && (e->frequency
-         || (inline_edge_summary_vec
-             && ((VEC_length(inline_edge_summary_t, inline_edge_summary_vec)
-                 <= (unsigned) e->uid)
-                 || !inline_edge_summary (e)->predicate)))
-      && (e->frequency
-         != compute_call_stmt_bb_frequency (e->caller->symbol.decl,
-                                            gimple_bb (e->call_stmt))))
-    {
-      error ("caller edge frequency %i does not match BB frequency %i",
-            e->frequency,
-            compute_call_stmt_bb_frequency (e->caller->symbol.decl,
-                                            gimple_bb (e->call_stmt)));
-      error_found = true;
-    }
-  return error_found;
-}
-
-/* Switch to THIS_CFUN if needed and print STMT to stderr.  */
-static void
-cgraph_debug_gimple_stmt (struct function *this_cfun, gimple stmt)
-{
-  /* debug_gimple_stmt needs correct cfun */
-  if (cfun != this_cfun)
-    set_cfun (this_cfun);
-  debug_gimple_stmt (stmt);
-}
-
-/* Verify that call graph edge E corresponds to DECL from the associated
-   statement.  Return true if the verification should fail.  */
-
-static bool
-verify_edge_corresponds_to_fndecl (struct cgraph_edge *e, tree decl)
-{
-  struct cgraph_node *node;
-
-  if (!decl || e->callee->global.inlined_to)
-    return false;
-  node = cgraph_get_node (decl);
-
-  /* We do not know if a node from a different partition is an alias or what it
-     aliases and therefore cannot do the former_clone_of check reliably.  */
-  if (!node || node->symbol.in_other_partition)
-    return false;
-  node = cgraph_function_or_thunk_node (node, NULL);
-
-  if ((e->callee->former_clone_of != node->symbol.decl
-       && (!node->same_body_alias
-          || e->callee->former_clone_of != node->thunk.alias))
-      /* IPA-CP sometimes redirect edge to clone and then back to the former
-        function.  This ping-pong has to go, eventually.  */
-      && (node != cgraph_function_or_thunk_node (e->callee, NULL))
-      && !clone_of_p (node, e->callee)
-      /* If decl is a same body alias of some other decl, allow e->callee to be
-        a clone of a clone of that other decl too.  */
-      && (!node->same_body_alias
-         || !clone_of_p (cgraph_get_node (node->thunk.alias), e->callee)))
-    return true;
-  else
-    return false;
-}
-
-/* Verify cgraph nodes of given cgraph node.  */
-DEBUG_FUNCTION void
-verify_cgraph_node (struct cgraph_node *node)
-{
-  struct cgraph_edge *e;
-  struct function *this_cfun = DECL_STRUCT_FUNCTION (node->symbol.decl);
-  basic_block this_block;
-  gimple_stmt_iterator gsi;
-  bool error_found = false;
-
-  if (seen_error ())
-    return;
-
-  timevar_push (TV_CGRAPH_VERIFY);
-  error_found |= verify_symtab_base ((symtab_node) node);
-  for (e = node->callees; e; e = e->next_callee)
-    if (e->aux)
-      {
-       error ("aux field set for edge %s->%s",
-              identifier_to_locale (cgraph_node_name (e->caller)),
-              identifier_to_locale (cgraph_node_name (e->callee)));
-       error_found = true;
-      }
-  if (node->count < 0)
-    {
-      error ("execution count is negative");
-      error_found = true;
-    }
-  if (node->global.inlined_to && node->symbol.externally_visible)
-    {
-      error ("externally visible inline clone");
-      error_found = true;
-    }
-  if (node->global.inlined_to && node->symbol.address_taken)
-    {
-      error ("inline clone with address taken");
-      error_found = true;
-    }
-  if (node->global.inlined_to && node->symbol.force_output)
-    {
-      error ("inline clone is forced to output");
-      error_found = true;
-    }
-  for (e = node->indirect_calls; e; e = e->next_callee)
-    {
-      if (e->aux)
-       {
-         error ("aux field set for indirect edge from %s",
-                identifier_to_locale (cgraph_node_name (e->caller)));
-         error_found = true;
-       }
-      if (!e->indirect_unknown_callee
-         || !e->indirect_info)
-       {
-         error ("An indirect edge from %s is not marked as indirect or has "
-                "associated indirect_info, the corresponding statement is: ",
-                identifier_to_locale (cgraph_node_name (e->caller)));
-         cgraph_debug_gimple_stmt (this_cfun, e->call_stmt);
-         error_found = true;
-       }
-    }
-  for (e = node->callers; e; e = e->next_caller)
-    {
-      if (verify_edge_count_and_frequency (e))
-       error_found = true;
-      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;
-         }
-    }
-  for (e = node->indirect_calls; e; e = e->next_callee)
-    if (verify_edge_count_and_frequency (e))
-      error_found = true;
-  if (!node->callers && node->global.inlined_to)
-    {
-      error ("inlined_to pointer is set but no predecessors found");
-      error_found = true;
-    }
-  if (node->global.inlined_to == node)
-    {
-      error ("inlined_to pointer refers to itself");
-      error_found = true;
-    }
-
-  if (node->clone_of)
-    {
-      struct cgraph_node *n;
-      for (n = node->clone_of->clones; n; n = n->next_sibling_clone)
-        if (n == node)
-         break;
-      if (!n)
-       {
-         error ("node has wrong clone_of");
-         error_found = true;
-       }
-    }
-  if (node->clones)
-    {
-      struct cgraph_node *n;
-      for (n = node->clones; n; n = n->next_sibling_clone)
-        if (n->clone_of != node)
-         break;
-      if (n)
-       {
-         error ("node has wrong clone list");
-         error_found = true;
-       }
-    }
-  if ((node->prev_sibling_clone || node->next_sibling_clone) && !node->clone_of)
-    {
-       error ("node is in clone list but it is not clone");
-       error_found = true;
-    }
-  if (!node->prev_sibling_clone && node->clone_of && node->clone_of->clones != node)
-    {
-      error ("node has wrong prev_clone pointer");
-      error_found = true;
-    }
-  if (node->prev_sibling_clone && node->prev_sibling_clone->next_sibling_clone != node)
-    {
-      error ("double linked list of clones corrupted");
-      error_found = true;
-    }
-
-  if (node->analyzed && node->alias)
-    {
-      bool ref_found = false;
-      int i;
-      struct ipa_ref *ref;
-
-      if (node->callees)
-       {
-         error ("Alias has call edges");
-          error_found = true;
-       }
-      for (i = 0; ipa_ref_list_reference_iterate (&node->symbol.ref_list,
-                                                 i, ref); i++)
-       if (ref->use != IPA_REF_ALIAS)
-         {
-           error ("Alias has non-alias reference");
-           error_found = true;
-         }
-       else if (ref_found)
-         {
-           error ("Alias has more than one alias reference");
-           error_found = true;
-         }
-       else
-         ref_found = true;
-       if (!ref_found)
-         {
-           error ("Analyzed alias has no reference");
-           error_found = true;
-         }
-    }
-  if (node->analyzed && node->thunk.thunk_p)
-    {
-      if (!node->callees)
-       {
-         error ("No edge out of thunk node");
-          error_found = true;
-       }
-      else if (node->callees->next_callee)
-       {
-         error ("More than one edge out of thunk node");
-          error_found = true;
-       }
-      if (gimple_has_body_p (node->symbol.decl))
-        {
-         error ("Thunk is not supposed to have body");
-          error_found = true;
-        }
-    }
-  else if (node->analyzed && gimple_has_body_p (node->symbol.decl)
-           && !TREE_ASM_WRITTEN (node->symbol.decl)
-           && (!DECL_EXTERNAL (node->symbol.decl) || node->global.inlined_to)
-           && !flag_wpa)
-    {
-      if (this_cfun->cfg)
-       {
-         /* The nodes we're interested in are never shared, so walk
-            the tree ignoring duplicates.  */
-         struct pointer_set_t *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 (gsi = gsi_start_bb (this_block);
-                 !gsi_end_p (gsi);
-                 gsi_next (&gsi))
-             {
-               gimple stmt = gsi_stmt (gsi);
-               if (is_gimple_call (stmt))
-                 {
-                   struct cgraph_edge *e = cgraph_edge (node, stmt);
-                   tree decl = gimple_call_fndecl (stmt);
-                   if (e)
-                     {
-                       if (e->aux)
-                         {
-                           error ("shared call_stmt:");
-                           cgraph_debug_gimple_stmt (this_cfun, stmt);
-                           error_found = true;
-                         }
-                       if (!e->indirect_unknown_callee)
-                         {
-                           if (verify_edge_corresponds_to_fndecl (e, decl))
-                             {
-                               error ("edge points to wrong declaration:");
-                               debug_tree (e->callee->symbol.decl);
-                               fprintf (stderr," Instead of:");
-                               debug_tree (decl);
-                               error_found = true;
-                             }
-                         }
-                       else if (decl)
-                         {
-                           error ("an indirect edge with unknown callee "
-                                  "corresponding to a call_stmt with "
-                                  "a known declaration:");
-                           error_found = true;
-                           cgraph_debug_gimple_stmt (this_cfun, e->call_stmt);
-                         }
-                       e->aux = (void *)1;
-                     }
-                   else if (decl)
-                     {
-                       error ("missing callgraph edge for call stmt:");
-                       cgraph_debug_gimple_stmt (this_cfun, stmt);
-                       error_found = true;
-                     }
-                 }
-             }
-         pointer_set_destroy (visited_nodes);
-       }
-      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",
-                    identifier_to_locale (cgraph_node_name (e->caller)),
-                    identifier_to_locale (cgraph_node_name (e->callee)));
-             cgraph_debug_gimple_stmt (this_cfun, e->call_stmt);
-             error_found = true;
-           }
-         e->aux = 0;
-       }
-      for (e = node->indirect_calls; e; e = e->next_callee)
-       {
-         if (!e->aux)
-           {
-             error ("an indirect edge from %s has no corresponding call_stmt",
-                    identifier_to_locale (cgraph_node_name (e->caller)));
-             cgraph_debug_gimple_stmt (this_cfun, 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.  */
-DEBUG_FUNCTION void
-verify_cgraph (void)
-{
-  struct cgraph_node *node;
-
-  if (seen_error ())
-    return;
-
-  FOR_EACH_FUNCTION (node)
-    verify_cgraph_node (node);
-}
-
 /* Output all asm statements we have stored up to be output.  */
 
 static void
@@ -900,11 +549,13 @@ cgraph_output_pending_asms (void)
 }
 
 /* Analyze the function scheduled to be output.  */
-void
+static void
 cgraph_analyze_function (struct cgraph_node *node)
 {
   tree save = current_function_decl;
   tree decl = node->symbol.decl;
+  location_t saved_loc = input_location;
+  input_location = DECL_SOURCE_LOCATION (decl);
 
   if (node->alias && node->thunk.alias)
     {
@@ -917,6 +568,7 @@ cgraph_analyze_function (struct cgraph_node *node)
          {
            error ("function %q+D part of alias cycle", node->symbol.decl);
            node->alias = false;
+           input_location = saved_loc;
            return;
          }
       if (!VEC_length (ipa_ref_t, node->symbol.ref_list.references))
@@ -1002,6 +654,7 @@ cgraph_analyze_function (struct cgraph_node *node)
   node->analyzed = true;
 
   current_function_decl = save;
+  input_location = saved_loc;
 }
 
 /* C++ frontend produce same body aliases all over the place, even before PCH
@@ -1888,15 +1541,23 @@ assemble_thunks_and_aliases (struct cgraph_node *node)
       }
 }
 
-/* Perform IPA transforms and all further optimizations and compilation
-   for FNDECL.  */
+/* Expand function specified by NODE.  */
 
 static void
-tree_rest_of_compilation (struct cgraph_node *node)
+cgraph_expand_function (struct cgraph_node *node)
 {
-  tree fndecl = node->symbol.decl;
+  tree decl = node->symbol.decl;
   location_t saved_loc;
 
+  /* We ought to not compile any inline clones.  */
+  gcc_assert (!node->global.inlined_to);
+
+  announce_function (decl);
+  node->process = 0;
+  gcc_assert (node->lowered);
+
+  /* Generate RTL for the body of DECL.  */
+
   timevar_push (TV_REST_OF_COMPILATION);
 
   gcc_assert (cgraph_global_info_ready);
@@ -1905,10 +1566,10 @@ tree_rest_of_compilation (struct cgraph_node *node)
   bitmap_obstack_initialize (NULL);
 
   /* Initialize the RTL code for the function.  */
-  current_function_decl = fndecl;
+  current_function_decl = decl;
   saved_loc = input_location;
-  input_location = DECL_SOURCE_LOCATION (fndecl);
-  init_function_start (fndecl);
+  input_location = DECL_SOURCE_LOCATION (decl);
+  init_function_start (decl);
 
   gimple_register_cfg_hooks ();
 
@@ -1936,9 +1597,9 @@ tree_rest_of_compilation (struct cgraph_node *node)
   /* If requested, warn about function definitions where the function will
      return a value (usually of some struct or union type) which itself will
      take up a lot of stack space.  */
-  if (warn_larger_than && !DECL_EXTERNAL (fndecl) && TREE_TYPE (fndecl))
+  if (warn_larger_than && !DECL_EXTERNAL (decl) && TREE_TYPE (decl))
     {
-      tree ret_type = TREE_TYPE (TREE_TYPE (fndecl));
+      tree ret_type = TREE_TYPE (TREE_TYPE (decl));
 
       if (ret_type && TYPE_SIZE_UNIT (ret_type)
          && TREE_CODE (TYPE_SIZE_UNIT (ret_type)) == INTEGER_CST
@@ -1950,53 +1611,34 @@ tree_rest_of_compilation (struct cgraph_node *node)
 
          if (compare_tree_int (TYPE_SIZE_UNIT (ret_type), size_as_int) == 0)
            warning (OPT_Wlarger_than_, "size of return value of %q+D is %u bytes",
-                     fndecl, size_as_int);
+                     decl, size_as_int);
          else
            warning (OPT_Wlarger_than_, "size of return value of %q+D is larger than %wd bytes",
-                     fndecl, larger_than_size);
+                     decl, larger_than_size);
        }
     }
 
-  gimple_set_body (fndecl, NULL);
-  if (DECL_STRUCT_FUNCTION (fndecl) == 0
-      && !cgraph_get_node (fndecl)->origin)
+  gimple_set_body (decl, NULL);
+  if (DECL_STRUCT_FUNCTION (decl) == 0
+      && !cgraph_get_node (decl)->origin)
     {
       /* Stop pointing to the local nodes about to be freed.
         But DECL_INITIAL must remain nonzero so we know this
         was an actual function definition.
         For a nested function, this is done in c_pop_function_context.
         If rest_of_compilation set this to 0, leave it 0.  */
-      if (DECL_INITIAL (fndecl) != 0)
-       DECL_INITIAL (fndecl) = error_mark_node;
+      if (DECL_INITIAL (decl) != 0)
+       DECL_INITIAL (decl) = error_mark_node;
     }
 
   input_location = saved_loc;
 
   ggc_collect ();
   timevar_pop (TV_REST_OF_COMPILATION);
-}
-
-/* Expand function specified by NODE.  */
-
-static void
-cgraph_expand_function (struct cgraph_node *node)
-{
-  tree decl = node->symbol.decl;
-
-  /* We ought to not compile any inline clones.  */
-  gcc_assert (!node->global.inlined_to);
-
-  announce_function (decl);
-  node->process = 0;
-  gcc_assert (node->lowered);
-
-  /* Generate RTL for the body of DECL.  */
-  tree_rest_of_compilation (node);
 
   /* Make sure that BE didn't give up on compiling.  */
   gcc_assert (TREE_ASM_WRITTEN (decl));
   current_function_decl = NULL;
-  gcc_assert (!cgraph_preserve_function_body_p (node));
 
   /* It would make a lot more sense to output thunks before function body to get more
      forward and lest backwarding jumps.  This is however would need solving problem
@@ -2011,16 +1653,6 @@ cgraph_expand_function (struct cgraph_node *node)
   cgraph_node_remove_callees (node);
 }
 
-/* Return true when CALLER_DECL should be inlined into CALLEE_DECL.  */
-
-bool
-cgraph_inline_p (struct cgraph_edge *e, cgraph_inline_failed_t *reason)
-{
-  *reason = e->inline_failed;
-  return !e->inline_failed;
-}
-
-
 
 /* Expand all functions that must be output.
 
@@ -2166,20 +1798,6 @@ cgraph_output_in_order (void)
   free (nodes);
 }
 
-/* Return true when function body of DECL still needs to be kept around
-   for later re-use.  */
-bool
-cgraph_preserve_function_body_p (struct cgraph_node *node)
-{
-  gcc_assert (cgraph_global_info_ready);
-  gcc_assert (!node->alias && !node->thunk.thunk_p);
-
-  /* Look if there is any clone around.  */
-  if (node->clones)
-    return true;
-  return false;
-}
-
 static void
 ipa_passes (void)
 {
@@ -2277,7 +1895,7 @@ output_weakrefs (void)
                      : get_alias_symbol (vnode->symbol.decl));
 }
 
-
+/* Initialize callgraph dump file.  */
 
 void
 init_cgraph (void)
index c6cbd01..e07468a 100644 (file)
@@ -353,6 +353,19 @@ save_inline_function_body (struct cgraph_node *node)
   return first_clone;
 }
 
+/* Return true when function body of DECL still needs to be kept around
+   for later re-use.  */
+bool
+preserve_function_body_p (struct cgraph_node *node)
+{
+  gcc_assert (cgraph_global_info_ready);
+  gcc_assert (!node->alias && !node->thunk.thunk_p);
+
+  /* Look if there is any clone around.  */
+  if (node->clones)
+    return true;
+  return false;
+}
 
 /* Apply inline plan to function.  */
 
@@ -369,7 +382,7 @@ inline_transform (struct cgraph_node *node)
 
   /* We might need the body of this function so that we can expand
      it inline somewhere else.  */
-  if (cgraph_preserve_function_body_p (node))
+  if (preserve_function_body_p (node))
     save_inline_function_body (node);
 
   for (e = node->callees; e; e = e->next_callee)
index ed3230c..d8f479f 100644 (file)
@@ -69,7 +69,6 @@ extern void lhd_init_options (unsigned int,
 extern bool lhd_complain_wrong_lang_p (const struct cl_option *);
 extern bool lhd_handle_option (size_t, const char *, int, int, location_t,
                               const struct cl_option_handlers *);
-extern tree lhd_callgraph_analyze_expr (tree *, int *);
 
 
 /* Declarations for tree gimplification hooks.  */
@@ -132,12 +131,6 @@ extern void lhd_omp_firstprivatize_type_sizes (struct gimplify_omp_ctx *,
   LANG_HOOKS_TREE_INLINING_VAR_MOD_TYPE_P, \
 }
 
-#define LANG_HOOKS_CALLGRAPH_ANALYZE_EXPR lhd_callgraph_analyze_expr
-
-#define LANG_HOOKS_CALLGRAPH_INITIALIZER { \
-  LANG_HOOKS_CALLGRAPH_ANALYZE_EXPR \
-}
-
 /* Hooks for tree gimplification.  */
 #define LANG_HOOKS_GIMPLIFY_EXPR lhd_gimplify_expr
 
@@ -292,7 +285,6 @@ extern void lhd_end_section (void);
   LANG_HOOKS_COMMON_ATTRIBUTE_TABLE, \
   LANG_HOOKS_FORMAT_ATTRIBUTE_TABLE, \
   LANG_HOOKS_TREE_INLINING_INITIALIZER, \
-  LANG_HOOKS_CALLGRAPH_INITIALIZER, \
   LANG_HOOKS_TREE_DUMP_INITIALIZER, \
   LANG_HOOKS_DECLS, \
   LANG_HOOKS_FOR_TYPES_INITIALIZER, \
index 017e024..9d0e25e 100644 (file)
@@ -472,13 +472,6 @@ lhd_print_error_function (diagnostic_context *context, const char *file,
 }
 
 tree
-lhd_callgraph_analyze_expr (tree *tp ATTRIBUTE_UNUSED,
-                           int *walk_subtrees ATTRIBUTE_UNUSED)
-{
-  return NULL;
-}
-
-tree
 lhd_make_node (enum tree_code code)
 {
   return make_node (code);
index 1549722..76b1fe2 100644 (file)
@@ -43,13 +43,6 @@ struct lang_hooks_for_tree_inlining
   bool (*var_mod_type_p) (tree, tree);
 };
 
-struct lang_hooks_for_callgraph
-{
-  /* The node passed is a language-specific tree node.  If its contents
-     are relevant to use of other declarations, mark them.  */
-  tree (*analyze_expr) (tree *, int *);
-};
-
 /* The following hooks are used by tree-dump.c.  */
 
 struct lang_hooks_for_tree_dump
@@ -407,8 +400,6 @@ struct lang_hooks
 
   struct lang_hooks_for_tree_inlining tree_inlining;
 
-  struct lang_hooks_for_callgraph callgraph;
-
   struct lang_hooks_for_tree_dump tree_dump;
 
   struct lang_hooks_for_decls decls;
index d0710c0..2ba95f5 100644 (file)
@@ -3807,8 +3807,9 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
     fn = DECL_ABSTRACT_ORIGIN (fn);
 
   /* Don't try to inline functions that are not well-suited to inlining.  */
-  if (!cgraph_inline_p (cg_edge, &reason))
+  if (cg_edge->inline_failed)
     {
+      reason = cg_edge->inline_failed;
       /* If this call was originally indirect, we do not want to emit any
         inlining related warnings or sorry messages because there are no
         guarantees regarding those.  */
index 7837d45..4623d37 100644 (file)
@@ -5244,7 +5244,6 @@ free_lang_data (void)
 
   /* Reset some langhooks.  Do not reset types_compatible_p, it may
      still be used indirectly via the get_alias_set langhook.  */
-  lang_hooks.callgraph.analyze_expr = NULL;
   lang_hooks.dwarf_name = lhd_dwarf_name;
   lang_hooks.decl_printable_name = gimple_decl_printable_name;
   /* We do not want the default decl_assembler_name implementation,
index 7c8d1fd..75e546d 100644 (file)
@@ -37,17 +37,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-flow.h"
 #include "flags.h"
 
-/*  This file contains basic routines manipulating variable pool.
-
-    Varpool acts as interface in between the front-end and middle-end
-    and drives the decision process on what variables and when are
-    going to be compiled.
-
-    The varpool nodes are allocated lazily for declarations
-    either by frontend or at callgraph construction time.
-    All variables supposed to be output into final file needs to be
-    explicitly marked by frontend via VARPOOL_FINALIZE_DECL function.  */
-
 /* Return varpool node assigned to DECL.  Create new one when needed.  */
 struct varpool_node *
 varpool_node (tree decl)