OSDN Git Service

* tree-pass.h (opt_pass): Add IPA_PASS.
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 1 May 2008 16:08:15 +0000 (16:08 +0000)
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 1 May 2008 16:08:15 +0000 (16:08 +0000)
(varpool_node, cgraph_node): Forward declare.
(ipa_opt_pass): Define.
(pass_ipa_inline): Turn into ipa_opt_pass.
(pass_apply_inline): Remove.
* ipa-inline.c (pass_ipa_inline): Turn into ipa_opt_pass.
(apply_inline): Turn into ....
(inline_transform): ... this one.
(inline_generate_summary): New function.
(pass_apply_inline): Remove.
* function.h (ipa_opt_pass): Forward declare structure; typedef;
vector.
(struct function): Add ipa_transforms_to_apply.
* passes.c (register_one_dump_file): Work on IPA_PASS.
(init_optimization_passes): Remove pass_inline_parameters and
pass_apply_inline.
(pass_init_dump_file, pass_fini_dump_file): Break out from ....
(execute_one_pass) ... here; apply transforms when possible.
(add_ipa_transform_pass, execute_ipa_summary_asses,
execute_one_ipa_transform_pass): New.
(execute_ipa_pass_list): Update for IPA_PASS type.

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

gcc/ChangeLog
gcc/function.h
gcc/ipa-inline.c
gcc/passes.c
gcc/tree-pass.h

index 525bdd3..fe9d9c4 100644 (file)
@@ -1,3 +1,27 @@
+2008-05-01  Jan Hubicka  <jh@suse.cz>
+
+       * tree-pass.h (opt_pass): Add IPA_PASS.
+       (varpool_node, cgraph_node): Forward declare.
+       (ipa_opt_pass): Define.
+       (pass_ipa_inline): Turn into ipa_opt_pass.
+       (pass_apply_inline): Remove.
+       * ipa-inline.c (pass_ipa_inline): Turn into ipa_opt_pass.
+       (apply_inline): Turn into ....
+       (inline_transform): ... this one.
+       (inline_generate_summary): New function.
+       (pass_apply_inline): Remove.
+       * function.h (ipa_opt_pass): Forward declare structure; typedef;
+       vector.
+       (struct function): Add ipa_transforms_to_apply.
+       * passes.c (register_one_dump_file): Work on IPA_PASS.
+       (init_optimization_passes): Remove pass_inline_parameters and
+       pass_apply_inline.
+       (pass_init_dump_file, pass_fini_dump_file): Break out from ....
+       (execute_one_pass) ... here; apply transforms when possible.
+       (add_ipa_transform_pass, execute_ipa_summary_asses,
+       execute_one_ipa_transform_pass): New.
+       (execute_ipa_pass_list): Update for IPA_PASS type.
+
 2008-05-01  H.J. Lu  <hongjiu.lu@intel.com>
 
        * config/i386/i386.c (ix86_builtin_type): Add
index 2e88f97..fcfd3b6 100644 (file)
@@ -179,6 +179,11 @@ struct call_site_record;
 
 DEF_VEC_P(temp_slot_p);
 DEF_VEC_ALLOC_P(temp_slot_p,gc);
+struct ipa_opt_pass;
+typedef struct ipa_opt_pass *ipa_opt_pass;
+
+DEF_VEC_P(ipa_opt_pass);
+DEF_VEC_ALLOC_P(ipa_opt_pass,heap);
 
 enum function_frequency {
   /* This function most likely won't be executed at all.
@@ -466,6 +471,10 @@ struct function GTY(())
   /* Properties used by the pass manager.  */
   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;
 
   /* Collected bit flags.  */
 
index f251fbe..f0a7819 100644 (file)
@@ -1426,26 +1426,6 @@ cgraph_gate_inlining (void)
   return flag_inline_trees;
 }
 
