* cgraph.c (cgraph_release_function_body): Update use of
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 16 Nov 2009 13:26:40 +0000 (13:26 +0000)
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 16 Nov 2009 13:26:40 +0000 (13:26 +0000)
ipa_transforms_to_apply.
(cgraph_remove_node): Remove ipa_transforms_to_apply.
* cgraph.h (struct cgraph_node): Add ipa_transforms_to_apply.
* cgraphunit.c (save_inline_function_body): Clear ipa_transforms for
copied body.
(cgraph_materialize_clone): Remove original if dead.
* lto-streamer-in.c (lto_read_body): Remove FIXME and
ipa_transforms_to_apply hack.
* function.h (struct function): Add ipa_transforms_to_apply.
* ipa.c (cgraph_remove_unreachable_nodes): Handle dead clone originals.
* tree-inline.c (copy_bb): Update sanity check.
(initialize_cfun): Do not copy ipa_transforms_to_apply.
(expand_call_inline): remove dead clone originals.
(tree_function_versioning): Merge transformation queues.
* passes.c (add_ipa_transform_pass): Remove.
(execute_one_ipa_transform_pass): Update ipa_transforms_to_apply
tracking.
(execute_all_ipa_transforms): Update.
(execute_one_pass): Update.

* lto.c (read_cgraph_and_symbols): Set also ipa_transforms_to_apply.

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

gcc/ChangeLog
gcc/cgraph.c
gcc/cgraph.h
gcc/cgraphunit.c
gcc/function.h
gcc/ipa.c
gcc/lto-streamer-in.c
gcc/lto/ChangeLog
gcc/lto/lto.c
gcc/passes.c
gcc/tree-inline.c

index 0ee4395..9796fa0 100644 (file)
@@ -1,3 +1,26 @@
+2009-11-14  Jan Hubicka  <jh@suse.cz>
+
+       * cgraph.c (cgraph_release_function_body): Update use of
+       ipa_transforms_to_apply.
+       (cgraph_remove_node): Remove ipa_transforms_to_apply.
+       * cgraph.h (struct cgraph_node): Add ipa_transforms_to_apply.
+       * cgraphunit.c (save_inline_function_body): Clear ipa_transforms for
+       copied body.
+       (cgraph_materialize_clone): Remove original if dead.
+       * lto-streamer-in.c (lto_read_body): Remove FIXME and
+       ipa_transforms_to_apply hack.
+       * function.h (struct function): Add ipa_transforms_to_apply.
+       * ipa.c (cgraph_remove_unreachable_nodes): Handle dead clone originals.
+       * tree-inline.c (copy_bb): Update sanity check.
+       (initialize_cfun): Do not copy ipa_transforms_to_apply.
+       (expand_call_inline): remove dead clone originals.
+       (tree_function_versioning): Merge transformation queues.
+       * passes.c (add_ipa_transform_pass): Remove.
+       (execute_one_ipa_transform_pass): Update ipa_transforms_to_apply
+       tracking.
+       (execute_all_ipa_transforms): Update.
+       (execute_one_pass): Update.
+
 2009-11-14  Andy Hutchinson   <hutchinsonandy@gcc.gnu.org>
 
        PR target/21078, 21080
index 167e8a8..840cf29 100644 (file)
@@ -1132,7 +1132,7 @@ cgraph_release_function_body (struct cgraph_node *node)
       pop_cfun();
       gimple_set_body (node->decl, NULL);
       VEC_free (ipa_opt_pass, heap,
-               DECL_STRUCT_FUNCTION (node->decl)->ipa_transforms_to_apply);
+               node->ipa_transforms_to_apply);
       /* Struct function hangs a lot of data that would leak if we didn't
          removed all pointers to it.   */
       ggc_free (DECL_STRUCT_FUNCTION (node->decl));
@@ -1159,6 +1159,8 @@ cgraph_remove_node (struct cgraph_node *node)
   cgraph_call_node_removal_hooks (node);
   cgraph_node_remove_callers (node);
   cgraph_node_remove_callees (node);
