aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Hubicka <jh@suse.cz>2008-05-01 18:08:15 +0200
committerJan Hubicka <hubicka@gcc.gnu.org>2008-05-01 16:08:15 +0000
commit17653c00b9d77f94272588e58400de197005b3a6 (patch)
tree417705d74e26aac95b03885b54a88b3c22e0d807
parentbd9513ea36c626d301024efb0d0eebd43ca2489a (diff)
downloadgcc-17653c00b9d77f94272588e58400de197005b3a6.zip
gcc-17653c00b9d77f94272588e58400de197005b3a6.tar.gz
gcc-17653c00b9d77f94272588e58400de197005b3a6.tar.bz2
tree-pass.h (opt_pass): Add IPA_PASS.
* 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. From-SVN: r134859
-rw-r--r--gcc/ChangeLog24
-rw-r--r--gcc/function.h9
-rw-r--r--gcc/ipa-inline.c62
-rw-r--r--gcc/passes.c203
-rw-r--r--gcc/tree-pass.h40
5 files changed, 259 insertions, 79 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 525bdd3..fe9d9c4 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/function.h b/gcc/function.h
index 2e88f97..fcfd3b6 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -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. */
diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
index f251fbe..f0a7819 100644
--- a/gcc/ipa-inline.c
+++ b/gcc/ipa-inline.c
@@ -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"
diff --git a/gcc/passes.c b/gcc/passes.c
index 42f456c..196e5a7 100644
--- a/gcc/passes.c
+++ b/gcc/passes.c
@@ -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 ();
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index f391c52..4d16ed6 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -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;