-struct simple_ipa_opt_pass pass_ipa_inline = 
-{
- {
-  SIMPLE_IPA_PASS,
-  "inline",                            /* name */
-  cgraph_gate_inlining,                        /* gate */
-  cgraph_decide_inlining,              /* execute */
-  NULL,                                        /* sub */
-  NULL,                                        /* next */
-  0,                                   /* static_pass_number */
-  TV_INLINE_HEURISTICS,                        /* tv_id */
-  0,                                   /* properties_required */
-  PROP_cfg,                            /* properties_provided */
-  0,                                   /* properties_destroyed */
-  TODO_remove_functions,               /* todo_flags_finish */
-  TODO_dump_cgraph | TODO_dump_func
-  | TODO_remove_functions              /* todo_flags_finish */
- }
-};
-
 /* Because inlining might remove no-longer reachable nodes, we need to
    keep the array visible to garbage collector to avoid reading collected
    out nodes.  */
@@ -1579,13 +1559,20 @@ struct gimple_opt_pass pass_inline_parameters =
  }
 };
 
-/* Apply inline plan to the function.  */
-static unsigned int
-apply_inline (void)
+/* Note function body size.  */
+void
+inline_generate_summary (struct cgraph_node *node ATTRIBUTE_UNUSED)
+{
+  compute_inline_parameters ();
+  return;
+}
+
+/* Apply inline plan to function.  */
+int
+inline_transform (struct cgraph_node *node)
 {
   unsigned int todo = 0;
   struct cgraph_edge *e;
-  struct cgraph_node *node = cgraph_node (current_function_decl);
 
   /* Even when not optimizing, ensure that always_inline functions get inlined.
    */
@@ -1617,13 +1604,13 @@ apply_inline (void)
   return todo | execute_fixup_cfg ();
 }
 
-struct gimple_opt_pass pass_apply_inline = 
+struct ipa_opt_pass pass_ipa_inline = 
 {
  {
-  GIMPLE_PASS,
-  "apply_inline",                      /* name */
-  NULL,                                        /* gate */
-  apply_inline,                                /* execute */
+  IPA_PASS,
+  "inline",                            /* name */
+  cgraph_gate_inlining,                        /* gate */
+  cgraph_decide_inlining,              /* execute */
   NULL,                                        /* sub */
   NULL,                                        /* next */
   0,                                   /* static_pass_number */
@@ -1631,10 +1618,19 @@ struct gimple_opt_pass pass_apply_inline =
   0,                                   /* properties_required */
   PROP_cfg,                            /* properties_provided */
   0,                                   /* properties_destroyed */
-  0,                                   /* todo_flags_start */
-  TODO_dump_func | TODO_verify_flow
-  | TODO_verify_stmts                  /* todo_flags_finish */
- }
+  TODO_remove_functions,               /* todo_flags_finish */
+  TODO_dump_cgraph | TODO_dump_func
+  | TODO_remove_functions              /* todo_flags_finish */
+ },
+ inline_generate_summary,              /* function_generate_summary */
+ NULL,                                 /* variable_generate_summary */
+ NULL,                                 /* function_write_summary */
+ NULL,                                 /* variable_write_summary */
+ NULL,                                 /* function_read_summary */
+ NULL,                                 /* variable_read_summary */
+ 0,                                    /* TODOs */
+ inline_transform,                     /* function_transform */
+ NULL,                                 /* variable_transform */
 };
 
 #include "gt-ipa-inline.h"
index 42f456c..196e5a7 100644 (file)
@@ -352,7 +352,7 @@ register_one_dump_file (struct opt_pass *pass)
                         ? 1 : pass->static_pass_number));
 
   dot_name = concat (".", pass->name, num, NULL);
-  if (pass->type == SIMPLE_IPA_PASS)
+  if (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS)
     prefix = "ipa-", flags = TDF_IPA;
   else if (pass->type == GIMPLE_PASS)
     prefix = "tree-", flags = TDF_TREE;
@@ -538,7 +538,6 @@ init_optimization_passes (void)
          NEXT_PASS (pass_release_ssa_names);
        }
       NEXT_PASS (pass_rebuild_cgraph_edges);
-      NEXT_PASS (pass_inline_parameters);
     }
   NEXT_PASS (pass_ipa_increase_alignment);
   NEXT_PASS (pass_ipa_matrix_reorg);
@@ -554,7 +553,6 @@ init_optimization_passes (void)
   /* These passes are run after IPA passes on every function that is being
      output to the assembler file.  */
   p = &all_passes;