+  VEC_free (ipa_opt_pass, heap,
+            node->ipa_transforms_to_apply);
 
   /* Incremental inlining access removed nodes stored in the postorder list.
      */
index 46fee67..33eb821 100644 (file)
@@ -190,6 +190,11 @@ struct GTY((chain_next ("%h.next"), chain_prev ("%h.previous"))) cgraph_node {
 
   PTR GTY ((skip)) aux;
 
+  /* Interprocedural passes scheduled to have their transform functions
+     applied next time we execute local pass on them.  We maintain it
+     per-function in order to allow IPA passes to introduce new functions.  */
+  VEC(ipa_opt_pass,heap) * GTY((skip)) ipa_transforms_to_apply;
+
   struct cgraph_local_info local;
   struct cgraph_global_info global;
   struct cgraph_rtl_info rtl;
@@ -206,16 +211,24 @@ struct GTY((chain_next ("%h.next"), chain_prev ("%h.previous"))) cgraph_node {
      number of cfg nodes with -fprofile-generate and -fprofile-use */
   int pid;
 
-  /* Set when function must be output - it is externally visible
-     or its address is taken.  */
+  /* Set when function must be output for some reason.  The primary
+     use of this flag is to mark functions needed to be output for
+     non-standard reason.  Functions that are externally visible
+     or reachable from functions needed to be output are marked
+     by specialized flags.  */
   unsigned needed : 1;
-  /* Set when function has address taken.  */
+  /* Set when function has address taken.
+     In current implementation it imply needed flag. */
   unsigned address_taken : 1;
   /* Set when decl is an abstract function pointed to by the
      ABSTRACT_DECL_ORIGIN of a reachable function.  */
   unsigned abstract_and_needed : 1;
   /* Set when function is reachable by call from other function
-     that is either reachable or needed.  */
+     that is either reachable or needed.  
+     This flag is computed at original cgraph construction and then
+     updated in cgraph_remove_unreachable_nodes.  Note that after
+     cgraph_remove_unreachable_nodes cgraph still can contain unreachable
+     nodes when they are needed for virtual clone instantiation.  */
   unsigned reachable : 1;
   /* Set once the function is lowered (i.e. its CFG is built).  */
   unsigned lowered : 1;
index 377e435..1c13f95 100644 (file)
@@ -1777,8 +1777,8 @@ save_inline_function_body (struct cgraph_node *node)
   TREE_PUBLIC (first_clone->decl) = 0;
   DECL_COMDAT (first_clone->decl) = 0;
   VEC_free (ipa_opt_pass, heap,
-            DECL_STRUCT_FUNCTION (first_clone->decl)->ipa_transforms_to_apply);
-  DECL_STRUCT_FUNCTION (first_clone->decl)->ipa_transforms_to_apply = NULL;
+            first_clone->ipa_transforms_to_apply);
+  first_clone->ipa_transforms_to_apply = NULL;
 
 #ifdef ENABLE_CHECKING
   verify_cgraph_node (first_clone);
@@ -1810,6 +1810,8 @@ cgraph_materialize_clone (struct cgraph_node *node)
     node->clone_of->clones = node->next_sibling_clone;
   node->next_sibling_clone = NULL;
   node->prev_sibling_clone = NULL;
+  if (!node->clone_of->analyzed && !node->clone_of->clones)
+    cgraph_remove_node (node->clone_of);
   node->clone_of = NULL;
   bitmap_obstack_release (NULL);
 }
