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. */
}
};
-/* 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.
*/
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 */
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"
? 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;
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);
/* 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;
}
#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)
{
& ~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)
{
/* 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 ())
(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)
/* 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);
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 ();
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;
unsigned int todo_flags_finish;
};
-/* Description or GIMPLE pass. */
+/* Description of GIMPLE pass. */
struct gimple_opt_pass
{
struct opt_pass 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
{
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;
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;