tree-pass.h (pass_build_cgraph_edges): Declare.
authorJan Hubicka <jh@suse.cz>
Sat, 6 Jan 2007 17:58:40 +0000 (18:58 +0100)
committerJan Hubicka <hubicka@gcc.gnu.org>
Sat, 6 Jan 2007 17:58:40 +0000 (17:58 +0000)
* tree-pass.h (pass_build_cgraph_edges): Declare.
* cgraphunit.c (record_refernece): Move to cgraphbuild.c
(visited_nodes): Remove.
(cgraph_create_edges): Move to cgraphbuild.c; rename to
build_cgrpah_edges; make visited_nodes local.
(cgraph_process_new_functions): DO not call initialize_inline_failed.
(record_references_in_initializer): Move to cgraphbuild.c
(initialize_inline_failed, rebuild_cgraph_edges,
pass_rebuild_cgraph_edges): Move to cgraphbuild.c.
(verify_cgraph_node): Make visited_nodes local.
(cgraph_analyze_function): Do not call cgraph_create_edges and
initialize_inline_failed.
(cgraph_expand_function): Do not call cgraph_lower_function;
assert that function is already lowered.
* Makefile.in (cgraphbuild.o): New.
* passes.c (init_optimization_passes): Add pass_build_cgraph_edges
at the end of lowering passes.

From-SVN: r120527

gcc/ChangeLog
gcc/Makefile.in
gcc/cgraphbuild.c [new file with mode: 0644]
gcc/cgraphunit.c
gcc/passes.c
gcc/tree-pass.h

index 2623d7fecf95e1b24976966bc4ee6a402bb18633..74eb580e49ec8ef09c6b8d29b9f3a8fa8dbfe1a7 100644 (file)
@@ -1,3 +1,23 @@
+2007-01-06  Jan Hubicka  <jh@suse.cz>
+
+       * tree-pass.h (pass_build_cgraph_edges): Declare.
+       * cgraphunit.c (record_refernece): Move to cgraphbuild.c
+       (visited_nodes): Remove.
+       (cgraph_create_edges): Move to cgraphbuild.c; rename to
+       build_cgrpah_edges; make visited_nodes local.
+       (cgraph_process_new_functions): DO not call initialize_inline_failed.
+       (record_references_in_initializer): Move to cgraphbuild.c
+       (initialize_inline_failed, rebuild_cgraph_edges,
+       pass_rebuild_cgraph_edges): Move to cgraphbuild.c.
+       (verify_cgraph_node): Make visited_nodes local.
+       (cgraph_analyze_function): Do not call cgraph_create_edges and
+       initialize_inline_failed.
+       (cgraph_expand_function): Do not call cgraph_lower_function;
+       assert that function is already lowered.
+       * Makefile.in (cgraphbuild.o): New.
+       * passes.c (init_optimization_passes): Add pass_build_cgraph_edges
+       at the end of lowering passes.
+
 2007-01-06  Steven Bosscher  <steven@gcc.gnu.org>
 
        * ifcvt.c (cond_move_convert_if_block): New function, code
index 182b738c82fb2ec9bfffe6858e37798fe9fd3c19..1ec937a9d57013359d4cde9f84d6dc23cf1b5f70 100644 (file)
@@ -1014,7 +1014,7 @@ OBJS-common = \
 
 OBJS-md = $(out_object_file)
 OBJS-archive = $(EXTRA_OBJS) $(host_hook_obj) tree-inline.o               \
-  cgraph.o cgraphunit.o tree-nomudflap.o ipa.o ipa-inline.o                \
+  cgraph.o cgraphunit.o cgraphbuild.o tree-nomudflap.o ipa.o ipa-inline.o  \
   ipa-utils.o ipa-reference.o ipa-pure-const.o ipa-type-escape.o           \
   ipa-prop.o ipa-cp.o varpool.o
 
@@ -2269,6 +2269,9 @@ cgraphunit.o : cgraphunit.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
    $(TARGET_H) $(CGRAPH_H) intl.h pointer-set.h $(FUNCTION_H) $(TREE_GIMPLE_H) \
    $(TREE_FLOW_H) tree-pass.h $(C_COMMON_H) debug.h $(DIAGNOSTIC_H) \
    $(FIBHEAP_H) output.h $(PARAMS_H) $(RTL_H) $(TIMEVAR_H) ipa-prop.h 