index 4825d16..ad203ba 100644 (file)
@@ -522,11 +522,6 @@ struct GTY(()) function {
   unsigned int curr_properties;
   unsigned int last_verified;
 
-  /* Interprocedural passes scheduled to have their transform functions
-     applied next time we execute local pass on them.  We maintain it
-     per-function in order to allow IPA passes to introduce new functions.  */
-  VEC(ipa_opt_pass,heap) * GTY((skip)) ipa_transforms_to_apply;
-
   /* Non-null if the function does something that would prevent it from
      being copied; this applies to both versioning and inlining.  Set to
      a string describing the reason for failure.  */
index 6234e66..4d52ed4 100644 (file)
--- a/gcc/ipa.c
+++ b/gcc/ipa.c
@@ -121,6 +121,7 @@ bool
 cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
 {
   struct cgraph_node *first = (struct cgraph_node *) (void *) 1;
+  struct cgraph_node *processed = (struct cgraph_node *) (void *) 2;
   struct cgraph_node *node, *next;
   bool changed = false;
 
@@ -142,9 +143,13 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
         gcc_assert (!node->global.inlined_to);
        node->aux = first;
        first = node;
+       node->reachable = true;
       }
     else
-      gcc_assert (!node->aux);
+      {
+        gcc_assert (!node->aux);
+       node->reachable = false;
+      }
 
   /* Perform reachability analysis.  As a special case do not consider
      extern inline functions not inlined as live because we won't output
@@ -154,17 +159,26 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
       struct cgraph_edge *e;
       node = first;
       first = (struct cgraph_node *) first->aux;
-
-      for (e = node->callees; e; e = e->next_callee)
-       if (!e->callee->aux
-           && node->analyzed
-           && (!e->inline_failed || !e->callee->analyzed
-               || (!DECL_EXTERNAL (e->callee->decl))
-                || before_inlining_p))
-         {
-           e->callee->aux = first;
-           first = e->callee;
-         }
+      node->aux = processed;
+
+      if (node->reachable)
+        for (e = node->callees; e; e = e->next_callee)
+         if (!e->callee->reachable
+             && node->analyzed
+             && (!e->inline_failed || !e->callee->analyzed
+                 || (!DECL_EXTERNAL (e->callee->decl))
+                  || before_inlining_p))
+           {
+             bool prev_reachable = e->callee->reachable;
+             e->callee->reachable |= node->reachable;
+             if (!e->callee->aux
+                 || (e->callee->aux == processed
+                     && prev_reachable != e->callee->reachable))
+               {
+                 e->callee->aux = first;
+                 first = e->callee;
+               }
+           }
       while (node->clone_of && !node->clone_of->aux && !gimple_has_body_p (node->decl))
         {
          node = node->clone_of;
@@ -184,13 +198,18 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
   for (node = cgraph_nodes; node; node = next)
     {
       next = node->next;
+      if (node->aux && !node->reachable)
+        {
+         cgraph_node_remove_callees (node);
+         node->analyzed = false;
+         node->local.inlinable = false;
+       }
       if (!node->aux)
        {
           node->global.inlined_to = NULL;
          if (file)
            fprintf (file, " %s", cgraph_node_name (node));
-         if (!node->analyzed || !DECL_EXTERNAL (node->decl)
-             || before_inlining_p)
+         if (!node->analyzed || !DECL_EXTERNAL (node->decl) || before_inlining_p)
            cgraph_remove_node (node);
          else
            {
@@ -219,6 +238,12 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
                      node->analyzed = false;
                      node->local.inlinable = false;
                    }
+                 if (node->prev_sibling_clone)
+                   node->prev_sibling_clone->next_sibling_clone = node->next_sibling_clone;
+                 else if (node->clone_of)
+                   node->clone_of->clones = node->next_sibling_clone;
+                 if (node->next_sibling_clone)
+                   node->next_sibling_clone->prev_sibling_clone = node->prev_sibling_clone;
                }
              else
                cgraph_remove_node (node);
index 59784a4..dcc92fd 100644 (file)
@@ -1476,15 +1476,6 @@ lto_read_body (struct lto_file_decl_data *file_data, tree fn_decl,
       /* Restore decl state */
       file_data->current_decl_state = file_data->global_decl_state;
 
-      /* FIXME: ipa_transforms_to_apply holds list of passes that have optimization
-         summaries computed and needs to apply changes.  At the moment WHOPR only
-         supports inlining, so we can push it here by hand.  In future we need to stream
-         this field into ltrans compilation.  This will also need to move the field
-        from struct function into cgraph node where it belongs.  */
-      if (flag_ltrans && !cgraph_node (fn_decl)->global.inlined_to)
-        VEC_safe_push (ipa_opt_pass, heap,
-                       cfun->ipa_transforms_to_apply,
-                       (ipa_opt_pass)&pass_ipa_inline);
       pop_cfun ();
     }
   else 