-  NEXT_PASS (pass_apply_inline);
   NEXT_PASS (pass_all_optimizations);
     {
       struct opt_pass **p = &pass_all_optimizations.pass.sub;
@@ -1054,8 +1052,58 @@ verify_curr_properties (void *data)
 }
 #endif
 
+/* Initialize pass dump file.  */
+
+static bool
+pass_init_dump_file (struct opt_pass *pass)
+{
+  /* If a dump file name is present, open it if enabled.  */
+  if (pass->static_pass_number != -1)
+    {
+      bool initializing_dump = !dump_initialized_p (pass->static_pass_number);
+      dump_file_name = get_dump_file_name (pass->static_pass_number);
+      dump_file = dump_begin (pass->static_pass_number, &dump_flags);
+      if (dump_file && current_function_decl)
+       {
+         const char *dname, *aname;
+         dname = lang_hooks.decl_printable_name (current_function_decl, 2);
+         aname = (IDENTIFIER_POINTER
+                  (DECL_ASSEMBLER_NAME (current_function_decl)));
+         fprintf (dump_file, "\n;; Apply transform to function %s (%s)%s\n\n", dname, aname,
+            cfun->function_frequency == FUNCTION_FREQUENCY_HOT
+            ? " (hot)"
+            : cfun->function_frequency == FUNCTION_FREQUENCY_UNLIKELY_EXECUTED
+            ? " (unlikely executed)"
+            : "");
+       }
+      return initializing_dump;
+    }
+  else
+    return false;
+}
+
+/* Flush PASS dump file.  */
+
+static void
+pass_fini_dump_file (struct opt_pass *pass)
+{
+  /* Flush and close dump file.  */
+  if (dump_file_name)
+    {
+      free (CONST_CAST (char *, dump_file_name));
+      dump_file_name = NULL;
+    }
+
+  if (dump_file)
+    {
+      dump_end (pass->static_pass_number, dump_file);
+      dump_file = NULL;
+    }
+}
+
 /* After executing the pass, apply expected changes to the function
    properties. */
+
 static void
 update_properties_after_pass (void *data)
 {
@@ -1064,6 +1112,80 @@ 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 *ipa_pass = (struct ipa_opt_pass *) data;
+  VEC_safe_push (ipa_opt_pass, heap, cfun->ipa_transforms_to_apply, ipa_pass);
+}
+
+/* Execute IPA pass function summary generation. DATA is pointer to
+   pass list to execute.  */
+
+static void
+execute_ipa_summary_passes (void *data)
+{
+  struct ipa_opt_pass *ipa_pass = (struct ipa_opt_pass *)data;
+  struct cgraph_node *node = cgraph_node (cfun->decl);
+  while (ipa_pass && ipa_pass->pass.type == IPA_PASS)
+    {
+      struct opt_pass *pass = &ipa_pass->pass;
+      if (!pass->gate || pass->gate ())
+       {
+         pass_init_dump_file (pass);
+         ipa_pass->function_generate_summary (node);
+         pass_fini_dump_file (pass);
+       }
+      ipa_pass = (struct ipa_opt_pass *)ipa_pass->pass.next;
+    }
+}
+
+/* Execute IPA_PASS function transform on NODE.  */
+
+static void
+execute_one_ipa_transform_pass (struct cgraph_node *node,
+                               struct ipa_opt_pass *ipa_pass)
+{
+  struct opt_pass *pass = &ipa_pass->pass;
+  unsigned int todo_after = 0;
+
+  current_pass = pass;
+  if (!ipa_pass->function_transform)
+    return;
+
+  /* Note that the folders should only create gimple expressions.
+     This is a hack until the new folder is ready.  */
+  in_gimple_form = (cfun && (cfun->curr_properties & PROP_trees)) != 0;
+
+  pass_init_dump_file (pass);
+
+  /* Run pre-pass verification.  */
+  execute_todo (pass->todo_flags_start);
+
+  /* If a timevar is present, start it.  */
+  if (pass->tv_id)
+    timevar_push (pass->tv_id);
+
+  /* Do it!  */
+  todo_after = ipa_pass->function_transform (node);
+
+  /* Stop timevar.  */
+  if (pass->tv_id)
+    timevar_pop (pass->tv_id);
+
+  /* Run post-pass cleanup and verification.  */
+  execute_todo (todo_after);
+  verify_interpass_invariants ();
+
+  pass_fini_dump_file (pass);
+
+  current_pass = NULL;
+  /* Reset in_gimple_form to not break non-unit-at-a-time mode.  */
+  in_gimple_form = false;
+}
+
 static bool
 execute_one_pass (struct opt_pass *pass)
 {
@@ -1072,11 +1194,26 @@ execute_one_pass (struct opt_pass *pass)
 
   /* IPA passes are executed on whole program, so cfun should be NULL.
      Ohter passes needs function context set.  */
-  if (pass->type == SIMPLE_IPA_PASS)
+  if (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS)
     gcc_assert (!cfun && !current_function_decl);
   else
     gcc_assert (cfun && current_function_decl);
 
+  if (cfun && cfun->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);
+          i++)
+       execute_one_ipa_transform_pass (node,
+                                       VEC_index (ipa_opt_pass,
+                                                  cfun->ipa_transforms_to_apply,
+                                                  i));
+      VEC_free (ipa_opt_pass, heap, cfun->ipa_transforms_to_apply);
+      cfun->ipa_transforms_to_apply = NULL;
+    }
+
   current_pass = pass;
   /* See if we're supposed to run this pass.  */
   if (pass->gate && !pass->gate ())