+cgraphbuild.o : cgraphbuild.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
+   $(TREE_H) langhooks.h $(CGRAPH_H) intl.h pointer-set.h $(TREE_GIMPLE_H) \
+   $(TREE_FLOW_H) tree-pass.h 
 varpool.o : varpool.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
    $(TREE_H) langhooks.h $(TREE_INLINE_H) toplev.h $(FLAGS_H) $(GGC_H) \
    $(TARGET_H) $(CGRAPH_H) intl.h pointer-set.h $(FUNCTION_H) $(TREE_GIMPLE_H) \
diff --git a/gcc/cgraphbuild.c b/gcc/cgraphbuild.c
new file mode 100644 (file)
index 0000000..a2df564
--- /dev/null
@@ -0,0 +1,236 @@
+/* Callgraph construction.
+   Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+   Contributed by Jan Hubicka
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "tree-flow.h"
+#include "langhooks.h"
+#include "pointer-set.h"
+#include "cgraph.h"
+#include "intl.h"
+#include "tree-gimple.h"
+#include "tree-pass.h"
+
+/* Walk tree and record all calls and references to functions/variables.
+   Called via walk_tree: TP is pointer to tree to be examined.  */
+
+static tree
+record_reference (tree *tp, int *walk_subtrees, void *data)
+{
+  tree t = *tp;
+
+  switch (TREE_CODE (t))
+    {
+    case VAR_DECL:
+      if (TREE_STATIC (t) || DECL_EXTERNAL (t))
+       {
+         varpool_mark_needed_node (varpool_node (t));
+         if (lang_hooks.callgraph.analyze_expr)
+           return lang_hooks.callgraph.analyze_expr (tp, walk_subtrees,
+                                                     data);
+       }
+      break;
+
+    case FDESC_EXPR:
+    case ADDR_EXPR:
+      if (flag_unit_at_a_time)
+       {
+         /* Record dereferences to the functions.  This makes the
+            functions reachable unconditionally.  */
+         tree decl = TREE_OPERAND (*tp, 0);
+         if (TREE_CODE (decl) == FUNCTION_DECL)
+           cgraph_mark_needed_node (cgraph_node (decl));
+       }
+      break;
+
+    default:
+      /* Save some cycles by not walking types and declaration as we
+        won't find anything useful there anyway.  */
+      if (IS_TYPE_OR_DECL_P (*tp))
+       {
+         *walk_subtrees = 0;
+         break;
+       }
+
+      if ((unsigned int) TREE_CODE (t) >= LAST_AND_UNUSED_TREE_CODE)
+       return lang_hooks.callgraph.analyze_expr (tp, walk_subtrees, data);
+      break;
+    }
+
+  return NULL_TREE;
+}
+
+/* Give initial reasons why inlining would fail on all calls from
+   NODE.  Those get 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");
+    }
+}
+
+/* Create cgraph edges for function calls.
+   Also look for functions and variables having addresses taken.  */
+
+static unsigned int
+build_cgraph_edges (void)
+{
+  basic_block bb;
+  struct cgraph_node *node = cgraph_node (current_function_decl);
+  struct pointer_set_t *visited_nodes = pointer_set_create ();
+  block_stmt_iterator bsi;
+  tree step;
+
+  /* Create the callgraph edges and record the nodes referenced by the function.
+     body.  */
+  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);
+           walk_tree (&TREE_OPERAND (call, 1),
+                      record_reference, node, visited_nodes);
+           if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT)
+             walk_tree (&GIMPLE_STMT_OPERAND (stmt, 0),
+                        record_reference, node, visited_nodes);
+         }
+       else
+         walk_tree (bsi_stmt_ptr (bsi), record_reference, node, visited_nodes);
+      }
+
+  /* Look for initializers of constant variables and private statics.  */
+  for (step = cfun->unexpanded_var_list;
+       step;
+       step = TREE_CHAIN (step))
+    {
+      tree decl = TREE_VALUE (step);
+      if (TREE_CODE (decl) == VAR_DECL
+         && (TREE_STATIC (decl) && !DECL_EXTERNAL (decl))
+         && flag_unit_at_a_time)
+       varpool_finalize_decl (decl);
+      else if (TREE_CODE (decl) == VAR_DECL && DECL_INITIAL (decl))
+       walk_tree (&DECL_INITIAL (decl), record_reference, node, visited_nodes);
+    }
+
+  pointer_set_destroy (visited_nodes);
+  initialize_inline_failed (node);
+  return 0;
+}
+
+struct tree_opt_pass pass_build_cgraph_edges =
+{
+  NULL,                                        /* name */
+  NULL,                                        /* gate */
+  build_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 */
+};
+
+/* Record references to functions and other variables present in the
+   initial value of DECL, a variable.  */
+
+void
+record_references_in_initializer (tree decl)
+{
+  struct pointer_set_t *visited_nodes = pointer_set_create ();
+  walk_tree (&DECL_INITIAL (decl), record_reference, NULL, visited_nodes);
+  pointer_set_destroy (visited_nodes);
+}
+
+/* Rebuild cgraph edges for current function node.  This needs to be run after
+   passes that don't update the cgraph.  */
+
+static unsigned int
+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);
+  return 0;
+}
+
+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 */
+};
index b1c5c8b461f18dd9120091d93f671842895516cc..e6f9db4a22c0804c1d49602464d99ae4f53a89de 100644 (file)
@@ -164,16 +164,8 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 static void cgraph_expand_all_functions (void);
 static void cgraph_mark_functions_to_output (void);
 static void cgraph_expand_function (struct cgraph_node *);