index 6cb9ff4..9633199 100644 (file)
@@ -1,3 +1,7 @@
+2009-11-14  Jan Hubicka  <jh@suse.cz>
+
+       * lto.c (read_cgraph_and_symbols): Set also ipa_transforms_to_apply.
+
 2009-11-12  Rafael Avila de Espindola  <espindola@google.com>
 
        * lang.opt (fresolution): Renamed from resolution.
index 323f6b3..40f3c30 100644 (file)
@@ -1826,9 +1826,19 @@ read_cgraph_and_symbols (unsigned nfiles, const char **fnames)
      phase. */
   if (flag_ltrans)
     for (node = cgraph_nodes; node; node = node->next)
-      if (!node->global.inlined_to
-         && cgraph_decide_is_function_needed (node, node->decl))
-        cgraph_mark_needed_node (node);
+      {
+        if (!node->global.inlined_to
+           && cgraph_decide_is_function_needed (node, node->decl))
+          cgraph_mark_needed_node (node);
+       /* FIXME: ipa_transforms_to_apply holds list of passes that have optimization
+          summaries computed and needs to apply changes.  At the moment WHOPR only
+          supports inlining, so we can push it here by hand.  In future we need to stream
+          this field into ltrans compilation.  */
+       if (node->analyzed)
+         VEC_safe_push (ipa_opt_pass, heap,
+                        node->ipa_transforms_to_apply,
+                        (ipa_opt_pass)&pass_ipa_inline);
+      }
 
   timevar_push (TV_IPA_LTO_DECL_IO);
 
index fb0dd83..e92d086 100644 (file)
@@ -1376,15 +1376,6 @@ update_properties_after_pass (void *data)
                           & ~pass->properties_destroyed;
 }
 
-/* Schedule IPA transform pass DATA for CFUN.  */
-
-static void
-add_ipa_transform_pass (void *data)
-{
-  struct ipa_opt_pass_d *ipa_pass = (struct ipa_opt_pass_d *) data;
-  VEC_safe_push (ipa_opt_pass, heap, cfun->ipa_transforms_to_apply, ipa_pass);
-}
-
 /* Execute summary generation for all of the passes in IPA_PASS.  */
 
 void