@@ -1100,28 +1237,7 @@ execute_one_pass (struct opt_pass *pass)
                   (void *)(size_t)pass->properties_required);
 #endif
 
-  /* If a dump file name is present, open it if enabled.  */
-  if (pass->static_pass_number != -1)
-    {
-      initializing_dump = !dump_initialized_p (pass->static_pass_number);
-      dump_file_name = get_dump_file_name (pass->static_pass_number);
-      dump_file = dump_begin (pass->static_pass_number, &dump_flags);
-      if (dump_file && current_function_decl)
-       {
-         const char *dname, *aname;
-         dname = lang_hooks.decl_printable_name (current_function_decl, 2);
-         aname = (IDENTIFIER_POINTER
-                  (DECL_ASSEMBLER_NAME (current_function_decl)));
-         fprintf (dump_file, "\n;; Function %s (%s)%s\n\n", dname, aname,
-            cfun->function_frequency == FUNCTION_FREQUENCY_HOT
-            ? " (hot)"
-            : cfun->function_frequency == FUNCTION_FREQUENCY_UNLIKELY_EXECUTED
-            ? " (unlikely executed)"
-            : "");
-       }
-    }
-  else
-    initializing_dump = false;
+  initializing_dump = pass_init_dump_file (pass);
 
   /* If a timevar is present, start it.  */
   if (pass->tv_id)
@@ -1154,24 +1270,15 @@ execute_one_pass (struct opt_pass *pass)
   /* Run post-pass cleanup and verification.  */
   execute_todo (todo_after | pass->todo_flags_finish);
   verify_interpass_invariants ();
+  if (pass->type == IPA_PASS)
+    do_per_function (add_ipa_transform_pass, pass);
 
   if (!current_function_decl)
     cgraph_process_new_functions ();
 
-  /* Flush and close dump file.  */
-  if (dump_file_name)
-    {
-      free (CONST_CAST (char *, dump_file_name));
-      dump_file_name = NULL;
-    }
-
-  if (dump_file)
-    {
-      dump_end (pass->static_pass_number, dump_file);
-      dump_file = NULL;
-    }
+  pass_fini_dump_file (pass);
 
-  if (pass->type != SIMPLE_IPA_PASS)
+  if (pass->type != SIMPLE_IPA_PASS && pass->type != IPA_PASS)
     gcc_assert (!(cfun->curr_properties & PROP_trees)
                || pass->type != RTL_PASS);
 