-static tree record_reference (tree *, int *, void *);
 static void cgraph_output_pending_asms (void);
 static void cgraph_increase_alignment (void);
-static void initialize_inline_failed (struct cgraph_node *);
-
-/* Records tree nodes seen in record_reference.  Simply using
-   walk_tree_without_duplicates doesn't guarantee each node is visited
-   once because it gets a new htab upon each recursive call from
-   record_reference itself.  */
-static struct pointer_set_t *visited_nodes;
 
 static FILE *cgraph_dump_file;
 
@@ -311,7 +303,6 @@ cgraph_process_new_functions (void)
          /* Inlining characteristics are maintained by the
             cgraph_mark_inline.  */
          node->global.insns = node->local.self_insns;
-         initialize_inline_failed (node);
          if (flag_really_no_inline && !node->local.disregard_inline_limits)
             node->local.inlinable = 0;
          if ((cgraph_state == CGRAPH_STATE_IPA_SSA
@@ -495,189 +486,6 @@ cgraph_finalize_function (tree decl, bool nested)
     do_warn_unused_parameter (decl);
 }
 
-/* Walk tree and record all calls.  Called via walk_tree.  */
-static tree
-record_reference (tree *tp, int *walk_subtrees, void *data)
-{
-  tree t = *tp;
-
-  switch (TREE_CODE (t))
-    {
-    case VAR_DECL:
-      /* ??? Really, we should mark this decl as *potentially* referenced
-        by this function and re-examine whether the decl is actually used
-        after rtl has been generated.  */
-      if (TREE_STATIC (t) || DECL_EXTERNAL (t))
-       {
-         varpool_mark_needed_node (varpool_node (t));
-         if (lang_hooks.callgraph.analyze_expr)
-           return lang_hooks.callgraph.analyze_expr (tp, walk_subtrees,
-                                                     data);
-       }
-      break;
-
-    case FDESC_EXPR:
-    case ADDR_EXPR:
-      if (flag_unit_at_a_time)
-       {
-         /* Record dereferences to the functions.  This makes the
-            functions reachable unconditionally.  */
-         tree decl = TREE_OPERAND (*tp, 0);
-         if (TREE_CODE (decl) == FUNCTION_DECL)
-           cgraph_mark_needed_node (cgraph_node (decl));
-       }
-      break;
-
-    default:
-      /* Save some cycles by not walking types and declaration as we
-        won't find anything useful there anyway.  */
-      if (IS_TYPE_OR_DECL_P (*tp))
-       {
-         *walk_subtrees = 0;
-         break;
-       }
-
-      if ((unsigned int) TREE_CODE (t) >= LAST_AND_UNUSED_TREE_CODE)
-       return lang_hooks.callgraph.analyze_expr (tp, walk_subtrees, data);
-      break;
-    }
-
-  return NULL;
-}
-
-/* Create cgraph edges for function calls inside BODY from NODE.  */
-
-static void
-cgraph_create_edges (struct cgraph_node *node, tree body)
-{
-  basic_block bb;
-
-  struct function *this_cfun = DECL_STRUCT_FUNCTION (body);
-  block_stmt_iterator bsi;
-  tree step;
-  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 (bb, this_cfun)
-    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);
-           walk_tree (&TREE_OPERAND (call, 1),
-                      record_reference, node, visited_nodes);
-           if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT)
-             walk_tree (&GIMPLE_STMT_OPERAND (stmt, 0),
-                        record_reference, node, visited_nodes);
-         }
-       else
-         walk_tree (bsi_stmt_ptr (bsi), record_reference, node, visited_nodes);
-      }
-
-  /* Look for initializers of constant variables and private statics.  */
-  for (step = DECL_STRUCT_FUNCTION (body)->unexpanded_var_list;
-       step;
-       step = TREE_CHAIN (step))
-    {
-      tree decl = TREE_VALUE (step);
-      if (TREE_CODE (decl) == VAR_DECL
-         && (TREE_STATIC (decl) && !DECL_EXTERNAL (decl))
-         && flag_unit_at_a_time)
-       varpool_finalize_decl (decl);
-      else if (TREE_CODE (decl) == VAR_DECL && DECL_INITIAL (decl))
-       walk_tree (&DECL_INITIAL (decl), record_reference, node, visited_nodes);
-    }
-
-  pointer_set_destroy (visited_nodes);
-  visited_nodes = NULL;
-}
-
-void
-record_references_in_initializer (tree decl)
-{
-  visited_nodes = pointer_set_create ();
-  walk_tree (&DECL_INITIAL (decl), record_reference, NULL, visited_nodes);
-  pointer_set_destroy (visited_nodes);
-  visited_nodes = NULL;
-}
-
-
-/* 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 unsigned int
-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);
-  return 0;
-}
-
-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)
@@ -763,7 +571,7 @@ verify_cgraph_node (struct cgraph_node *node)
        {
          /* The nodes we're interested in are never shared, so walk
             the tree ignoring duplicates.  */