@@ -1464,19 +1455,22 @@ execute_one_ipa_transform_pass (struct cgraph_node *node,
 void
 execute_all_ipa_transforms (void)
 {
-  if (cfun && cfun->ipa_transforms_to_apply)
+  struct cgraph_node *node;
+  if (!cfun)
+    return;
+  node = cgraph_node (current_function_decl);
+  if (node->ipa_transforms_to_apply)
     {
       unsigned int i;
-      struct cgraph_node *node = cgraph_node (current_function_decl);
 
-      for (i = 0; i < VEC_length (ipa_opt_pass, cfun->ipa_transforms_to_apply);
+      for (i = 0; i < VEC_length (ipa_opt_pass, node->ipa_transforms_to_apply);
           i++)
        execute_one_ipa_transform_pass (node,
                                        VEC_index (ipa_opt_pass,
-                                                  cfun->ipa_transforms_to_apply,
+                                                  node->ipa_transforms_to_apply,
                                                   i));
-      VEC_free (ipa_opt_pass, heap, cfun->ipa_transforms_to_apply);
-      cfun->ipa_transforms_to_apply = NULL;
+      VEC_free (ipa_opt_pass, heap, node->ipa_transforms_to_apply);
+      node->ipa_transforms_to_apply = NULL;
     }
 }
 
@@ -1551,7 +1545,13 @@ execute_one_pass (struct opt_pass *pass)
   execute_todo (todo_after | pass->todo_flags_finish);
   verify_interpass_invariants ();
   if (pass->type == IPA_PASS)
-    do_per_function (add_ipa_transform_pass, pass);
+    {
+      struct cgraph_node *node;
+      for (node = cgraph_nodes; node; node = node->next)
+        if (node->analyzed)
+          VEC_safe_push (ipa_opt_pass, heap, node->ipa_transforms_to_apply,
+                        (struct ipa_opt_pass_d *)pass);
+    }
 
   if (!current_function_decl)
     cgraph_process_new_functions ();
index f0ed4ba..629ccfb 100644 (file)
@@ -1665,10 +1665,12 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
 
                  /* We have missing edge in the callgraph.  This can happen
                     when previous inlining turned an indirect call into a
-                    direct call by constant propagating arguments.  In all
+                    direct call by constant propagating arguments or we are
+                    producing dead clone (for further clonning).  In all
                     other cases we hit a bug (incorrect node sharing is the
                     most common reason for missing edges).  */
-                 gcc_assert (dest->needed || !dest->analyzed);
+                 gcc_assert (dest->needed || !dest->analyzed
+                             || !id->src_node->analyzed);
                  if (id->transform_call_graph_edges == CB_CGE_MOVE_CLONES)
                    cgraph_create_edge_including_clones
                      (id->dst_node, dest, stmt, bb->count,
@@ -1983,9 +1985,6 @@ initialize_cfun (tree new_fndecl, tree callee_fndecl, gcov_type count,
   cfun->function_end_locus = src_cfun->function_end_locus;
   cfun->curr_properties = src_cfun->curr_properties;
   cfun->last_verified = src_cfun->last_verified;
-  if (src_cfun->ipa_transforms_to_apply)
-    cfun->ipa_transforms_to_apply = VEC_copy (ipa_opt_pass, heap,
-                                             src_cfun->ipa_transforms_to_apply);
   cfun->va_list_gpr_size = src_cfun->va_list_gpr_size;
   cfun->va_list_fpr_size = src_cfun->va_list_fpr_size;
   cfun->function_frequency = src_cfun->function_frequency;
@@ -3822,6 +3821,10 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
   (*debug_hooks->outlining_inline_function) (cg_edge->callee->decl);
 
   /* Update callgraph if needed.  */
+  if (cg_edge->callee->clone_of
+      && !cg_edge->callee->clone_of->next_sibling_clone
+      && !cg_edge->callee->analyzed)
+    cgraph_remove_node (cg_edge->callee);
   cgraph_remove_node (cg_edge->callee);
 
   id->block = NULL_TREE;
@@ -4848,6 +4851,19 @@ tree_function_versioning (tree old_decl, tree new_decl,
   id.src_node = old_version_node;
   id.dst_node = new_version_node;
   id.src_cfun = DECL_STRUCT_FUNCTION (old_decl);
+  if (id.src_node->ipa_transforms_to_apply)
+    {
+      VEC(ipa_opt_pass,heap) * old_transforms_to_apply = id.dst_node->ipa_transforms_to_apply;
+      unsigned int i;
+
+      id.dst_node->ipa_transforms_to_apply = VEC_copy (ipa_opt_pass, heap,
+                                                      id.src_node->ipa_transforms_to_apply);
+      for (i = 0; i < VEC_length (ipa_opt_pass, old_transforms_to_apply); i++)
+        VEC_safe_push (ipa_opt_pass, heap, id.dst_node->ipa_transforms_to_apply,
+                      VEC_index (ipa_opt_pass,
+                                 old_transforms_to_apply,
+                                 i));
+    }
   
   id.copy_decl = copy_decl_no_change;
   id.transform_call_graph_edges