@@ -1201,17 +1308,31 @@ execute_pass_list (struct opt_pass *pass)
 void
 execute_ipa_pass_list (struct opt_pass *pass)
 {
+  bool summaries_generated = false;
   do
     {
       gcc_assert (!current_function_decl);
       gcc_assert (!cfun);
-      gcc_assert (pass->type == SIMPLE_IPA_PASS);
+      gcc_assert (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS);
+      if (pass->type == IPA_PASS && (!pass->gate || pass->gate ()))
+       {
+         if (!summaries_generated)
+           {
+             if (!quiet_flag && !cfun)
+               fprintf (stderr, " <summary generate>");
+             do_per_function_toporder (execute_ipa_summary_passes, pass);
+           }
+         summaries_generated = true;
+       }
+      else
+       summaries_generated = false;
       if (execute_one_pass (pass) && pass->sub)
        {
          if (pass->sub->type == GIMPLE_PASS)
            do_per_function_toporder ((void (*)(void *))execute_pass_list,
                                      pass->sub);
-         else if (pass->sub->type == SIMPLE_IPA_PASS)
+         else if (pass->sub->type == SIMPLE_IPA_PASS
+                  || pass->sub->type == IPA_PASS)
            execute_ipa_pass_list (pass->sub);
          else
            gcc_unreachable ();
index f391c52..4d16ed6 100644 (file)
@@ -96,7 +96,8 @@ struct opt_pass
   enum opt_pass_type {
     GIMPLE_PASS,
     RTL_PASS,
-    SIMPLE_IPA_PASS
+    SIMPLE_IPA_PASS,
+    IPA_PASS
   } type;
   /* Terse name of the pass used as a fragment of the dump file name.  */
   const char *name;
@@ -133,7 +134,7 @@ struct opt_pass
   unsigned int todo_flags_finish;
 };
 
-/* Description or GIMPLE pass.  */
+/* Description of GIMPLE pass.  */
 struct gimple_opt_pass
 {
   struct opt_pass pass;
@@ -145,7 +146,36 @@ struct rtl_opt_pass
   struct opt_pass pass;
 };
 
-/* Description if simple IPA pass.  Simple IPA passes have just one execute
+struct varpool_node;
+struct cgraph_node;
+
+/* Description of IPA pass with generate summary, write, execute, read and
+   transform stages.  */
+struct ipa_opt_pass
+{
+  struct opt_pass pass;
+
+  /* IPA passes can analyze function body and variable initializers using this
+      hook and produce summary.  */
+  void (*function_generate_summary) (struct cgraph_node *);
+  void (*variable_generate_summary) (struct varpool_node *);
+
+  /* These hooks will be used to serialize IPA summaries on disk.  For a moment
+      they are just placeholders.  */
+  void (*function_write_summary) (struct cgraph_node *); 
+  void (*variable_write_summary) (struct varpool_node *);
+  void (*function_read_summary) (struct cgraph_node *);
+  void (*variable_read_summary) (struct varpool_node *);
+
+  /* Results of interprocedural propagation of an IPA pass is applied to
+     function body via this hook.  */
+  unsigned int function_transform_todo_flags_start;
+  unsigned int (*function_transform) (struct cgraph_node *);
+  void (*variable_transform) (struct varpool_node *);
+
+};
+
+/* Description of simple IPA pass.  Simple IPA passes have just one execute
    hook.  */
 struct simple_ipa_opt_pass
 {
@@ -353,9 +383,10 @@ extern struct gimple_opt_pass pass_build_cgraph_edges;
 extern struct gimple_opt_pass pass_reset_cc_flags;
 
 /* IPA Passes */
+extern struct ipa_opt_pass pass_ipa_inline;
+
 extern struct simple_ipa_opt_pass pass_ipa_matrix_reorg;
 extern struct simple_ipa_opt_pass pass_ipa_cp;
-extern struct simple_ipa_opt_pass pass_ipa_inline;
 extern struct simple_ipa_opt_pass pass_ipa_early_inline;
 extern struct simple_ipa_opt_pass pass_ipa_reference;
 extern struct simple_ipa_opt_pass pass_ipa_pure_const;
@@ -471,7 +502,6 @@ extern struct rtl_opt_pass pass_rtl_seqabstr;
 extern struct gimple_opt_pass pass_release_ssa_names;
 extern struct gimple_opt_pass pass_early_inline;
 extern struct gimple_opt_pass pass_inline_parameters;
-extern struct gimple_opt_pass pass_apply_inline;
 extern struct gimple_opt_pass pass_all_early_optimizations;
 extern struct gimple_opt_pass pass_update_address_taken;