-         visited_nodes = pointer_set_create ();
+         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)
@@ -802,7 +610,6 @@ verify_cgraph_node (struct cgraph_node *node)
                  }
              }
          pointer_set_destroy (visited_nodes);
-         visited_nodes = NULL;
        }
       else
        /* No CFG available?!  */
@@ -867,9 +674,6 @@ cgraph_analyze_function (struct cgraph_node *node)
   push_cfun (DECL_STRUCT_FUNCTION (decl));
   cgraph_lower_function (node);
 
-  /* First kill forward declaration so reverse inlining works properly.  */
-  cgraph_create_edges (node, decl);
-
   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;
@@ -879,7 +683,6 @@ cgraph_analyze_function (struct cgraph_node *node)
   if (node->local.inlinable)
     node->local.disregard_inline_limits
       = lang_hooks.tree_inlining.disregard_inline_limits (decl);
-  initialize_inline_failed (node);
   if (flag_really_no_inline && !node->local.disregard_inline_limits)
     node->local.inlinable = 0;
   /* Inlining characteristics are maintained by the cgraph_mark_inline.  */
@@ -1167,7 +970,8 @@ cgraph_expand_function (struct cgraph_node *node)
   if (flag_unit_at_a_time)
     announce_function (decl);
 
-  cgraph_lower_function (node);
+  gcc_assert (node->lowered);
+  /*cgraph_lower_function (node);*/
 
   /* Generate RTL for the body of DECL.  */
   lang_hooks.callgraph.expand_function (decl);
index d40f84e26882fc2a382b66042a7564a8b43d8587..91c9f1eff2a1400923b3bb074eb721f4d0ec0535 100644 (file)
@@ -461,6 +461,7 @@ init_optimization_passes (void)
   NEXT_PASS (pass_lower_complex_O0);
   NEXT_PASS (pass_lower_vector);
   NEXT_PASS (pass_warn_function_return);
+  NEXT_PASS (pass_build_cgraph_edges);
   *p = NULL;
 
   p = &pass_early_local_passes.sub;
index 01a0c7dfcff8557e08412e43abc4b58130593b81..0cec9d4f993c71b910a4e4955c98a29035a310ad 100644 (file)
@@ -303,6 +303,7 @@ extern struct tree_opt_pass pass_uncprop;
 extern struct tree_opt_pass pass_return_slot;
 extern struct tree_opt_pass pass_reassoc;
 extern struct tree_opt_pass pass_rebuild_cgraph_edges;
+extern struct tree_opt_pass pass_build_cgraph_edges;
 extern struct tree_opt_pass pass_reset_cc_flags;
 
 /* IPA Passes */