diff options
author | bstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4> | 2015-01-21 22:01:24 +0000 |
---|---|---|
committer | bstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4> | 2015-01-21 22:01:24 +0000 |
commit | ffde65b31066f17eef243be882bb89a6e19370aa (patch) | |
tree | ea876d041c0a63eefccdac5416a8678e75da4cfc /gcc/passes.c | |
parent | a8c7acc4db08ce7c8ac3ddcb943f9219e2893792 (diff) | |
download | gcc-ffde65b31066f17eef243be882bb89a6e19370aa.tar.gz |
[.]
2015-01-21 Basile Starynkevitch <basile@starynkevitch.net>
{{merged with trunk -i.e. GCC5.0 in stage4- using
svn merge -r209216:219879 svn+ssh://bstarynk@gcc.gnu.org/svn/gcc/trunk
but should probably have used
svn merge -r209216:219879 ^/trunk
we don't use svnmerge.py anymore since our svn is version 1.8.10
}}
VERY UNSTABLE
2015-01-20 Basile Starynkevitch <basile@starynkevitch.net>
Move previous topdir ChangeLog.MELT to ChangeLog.MELT.2008-2014
[contrib/]
2015-01-21 Basile Starynkevitch <basile@starynkevitch.net>
* MELT-Plugin-Makefile: Able to make upgrade-melt as a
plugin. Works for GCC 5.0. Remove GCC 4.7 old stuff.
Move previous contrib/ChangeLog.MELT to ChangeLog.MELT.2008-2014
[gcc/]
2015-01-21 Basile Starynkevitch <basile@starynkevitch.net>
{{merged with trunk -i.e. GCC5.0 in stage4- using
svn merge -r209216:219879 svn+ssh://bstarynk@gcc.gnu.org/svn/gcc/trunk
but should probably have used
svn merge -r209216:219879 ^/trunk
**@@@ UNSTABLE since libmelt-ana-gimple.melt not compiling, but
translator painfully bootstrapping!!@@@@ }}
* toplev.c: Merged manually by keeping MELT extra stuff.
* toplev.h: Likewise.
* gengtype.c: Add "melt-runtime.h" in list, but merged with trunk.
* melt-runtime.h (MELT_VERSION_STRING): Bump to "1.2-pre-merged".
(meltgc_walk_gimple_seq): Remove.
(gt_ggc_mx_gimple_statement_d): Same for GCC 4.9 & 5.0
* melt-runtime.cc: Update copyright year.
(ggc_alloc_cleared_melt_valuevector_st, melt_resize_scangcvect):
Call ggc_internal_cleared_alloc.
(melt_val2passflag): Skip TODO_verify_ssa, TODO_verify_flow,
TODO_verify_stmts, TODO_verify_rtl_sharing for GCC 5.0.
(meltgc_walkstmt_cb, meltgc_walktree_cb)
(melt_tree_walk_frame_size, meltgc_walk_gimple_seq): Remove.
(melt_gt_ggc_mx_gimple_seq_d): Call
gt_ggc_mx_gimple_statement_base.
* melt-build-script.tpl: Update copyright year. Don't symlink
meltrunsup.h anymore.
* melt-build-script.sh: Regenerate.
* melt/warmelt-base.melt: Update copyright year.
(valdesc_object, valdesc_mapobjects, valdesc_mapstrings)
(valdesc_multiple, valdesc_closure, valdesc_routine, valdesc_hook)
(valdesc_bucketlongs, valdesc_jsonobject, valdesc_string)
(valdesc_strbuf, valdesc_pair, valdesc_list, valdesc_int)
(valdesc_double, valdesc_mixint, valdesc_mixloc)
(valdesc_mixbigint, valdesc_real, valdesc_special_data): Use
ggc_internal_alloc & ggc_internal_cleared_alloc for GCC 5.0.
(json_canonical_name): Use ISUPPER, ISALPHA, TOUPPER instead of
their standard <ctype.h> lowercase macros.
* melt/warmelt-modes.melt: Update copyright year.
(generate_runtypesupport_forwcopy_fun): Emit both GCC 4.9 & 5.0
compatible code.
* melt/libmelt-ana-base.melt: Update copyright year.
* melt/libmelt-ana-gimple.melt: TO BE IMPROVED
* melt/generated/*: Painfully regenerated several times thru GCC
4.9 MELT plugin.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/melt-branch@219975 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/passes.c')
-rw-r--r-- | gcc/passes.c | 716 |
1 files changed, 417 insertions, 299 deletions
diff --git a/gcc/passes.c b/gcc/passes.c index 0904f1b7616..b2027edc45a 100644 --- a/gcc/passes.c +++ b/gcc/passes.c @@ -1,5 +1,5 @@ /* Top level of GCC compilers (cc1, cc1plus, etc.) - Copyright (C) 1987-2014 Free Software Foundation, Inc. + Copyright (C) 1987-2015 Free Software Foundation, Inc. This file is part of GCC. @@ -28,7 +28,16 @@ along with GCC; see the file COPYING3. If not see #include "tm.h" #include "line-map.h" #include "input.h" +#include "hash-set.h" +#include "machmode.h" +#include "vec.h" +#include "double-int.h" +#include "alias.h" +#include "symtab.h" +#include "wide-int.h" +#include "inchash.h" #include "tree.h" +#include "fold-const.h" #include "varasm.h" #include "rtl.h" #include "tm_p.h" @@ -42,7 +51,18 @@ along with GCC; see the file COPYING3. If not see #include "except.h" #include "function.h" #include "toplev.h" +#include "hashtab.h" +#include "statistics.h" +#include "real.h" +#include "fixed-value.h" +#include "expmed.h" +#include "dojump.h" +#include "explow.h" +#include "calls.h" +#include "emit-rtl.h" +#include "stmt.h" #include "expr.h" +#include "predict.h" #include "basic-block.h" #include "intl.h" #include "graph.h" @@ -75,7 +95,10 @@ along with GCC; see the file COPYING3. If not see #include "tree-pass.h" #include "tree-dump.h" #include "df.h" -#include "predict.h" +#include "hash-map.h" +#include "plugin-api.h" +#include "ipa-ref.h" +#include "cgraph.h" #include "lto-streamer.h" #include "plugin.h" #include "ipa-utils.h" @@ -108,13 +131,13 @@ opt_pass::clone () } bool -opt_pass::gate () +opt_pass::gate (function *) { return true; } unsigned int -opt_pass::execute () +opt_pass::execute (function *) { return 0; } @@ -132,13 +155,15 @@ opt_pass::opt_pass (const pass_data &data, context *ctxt) void pass_manager::execute_early_local_passes () { - execute_pass_list (pass_early_local_passes_1->sub); + execute_pass_list (cfun, pass_build_ssa_passes_1->sub); + execute_pass_list (cfun, pass_chkp_instrumentation_passes_1->sub); + execute_pass_list (cfun, pass_local_optimization_passes_1->sub); } unsigned int pass_manager::execute_pass_mode_switching () { - return pass_mode_switching_1->execute (); + return pass_mode_switching_1->execute (cfun); } @@ -238,7 +263,7 @@ rest_of_decl_compilation (tree decl, if (in_lto_p && !at_end) ; else if (finalize && TREE_CODE (decl) != FUNCTION_DECL) - varpool_finalize_decl (decl); + varpool_node::finalize_decl (decl); } #ifdef ASM_FINISH_DECLARE_OBJECT @@ -266,7 +291,7 @@ rest_of_decl_compilation (tree decl, ; else if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl) && TREE_STATIC (decl)) - varpool_node_for_decl (decl); + varpool_node::get_create (decl); } /* Called after finishing a record, union or enumeral type. */ @@ -324,7 +349,7 @@ finish_optimization_passes (void) } static unsigned int -execute_all_early_local_passes (void) +execute_build_ssa_passes (void) { /* Once this pass (and its sub-passes) are complete, all functions will be in SSA form. Technically this state change is happening @@ -332,66 +357,125 @@ execute_all_early_local_passes (void) none of the sub-passes are IPA passes and do not create new functions, this is ok. We're setting this value for the benefit of IPA passes that follow. */ - if (cgraph_state < CGRAPH_STATE_IPA_SSA) - cgraph_state = CGRAPH_STATE_IPA_SSA; + if (symtab->state < IPA_SSA) + symtab->state = IPA_SSA; return 0; } -/* Gate: execute, or not, all of the non-trivial optimizations. */ +namespace { -static bool -gate_all_early_local_passes (void) +const pass_data pass_data_build_ssa_passes = { - /* Don't bother doing anything if the program has errors. */ - return (!seen_error () && !in_lto_p); -} + SIMPLE_IPA_PASS, /* type */ + "build_ssa_passes", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ + TV_EARLY_LOCAL, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + /* todo_flags_finish is executed before subpases. For this reason + it makes no sense to remove unreachable functions here. */ + 0, /* todo_flags_finish */ +}; -namespace { +class pass_build_ssa_passes : public simple_ipa_opt_pass +{ +public: + pass_build_ssa_passes (gcc::context *ctxt) + : simple_ipa_opt_pass (pass_data_build_ssa_passes, ctxt) + {} -const pass_data pass_data_early_local_passes = + /* opt_pass methods: */ + virtual bool gate (function *) + { + /* Don't bother doing anything if the program has errors. */ + return (!seen_error () && !in_lto_p); + } + + virtual unsigned int execute (function *) + { + return execute_build_ssa_passes (); + } + +}; // class pass_build_ssa_passes + +const pass_data pass_data_chkp_instrumentation_passes = { SIMPLE_IPA_PASS, /* type */ - "early_local_cleanups", /* name */ + "chkp_passes", /* name */ OPTGROUP_NONE, /* optinfo_flags */ - true, /* has_gate */ - true, /* has_execute */ - TV_EARLY_LOCAL, /* tv_id */ + TV_NONE, /* tv_id */ 0, /* properties_required */ 0, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ - TODO_remove_functions, /* todo_flags_finish */ + 0, /* todo_flags_finish */ }; -class pass_early_local_passes : public simple_ipa_opt_pass +class pass_chkp_instrumentation_passes : public simple_ipa_opt_pass { public: - pass_early_local_passes (gcc::context *ctxt) - : simple_ipa_opt_pass (pass_data_early_local_passes, ctxt) + pass_chkp_instrumentation_passes (gcc::context *ctxt) + : simple_ipa_opt_pass (pass_data_chkp_instrumentation_passes, ctxt) {} /* opt_pass methods: */ - bool gate () { return gate_all_early_local_passes (); } - unsigned int execute () { return execute_all_early_local_passes (); } + virtual bool gate (function *) + { + /* Don't bother doing anything if the program has errors. */ + return (!seen_error () && !in_lto_p); + } -}; // class pass_early_local_passes +}; // class pass_chkp_instrumentation_passes + +const pass_data pass_data_local_optimization_passes = +{ + SIMPLE_IPA_PASS, /* type */ + "opt_local_passes", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ + TV_NONE, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0, /* todo_flags_finish */ +}; + +class pass_local_optimization_passes : public simple_ipa_opt_pass +{ +public: + pass_local_optimization_passes (gcc::context *ctxt) + : simple_ipa_opt_pass (pass_data_local_optimization_passes, ctxt) + {} + + /* opt_pass methods: */ + virtual bool gate (function *) + { + /* Don't bother doing anything if the program has errors. */ + return (!seen_error () && !in_lto_p); + } + +}; // class pass_local_optimization_passes } // anon namespace simple_ipa_opt_pass * -make_pass_early_local_passes (gcc::context *ctxt) +make_pass_build_ssa_passes (gcc::context *ctxt) { - return new pass_early_local_passes (ctxt); + return new pass_build_ssa_passes (ctxt); } -/* Gate: execute, or not, all of the non-trivial optimizations. */ +simple_ipa_opt_pass * +make_pass_chkp_instrumentation_passes (gcc::context *ctxt) +{ + return new pass_chkp_instrumentation_passes (ctxt); +} -static bool -gate_all_early_optimizations (void) +simple_ipa_opt_pass * +make_pass_local_optimization_passes (gcc::context *ctxt) { - return (optimize >= 1 - /* Don't bother doing anything if the program has errors. */ - && !seen_error ()); + return new pass_local_optimization_passes (ctxt); } namespace { @@ -401,8 +485,6 @@ const pass_data pass_data_all_early_optimizations = GIMPLE_PASS, /* type */ "early_optimizations", /* name */ OPTGROUP_NONE, /* optinfo_flags */ - true, /* has_gate */ - false, /* has_execute */ TV_NONE, /* tv_id */ 0, /* properties_required */ 0, /* properties_provided */ @@ -419,7 +501,12 @@ public: {} /* opt_pass methods: */ - bool gate () { return gate_all_early_optimizations (); } + virtual bool gate (function *) + { + return (optimize >= 1 + /* Don't bother doing anything if the program has errors. */ + && !seen_error ()); + } }; // class pass_all_early_optimizations @@ -431,14 +518,6 @@ make_pass_all_early_optimizations (gcc::context *ctxt) return new pass_all_early_optimizations (ctxt); } -/* Gate: execute, or not, all of the non-trivial optimizations. */ - -static bool -gate_all_optimizations (void) -{ - return optimize >= 1 && !optimize_debug; -} - namespace { const pass_data pass_data_all_optimizations = @@ -446,8 +525,6 @@ const pass_data pass_data_all_optimizations = GIMPLE_PASS, /* type */ "*all_optimizations", /* name */ OPTGROUP_NONE, /* optinfo_flags */ - true, /* has_gate */ - false, /* has_execute */ TV_OPTIMIZE, /* tv_id */ 0, /* properties_required */ 0, /* properties_provided */ @@ -464,7 +541,7 @@ public: {} /* opt_pass methods: */ - bool gate () { return gate_all_optimizations (); } + virtual bool gate (function *) { return optimize >= 1 && !optimize_debug; } }; // class pass_all_optimizations @@ -476,14 +553,6 @@ make_pass_all_optimizations (gcc::context *ctxt) return new pass_all_optimizations (ctxt); } -/* Gate: execute, or not, all of the non-trivial optimizations. */ - -static bool -gate_all_optimizations_g (void) -{ - return optimize >= 1 && optimize_debug; -} - namespace { const pass_data pass_data_all_optimizations_g = @@ -491,8 +560,6 @@ const pass_data pass_data_all_optimizations_g = GIMPLE_PASS, /* type */ "*all_optimizations_g", /* name */ OPTGROUP_NONE, /* optinfo_flags */ - true, /* has_gate */ - false, /* has_execute */ TV_OPTIMIZE, /* tv_id */ 0, /* properties_required */ 0, /* properties_provided */ @@ -509,7 +576,7 @@ public: {} /* opt_pass methods: */ - bool gate () { return gate_all_optimizations_g (); } + virtual bool gate (function *) { return optimize >= 1 && optimize_debug; } }; // class pass_all_optimizations_g @@ -521,14 +588,6 @@ make_pass_all_optimizations_g (gcc::context *ctxt) return new pass_all_optimizations_g (ctxt); } -static bool -gate_rest_of_compilation (void) -{ - /* Early return if there were errors. We can run afoul of our - consistency checks, and there's not really much point in fixing them. */ - return !(rtl_dump_and_exit || flag_syntax_only || seen_error ()); -} - namespace { const pass_data pass_data_rest_of_compilation = @@ -536,8 +595,6 @@ const pass_data pass_data_rest_of_compilation = RTL_PASS, /* type */ "*rest_of_compilation", /* name */ OPTGROUP_NONE, /* optinfo_flags */ - true, /* has_gate */ - false, /* has_execute */ TV_REST_OF_COMPILATION, /* tv_id */ PROP_rtl, /* properties_required */ 0, /* properties_provided */ @@ -554,7 +611,12 @@ public: {} /* opt_pass methods: */ - bool gate () { return gate_rest_of_compilation (); } + virtual bool gate (function *) + { + /* Early return if there were errors. We can run afoul of our + consistency checks, and there's not really much point in fixing them. */ + return !(rtl_dump_and_exit || flag_syntax_only || seen_error ()); + } }; // class pass_rest_of_compilation @@ -566,12 +628,6 @@ make_pass_rest_of_compilation (gcc::context *ctxt) return new pass_rest_of_compilation (ctxt); } -static bool -gate_postreload (void) -{ - return reload_completed; -} - namespace { const pass_data pass_data_postreload = @@ -579,14 +635,12 @@ const pass_data pass_data_postreload = RTL_PASS, /* type */ "*all-postreload", /* name */ OPTGROUP_NONE, /* optinfo_flags */ - true, /* has_gate */ - false, /* has_execute */ TV_POSTRELOAD, /* tv_id */ PROP_rtl, /* properties_required */ 0, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ - TODO_verify_rtl_sharing, /* todo_flags_finish */ + 0, /* todo_flags_finish */ }; class pass_postreload : public rtl_opt_pass @@ -597,7 +651,7 @@ public: {} /* opt_pass methods: */ - bool gate () { return gate_postreload (); } + virtual bool gate (function *) { return reload_completed; } }; // class pass_postreload @@ -609,6 +663,44 @@ make_pass_postreload (gcc::context *ctxt) return new pass_postreload (ctxt); } +namespace { + +const pass_data pass_data_late_compilation = +{ + RTL_PASS, /* type */ + "*all-late_compilation", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ + TV_LATE_COMPILATION, /* tv_id */ + PROP_rtl, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0, /* todo_flags_finish */ +}; + +class pass_late_compilation : public rtl_opt_pass +{ +public: + pass_late_compilation (gcc::context *ctxt) + : rtl_opt_pass (pass_data_late_compilation, ctxt) + {} + + /* opt_pass methods: */ + virtual bool gate (function *) + { + return reload_completed || targetm.no_register_allocation; + } + +}; // class pass_late_compilation + +} // anon namespace + +static rtl_opt_pass * +make_pass_late_compilation (gcc::context *ctxt) +{ + return new pass_late_compilation (ctxt); +} + /* Set the static pass number of pass PASS to ID and record that @@ -699,114 +791,73 @@ pass_manager::register_one_dump_file (opt_pass *pass) if (optgroup_flags == OPTGROUP_NONE) optgroup_flags = OPTGROUP_OTHER; id = dumps->dump_register (dot_name, flag_name, glob_name, flags, - optgroup_flags); + optgroup_flags, + true); set_pass_for_id (id, pass); full_name = concat (prefix, pass->name, num, NULL); register_pass_name (pass, full_name); free (CONST_CAST (char *, full_name)); } -/* Recursive worker function for register_dump_files. */ +/* Register the dump files for the pass_manager starting at PASS. */ -int -pass_manager:: -register_dump_files_1 (opt_pass *pass, int properties) +void +pass_manager::register_dump_files (opt_pass *pass) { do { - int new_properties = (properties | pass->properties_provided) - & ~pass->properties_destroyed; - if (pass->name && pass->name[0] != '*') register_one_dump_file (pass); if (pass->sub) - new_properties = register_dump_files_1 (pass->sub, new_properties); - - /* If we have a gate, combine the properties that we could have with - and without the pass being examined. */ - if (pass->has_gate) - properties &= new_properties; - else - properties = new_properties; + register_dump_files (pass->sub); pass = pass->next; } while (pass); - - return properties; -} - -/* Register the dump files for the pass_manager starting at PASS. - PROPERTIES reflects the properties that are guaranteed to be available at - the beginning of the pipeline. */ - -void -pass_manager:: -register_dump_files (opt_pass *pass,int properties) -{ - pass->properties_required |= properties; - register_dump_files_1 (pass, properties); } -struct pass_registry -{ - const char* unique_name; - opt_pass *pass; -}; - /* Helper for pass_registry hash table. */ -struct pass_registry_hasher : typed_noop_remove <pass_registry> +struct pass_registry_hasher : default_hashmap_traits { - typedef pass_registry value_type; - typedef pass_registry compare_type; - static inline hashval_t hash (const value_type *); - static inline bool equal (const value_type *, const compare_type *); + static inline hashval_t hash (const char *); + static inline bool equal_keys (const char *, const char *); }; /* Pass registry hash function. */ inline hashval_t -pass_registry_hasher::hash (const value_type *s) +pass_registry_hasher::hash (const char *name) { - return htab_hash_string (s->unique_name); + return htab_hash_string (name); } /* Hash equal function */ inline bool -pass_registry_hasher::equal (const value_type *s1, const compare_type *s2) +pass_registry_hasher::equal_keys (const char *s1, const char *s2) { - return !strcmp (s1->unique_name, s2->unique_name); + return !strcmp (s1, s2); } -static hash_table <pass_registry_hasher> name_to_pass_map; +static hash_map<const char *, opt_pass *, pass_registry_hasher> + *name_to_pass_map; /* Register PASS with NAME. */ static void register_pass_name (opt_pass *pass, const char *name) { - struct pass_registry **slot; - struct pass_registry pr; - - if (!name_to_pass_map.is_created ()) - name_to_pass_map.create (256); - - pr.unique_name = name; - slot = name_to_pass_map.find_slot (&pr, INSERT); - if (!*slot) - { - struct pass_registry *new_pr; + if (!name_to_pass_map) + name_to_pass_map + = new hash_map<const char *, opt_pass *, pass_registry_hasher> (256); - new_pr = XCNEW (struct pass_registry); - new_pr->unique_name = xstrdup (name); - new_pr->pass = pass; - *slot = new_pr; - } - else + if (name_to_pass_map->get (name)) return; /* Ignore plugin passes. */ + + const char *unique_name = xstrdup (name); + name_to_pass_map->put (unique_name, pass); } /* Map from pass id to canonicalized pass name. */ @@ -816,15 +867,13 @@ static vec<char_ptr> pass_tab = vNULL; /* Callback function for traversing NAME_TO_PASS_MAP. */ -int -passes_pass_traverse (pass_registry **p, void *data ATTRIBUTE_UNUSED) +bool +passes_pass_traverse (const char *const &name, opt_pass *const &pass, void *) { - opt_pass *pass = (*p)->pass; - gcc_assert (pass->static_pass_number > 0); gcc_assert (pass_tab.exists ()); - pass_tab[pass->static_pass_number] = (*p)->unique_name; + pass_tab[pass->static_pass_number] = name; return 1; } @@ -839,7 +888,7 @@ create_pass_tab (void) return; pass_tab.safe_grow_cleared (g->get_passes ()->passes_by_id_size + 1); - name_to_pass_map.traverse <void *, passes_pass_traverse> (NULL); + name_to_pass_map->traverse <void *, passes_pass_traverse> (NULL); } static bool override_gate_status (opt_pass *, tree, bool); @@ -854,7 +903,7 @@ dump_one_pass (opt_pass *pass, int pass_indent) const char *pn; bool is_on, is_really_on; - is_on = pass->has_gate ? pass->gate () : true; + is_on = pass->gate (cfun); is_really_on = override_gate_status (pass, current_function_decl, is_on); if (pass->static_pass_number <= 0) @@ -926,15 +975,11 @@ pass_manager::dump_passes () const static opt_pass * get_pass_by_name (const char *name) { - struct pass_registry **slot, pr; - - pr.unique_name = name; - slot = name_to_pass_map.find_slot (&pr, NO_INSERT); + opt_pass **p = name_to_pass_map->get (name); + if (p) + return *p; - if (!slot || !*slot) - return NULL; - - return (*slot)->pass; + return NULL; } @@ -1170,7 +1215,7 @@ is_pass_explicitly_enabled_or_disabled (opt_pass *pass, if (!slot) return false; - cgraph_uid = func ? cgraph_get_node (func)->uid : 0; + cgraph_uid = func ? cgraph_node::get (func)->uid : 0; if (func && DECL_ASSEMBLER_NAME_SET_P (func)) aname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (func)); @@ -1498,6 +1543,12 @@ pass_manager::operator new (size_t sz) return xcalloc (1, sz); } +void +pass_manager::operator delete (void *ptr) +{ + free (ptr); +} + pass_manager::pass_manager (context *ctxt) : all_passes (NULL), all_small_ipa_passes (NULL), all_lowering_passes (NULL), all_regular_ipa_passes (NULL), @@ -1548,19 +1599,41 @@ pass_manager::pass_manager (context *ctxt) #undef TERMINATE_PASS_LIST /* Register the passes with the tree dump code. */ - register_dump_files (all_lowering_passes, PROP_gimple_any); - register_dump_files (all_small_ipa_passes, - PROP_gimple_any | PROP_gimple_lcf | PROP_gimple_leh - | PROP_cfg); - register_dump_files (all_regular_ipa_passes, - PROP_gimple_any | PROP_gimple_lcf | PROP_gimple_leh - | PROP_cfg); - register_dump_files (all_late_ipa_passes, - PROP_gimple_any | PROP_gimple_lcf | PROP_gimple_leh - | PROP_cfg); - register_dump_files (all_passes, - PROP_gimple_any | PROP_gimple_lcf | PROP_gimple_leh - | PROP_cfg); + register_dump_files (all_lowering_passes); + register_dump_files (all_small_ipa_passes); + register_dump_files (all_regular_ipa_passes); + register_dump_files (all_late_ipa_passes); + register_dump_files (all_passes); +} + +static void +delete_pass_tree (opt_pass *pass) +{ + while (pass) + { + /* Recurse into child passes. */ + delete_pass_tree (pass->sub); + + opt_pass *next = pass->next; + + /* Delete this pass. */ + delete pass; + + /* Iterate onto sibling passes. */ + pass = next; + } +} + +pass_manager::~pass_manager () +{ + XDELETEVEC (passes_by_id); + + /* Call delete_pass_tree on each of the pass_lists. */ +#define DEF_PASS_LIST(LIST) \ + delete_pass_tree (*pass_lists[PASS_LIST_NO_##LIST]); + GCC_PASS_LISTS +#undef DEF_PASS_LIST + } /* If we are in IPA mode (i.e., current_function_decl is NULL), call @@ -1568,27 +1641,17 @@ pass_manager::pass_manager (context *ctxt) call CALLBACK on the current function. */ static void -do_per_function (void (*callback) (void *data), void *data) +do_per_function (void (*callback) (function *, void *data), void *data) { if (current_function_decl) - callback (data); + callback (cfun, data); else { struct cgraph_node *node; FOR_EACH_DEFINED_FUNCTION (node) - if (node->analyzed && gimple_has_body_p (node->decl) + if (node->analyzed && (gimple_has_body_p (node->decl) && !in_lto_p) && (!node->clone_of || node->decl != node->clone_of->decl)) - { - push_cfun (DECL_STRUCT_FUNCTION (node->decl)); - callback (data); - if (!flag_wpa) - { - free_dominance_info (CDI_DOMINATORS); - free_dominance_info (CDI_POST_DOMINATORS); - } - pop_cfun (); - ggc_collect (); - } + callback (DECL_STRUCT_FUNCTION (node->decl), data); } } @@ -1596,44 +1659,71 @@ do_per_function (void (*callback) (void *data), void *data) keep the array visible to garbage collector to avoid reading collected out nodes. */ static int nnodes; -static GTY ((length ("nnodes"))) cgraph_node_ptr *order; +static GTY ((length ("nnodes"))) cgraph_node **order; + +/* Hook called when NODE is removed and therefore should be + excluded from order vector. DATA is an array of integers. + DATA[0] holds max index it may be accessed by. For cgraph + node DATA[node->uid + 1] holds index of this node in order + vector. */ +static void +remove_cgraph_node_from_order (cgraph_node *node, void *data) +{ + int *order_idx = (int *)data; + + if (node->uid >= order_idx[0]) + return; + + int idx = order_idx[node->uid + 1]; + if (idx >= 0 && idx < nnodes && order[idx] == node) + order[idx] = NULL; +} /* If we are in IPA mode (i.e., current_function_decl is NULL), call function CALLBACK for every function in the call graph. Otherwise, call CALLBACK on the current function. This function is global so that plugins can use it. */ void -do_per_function_toporder (void (*callback) (void *data), void *data) +do_per_function_toporder (void (*callback) (function *, void *data), void *data) { int i; if (current_function_decl) - callback (data); + callback (cfun, data); else { + cgraph_node_hook_list *hook; + int *order_idx; gcc_assert (!order); - order = ggc_alloc_vec_cgraph_node_ptr (cgraph_n_nodes); + order = ggc_vec_alloc<cgraph_node *> (symtab->cgraph_count); + + order_idx = XALLOCAVEC (int, symtab->cgraph_max_uid + 1); + memset (order_idx + 1, -1, sizeof (int) * symtab->cgraph_max_uid); + order_idx[0] = symtab->cgraph_max_uid; + nnodes = ipa_reverse_postorder (order); for (i = nnodes - 1; i >= 0; i--) - order[i]->process = 1; + { + order[i]->process = 1; + order_idx[order[i]->uid + 1] = i; + } + hook = symtab->add_cgraph_removal_hook (remove_cgraph_node_from_order, + order_idx); for (i = nnodes - 1; i >= 0; i--) { + /* Function could be inlined and removed as unreachable. */ + if (!order[i]) + continue; + struct cgraph_node *node = order[i]; /* Allow possibly removed nodes to be garbage collected. */ order[i] = NULL; node->process = 0; - if (cgraph_function_with_gimple_body_p (node)) - { - cgraph_get_body (node); - push_cfun (DECL_STRUCT_FUNCTION (node->decl)); - callback (data); - free_dominance_info (CDI_DOMINATORS); - free_dominance_info (CDI_POST_DOMINATORS); - pop_cfun (); - ggc_collect (); - } + if (node->has_gimple_body_p ()) + callback (DECL_STRUCT_FUNCTION (node->decl), data); } + symtab->remove_cgraph_removal_hook (hook); } ggc_free (order); order = NULL; @@ -1643,14 +1733,16 @@ do_per_function_toporder (void (*callback) (void *data), void *data) /* Helper function to perform function body dump. */ static void -execute_function_dump (void *data) +execute_function_dump (function *fn, void *data) { opt_pass *pass = (opt_pass *)data; - if (dump_file && current_function_decl) + if (dump_file) { - if (cfun->curr_properties & PROP_trees) - dump_function_to_file (current_function_decl, dump_file, dump_flags); + push_cfun (fn); + + if (fn->curr_properties & PROP_trees) + dump_function_to_file (fn->decl, dump_file, dump_flags); else print_rtl_with_bb (dump_file, get_insns (), dump_flags); @@ -1658,7 +1750,7 @@ execute_function_dump (void *data) close the file before aborting. */ fflush (dump_file); - if ((cfun->curr_properties & PROP_cfg) + if ((fn->curr_properties & PROP_cfg) && (dump_flags & TDF_GRAPH)) { if (!pass->graph_dump_initialized) @@ -1666,8 +1758,10 @@ execute_function_dump (void *data) clean_graph_dump_file (dump_file_name); pass->graph_dump_initialized = true; } - print_graph_cfg (dump_file_name, cfun); + print_graph_cfg (dump_file_name, fn); } + + pop_cfun (); } } @@ -1798,13 +1892,16 @@ pass_manager::dump_profile_report () const /* Perform all TODO actions that ought to be done on each function. */ static void -execute_function_todo (void *data) +execute_function_todo (function *fn, void *data) { + bool from_ipa_pass = (cfun == NULL); unsigned int flags = (size_t)data; - flags &= ~cfun->last_verified; + flags &= ~fn->last_verified; if (!flags) return; + push_cfun (fn); + /* Always cleanup the CFG before trying to update SSA. */ if (flags & TODO_cleanup_cfg) { @@ -1824,7 +1921,6 @@ execute_function_todo (void *data) { unsigned update_flags = flags & TODO_update_ssa_any; update_ssa (update_flags); - cfun->last_verified &= ~TODO_verify_ssa; } if (flag_tree_pta && (flags & TODO_rebuild_alias)) @@ -1840,30 +1936,59 @@ execute_function_todo (void *data) rebuild_frequencies (); if (flags & TODO_rebuild_cgraph_edges) - rebuild_cgraph_edges (); + cgraph_edge::rebuild_edges (); /* If we've seen errors do not bother running any verifiers. */ - if (seen_error ()) - return; - -#if defined ENABLE_CHECKING - if (flags & TODO_verify_ssa - || (current_loops && loops_state_satisfies_p (LOOP_CLOSED_SSA))) + if (!seen_error ()) { - verify_gimple_in_cfg (cfun); - verify_ssa (true); - } - else if (flags & TODO_verify_stmts) - verify_gimple_in_cfg (cfun); - if (flags & TODO_verify_flow) - verify_flow_info (); - if (current_loops && loops_state_satisfies_p (LOOP_CLOSED_SSA)) - verify_loop_closed_ssa (false); - if (flags & TODO_verify_rtl_sharing) - verify_rtl_sharing (); +#if defined ENABLE_CHECKING + dom_state pre_verify_state = dom_info_state (fn, CDI_DOMINATORS); + dom_state pre_verify_pstate = dom_info_state (fn, CDI_POST_DOMINATORS); + + if (flags & TODO_verify_il) + { + if (cfun->curr_properties & PROP_trees) + { + if (cfun->curr_properties & PROP_cfg) + /* IPA passes leave stmts to be fixed up, so make sure to + not verify stmts really throw. */ + verify_gimple_in_cfg (cfun, !from_ipa_pass); + else + verify_gimple_in_seq (gimple_body (cfun->decl)); + } + if (cfun->curr_properties & PROP_ssa) + /* IPA passes leave stmts to be fixed up, so make sure to + not verify SSA operands whose verifier will choke on that. */ + verify_ssa (true, !from_ipa_pass); + /* IPA passes leave basic-blocks unsplit, so make sure to + not trip on that. */ + if ((cfun->curr_properties & PROP_cfg) + && !from_ipa_pass) + verify_flow_info (); + if (current_loops + && loops_state_satisfies_p (LOOP_CLOSED_SSA)) + verify_loop_closed_ssa (false); + if (cfun->curr_properties & PROP_rtl) + verify_rtl_sharing (); + } + + /* Make sure verifiers don't change dominator state. */ + gcc_assert (dom_info_state (fn, CDI_DOMINATORS) == pre_verify_state); + gcc_assert (dom_info_state (fn, CDI_POST_DOMINATORS) == pre_verify_pstate); #endif + } + + fn->last_verified = flags & TODO_verify_all; - cfun->last_verified = flags & TODO_verify_all; + pop_cfun (); + + /* For IPA passes make sure to release dominator info, it can be + computed by non-verifying TODOs. */ + if (from_ipa_pass) + { + free_dominance_info (fn, CDI_DOMINATORS); + free_dominance_info (fn, CDI_POST_DOMINATORS); + } } /* Perform all TODO actions. */ @@ -1893,13 +2018,13 @@ execute_todo (unsigned int flags) if (flags & TODO_remove_functions) { gcc_assert (!cfun); - symtab_remove_unreachable_nodes (true, dump_file); + symtab->remove_unreachable_nodes (dump_file); } if ((flags & TODO_dump_symtab) && dump_file && !current_function_decl) { gcc_assert (!cfun); - dump_symtab (dump_file); + symtab_node::dump_table (dump_file); /* Flush the file. If verification fails, we won't be able to close the file before aborting. */ fflush (dump_file); @@ -1925,9 +2050,9 @@ verify_interpass_invariants (void) /* Clear the last verified flag. */ static void -clear_last_verified (void *data ATTRIBUTE_UNUSED) +clear_last_verified (function *fn, void *data ATTRIBUTE_UNUSED) { - cfun->last_verified = 0; + fn->last_verified = 0; } /* Helper function. Verify that the properties has been turn into the @@ -1935,10 +2060,10 @@ clear_last_verified (void *data ATTRIBUTE_UNUSED) #ifdef ENABLE_CHECKING static void -verify_curr_properties (void *data) +verify_curr_properties (function *fn, void *data) { unsigned int props = (size_t)data; - gcc_assert ((cfun->curr_properties & props) == props); + gcc_assert ((fn->curr_properties & props) == props); } #endif @@ -1948,7 +2073,6 @@ verify_curr_properties (void *data) bool pass_init_dump_file (opt_pass *pass) { - pass->graph_dump_initialized = false; /* If a dump file name is present, open it if enabled. */ if (pass->static_pass_number != -1) { @@ -1997,11 +2121,11 @@ pass_fini_dump_file (opt_pass *pass) properties. */ static void -update_properties_after_pass (void *data) +update_properties_after_pass (function *fn, void *data) { opt_pass *pass = (opt_pass *) data; - cfun->curr_properties = (cfun->curr_properties | pass->properties_provided) - & ~pass->properties_destroyed; + fn->curr_properties = (fn->curr_properties | pass->properties_provided) + & ~pass->properties_destroyed; } /* Execute summary generation for all of the passes in IPA_PASS. */ @@ -2015,7 +2139,7 @@ execute_ipa_summary_passes (ipa_opt_pass_d *ipa_pass) /* Execute all of the IPA_PASSes in the list. */ if (ipa_pass->type == IPA_PASS - && ((!pass->has_gate) || pass->gate ()) + && pass->gate (cfun) && ipa_pass->generate_summary) { pass_init_dump_file (pass); @@ -2024,6 +2148,7 @@ execute_ipa_summary_passes (ipa_opt_pass_d *ipa_pass) if (pass->tv_id) timevar_push (pass->tv_id); + current_pass = pass; ipa_pass->generate_summary (); /* Stop timevar. */ @@ -2097,7 +2222,7 @@ execute_all_ipa_transforms (void) struct cgraph_node *node; if (!cfun) return; - node = cgraph_get_node (current_function_decl); + node = cgraph_node::get (current_function_decl); if (node->ipa_transforms_to_apply.exists ()) { @@ -2109,20 +2234,6 @@ execute_all_ipa_transforms (void) } } -/* Callback for do_per_function to apply all IPA transforms. */ - -static void -apply_ipa_transforms (void *data) -{ - struct cgraph_node *node = cgraph_get_node (current_function_decl); - if (!node->global.inlined_to && node->ipa_transforms_to_apply.exists ()) - { - *(bool *)data = true; - execute_all_ipa_transforms (); - rebuild_cgraph_edges (); - } -} - /* Check if PASS is explicitly disabled or enabled and return the gate status. FUNC is the function to be processed, and GATE_STATUS is the gate status determined by pass manager by @@ -2167,7 +2278,7 @@ execute_one_pass (opt_pass *pass) /* Check whether gate check should be avoided. User controls the value of the gate through the parameter "gate_status". */ - gate_status = pass->has_gate ? pass->gate () : true; + gate_status = pass->gate (cfun); gate_status = override_gate_status (pass, current_function_decl, gate_status); /* Override gate with plugin. */ @@ -2190,18 +2301,6 @@ execute_one_pass (opt_pass *pass) executed. */ invoke_plugin_callbacks (PLUGIN_PASS_EXECUTION, pass); - /* SIPLE IPA passes do not handle callgraphs with IPA transforms in it. - Apply all trnasforms first. */ - if (pass->type == SIMPLE_IPA_PASS) - { - bool applied = false; - do_per_function (apply_ipa_transforms, (void *)&applied); - if (applied) - symtab_remove_unreachable_nodes (true, dump_file); - /* Restore current_pass. */ - current_pass = pass; - } - if (!quiet_flag && !cfun) fprintf (stderr, " <%s/%d%c>", pass->name ? pass->name : "", pass->static_pass_number, @@ -2228,11 +2327,8 @@ execute_one_pass (opt_pass *pass) timevar_push (pass->tv_id); /* Do it! */ - if (pass->has_execute) - { - todo_after = pass->execute (); - do_per_function (clear_last_verified, NULL); - } + todo_after = pass->execute (cfun); + do_per_function (clear_last_verified, NULL); /* Stop timevar. */ if (pass->tv_id != TV_NONE) @@ -2244,7 +2340,7 @@ execute_one_pass (opt_pass *pass) check_profile_consistency (pass->static_pass_number, 0, true); /* Run post-pass cleanup and verification. */ - execute_todo (todo_after | pass->todo_flags_finish); + execute_todo (todo_after | pass->todo_flags_finish | TODO_verify_il); if (profile_report && cfun && (cfun->curr_properties & PROP_cfg)) check_profile_consistency (pass->static_pass_number, 1, true); @@ -2259,7 +2355,7 @@ execute_one_pass (opt_pass *pass) } if (!current_function_decl) - cgraph_process_new_functions (); + symtab->process_new_functions (); pass_fini_dump_file (pass); @@ -2276,20 +2372,33 @@ execute_one_pass (opt_pass *pass) return true; } -void -execute_pass_list (opt_pass *pass) +static void +execute_pass_list_1 (opt_pass *pass) { do { gcc_assert (pass->type == GIMPLE_PASS || pass->type == RTL_PASS); if (execute_one_pass (pass) && pass->sub) - execute_pass_list (pass->sub); + execute_pass_list_1 (pass->sub); pass = pass->next; } while (pass); } +void +execute_pass_list (function *fn, opt_pass *pass) +{ + push_cfun (fn); + execute_pass_list_1 (pass); + if (fn->cfg) + { + free_dominance_info (CDI_DOMINATORS); + free_dominance_info (CDI_POST_DOMINATORS); + } + pop_cfun (); +} + /* Write out all LTO data. */ static void write_lto (void) @@ -2317,7 +2426,7 @@ ipa_write_summaries_2 (opt_pass *pass, struct lto_out_decl_state *state) gcc_assert (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS); if (pass->type == IPA_PASS && ipa_pass->write_summary - && ((!pass->has_gate) || pass->gate ())) + && pass->gate (cfun)) { /* If a timevar is present, start it. */ if (pass->tv_id) @@ -2325,6 +2434,7 @@ ipa_write_summaries_2 (opt_pass *pass, struct lto_out_decl_state *state) pass_init_dump_file (pass); + current_pass = pass; ipa_pass->write_summary (); pass_fini_dump_file (pass); @@ -2375,24 +2485,26 @@ ipa_write_summaries (void) struct cgraph_node *node; struct cgraph_node **order; - if (!flag_generate_lto || seen_error ()) + if ((!flag_generate_lto && !flag_generate_offload) || seen_error ()) return; + select_what_to_stream (); + encoder = lto_symtab_encoder_new (false); /* Create the callgraph set in the same order used in cgraph_expand_all_functions. This mostly facilitates debugging, since it causes the gimple file to be processed in the same order as the source code. */ - order = XCNEWVEC (struct cgraph_node *, cgraph_n_nodes); + order = XCNEWVEC (struct cgraph_node *, symtab->cgraph_count); order_pos = ipa_reverse_postorder (order); - gcc_assert (order_pos == cgraph_n_nodes); + gcc_assert (order_pos == symtab->cgraph_count); for (i = order_pos - 1; i >= 0; i--) { struct cgraph_node *node = order[i]; - if (cgraph_function_with_gimple_body_p (node)) + if (node->has_gimple_body_p ()) { /* When streaming out references to statements as part of some IPA pass summary, the statements need to have uids assigned and the @@ -2404,15 +2516,16 @@ ipa_write_summaries (void) renumber_gimple_stmt_uids (); pop_cfun (); } - if (node->definition) + if (node->definition && node->need_lto_streaming) lto_set_symtab_encoder_in_partition (encoder, node); } FOR_EACH_DEFINED_FUNCTION (node) - if (node->alias) + if (node->alias && node->need_lto_streaming) lto_set_symtab_encoder_in_partition (encoder, node); FOR_EACH_DEFINED_VARIABLE (vnode) - lto_set_symtab_encoder_in_partition (encoder, vnode); + if (vnode->need_lto_streaming) + lto_set_symtab_encoder_in_partition (encoder, vnode); ipa_write_summaries_1 (compute_ltrans_boundary (encoder)); @@ -2435,7 +2548,7 @@ ipa_write_optimization_summaries_1 (opt_pass *pass, gcc_assert (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS); if (pass->type == IPA_PASS && ipa_pass->write_optimization_summary - && ((!pass->has_gate) || pass->gate ())) + && pass->gate (cfun)) { /* If a timevar is present, start it. */ if (pass->tv_id) @@ -2443,6 +2556,7 @@ ipa_write_optimization_summaries_1 (opt_pass *pass, pass_init_dump_file (pass); + current_pass = pass; ipa_pass->write_optimization_summary (); pass_fini_dump_file (pass); @@ -2513,7 +2627,7 @@ ipa_read_summaries_1 (opt_pass *pass) gcc_assert (!cfun); gcc_assert (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS); - if ((!pass->has_gate) || pass->gate ()) + if (pass->gate (cfun)) { if (pass->type == IPA_PASS && ipa_pass->read_summary) { @@ -2523,6 +2637,7 @@ ipa_read_summaries_1 (opt_pass *pass) pass_init_dump_file (pass); + current_pass = pass; ipa_pass->read_summary (); pass_fini_dump_file (pass); @@ -2563,7 +2678,7 @@ ipa_read_optimization_summaries_1 (opt_pass *pass) gcc_assert (!cfun); gcc_assert (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS); - if ((!pass->has_gate) || pass->gate ()) + if (pass->gate (cfun)) { if (pass->type == IPA_PASS && ipa_pass->read_optimization_summary) { @@ -2573,6 +2688,7 @@ ipa_read_optimization_summaries_1 (opt_pass *pass) pass_init_dump_file (pass); + current_pass = pass; ipa_pass->read_optimization_summary (); pass_fini_dump_file (pass); @@ -2613,7 +2729,8 @@ execute_ipa_pass_list (opt_pass *pass) if (pass->sub->type == GIMPLE_PASS) { invoke_plugin_callbacks (PLUGIN_EARLY_GIMPLE_PASSES_START, NULL); - do_per_function_toporder ((void (*)(void *))execute_pass_list, + do_per_function_toporder ((void (*)(function *, void *)) + execute_pass_list, pass->sub); invoke_plugin_callbacks (PLUGIN_EARLY_GIMPLE_PASSES_END, NULL); } @@ -2624,7 +2741,7 @@ execute_ipa_pass_list (opt_pass *pass) gcc_unreachable (); } gcc_assert (!current_function_decl); - cgraph_process_new_functions (); + symtab->process_new_functions (); pass = pass->next; } while (pass); @@ -2640,7 +2757,7 @@ execute_ipa_stmt_fixups (opt_pass *pass, { /* Execute all of the IPA_PASSes in the list. */ if (pass->type == IPA_PASS - && ((!pass->has_gate) || pass->gate ())) + && pass->gate (cfun)) { ipa_opt_pass_d *ipa_pass = (ipa_opt_pass_d *) pass; @@ -2651,6 +2768,7 @@ execute_ipa_stmt_fixups (opt_pass *pass, if (pass->tv_id) timevar_push (pass->tv_id); + current_pass = pass; ipa_pass->stmt_fixup (node, stmts); /* Stop timevar. */ @@ -2719,13 +2837,13 @@ bool function_called_by_processed_nodes_p (void) { struct cgraph_edge *e; - for (e = cgraph_get_node (current_function_decl)->callers; + for (e = cgraph_node::get (current_function_decl)->callers; e; e = e->next_caller) { if (e->caller->decl == current_function_decl) continue; - if (!cgraph_function_with_gimple_body_p (e->caller)) + if (!e->caller->has_gimple_body_p ()) continue; if (TREE_ASM_WRITTEN (e->caller->decl)) continue; @@ -2735,7 +2853,7 @@ function_called_by_processed_nodes_p (void) if (dump_file && e) { fprintf (dump_file, "Already processed call to:\n"); - dump_cgraph_node (dump_file, e->caller); + e->caller->dump (dump_file); } return e != NULL; } |