138fd1498Szrj /* Top level of GCC compilers (cc1, cc1plus, etc.) 238fd1498Szrj Copyright (C) 1987-2018 Free Software Foundation, Inc. 338fd1498Szrj 438fd1498Szrj This file is part of GCC. 538fd1498Szrj 638fd1498Szrj GCC is free software; you can redistribute it and/or modify it under 738fd1498Szrj the terms of the GNU General Public License as published by the Free 838fd1498Szrj Software Foundation; either version 3, or (at your option) any later 938fd1498Szrj version. 1038fd1498Szrj 1138fd1498Szrj GCC is distributed in the hope that it will be useful, but WITHOUT ANY 1238fd1498Szrj WARRANTY; without even the implied warranty of MERCHANTABILITY or 1338fd1498Szrj FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1438fd1498Szrj for more details. 1538fd1498Szrj 1638fd1498Szrj You should have received a copy of the GNU General Public License 1738fd1498Szrj along with GCC; see the file COPYING3. If not see 1838fd1498Szrj <http://www.gnu.org/licenses/>. */ 1938fd1498Szrj 2038fd1498Szrj /* This is the top level of cc1/c++. 2138fd1498Szrj It parses command args, opens files, invokes the various passes 2238fd1498Szrj in the proper order, and counts the time used by each. 2338fd1498Szrj Error messages and low-level interface to malloc also handled here. */ 2438fd1498Szrj 2538fd1498Szrj #include "config.h" 2638fd1498Szrj #include "system.h" 2738fd1498Szrj #include "coretypes.h" 2838fd1498Szrj #include "backend.h" 2938fd1498Szrj #include "target.h" 3038fd1498Szrj #include "rtl.h" 3138fd1498Szrj #include "tree.h" 3238fd1498Szrj #include "gimple.h" 3338fd1498Szrj #include "cfghooks.h" 3438fd1498Szrj #include "df.h" 3538fd1498Szrj #include "memmodel.h" 3638fd1498Szrj #include "tm_p.h" 3738fd1498Szrj #include "ssa.h" 3838fd1498Szrj #include "emit-rtl.h" 3938fd1498Szrj #include "cgraph.h" 4038fd1498Szrj #include "lto-streamer.h" 4138fd1498Szrj #include "fold-const.h" 4238fd1498Szrj #include "varasm.h" 4338fd1498Szrj #include "output.h" 4438fd1498Szrj #include "graph.h" 4538fd1498Szrj #include "debug.h" 4638fd1498Szrj #include "cfgloop.h" 4738fd1498Szrj #include "value-prof.h" 4838fd1498Szrj #include "tree-cfg.h" 4938fd1498Szrj #include "tree-ssa-loop-manip.h" 5038fd1498Szrj #include "tree-into-ssa.h" 5138fd1498Szrj #include "tree-dfa.h" 5238fd1498Szrj #include "tree-ssa.h" 5338fd1498Szrj #include "tree-pass.h" 5438fd1498Szrj #include "plugin.h" 5538fd1498Szrj #include "ipa-utils.h" 5638fd1498Szrj #include "tree-pretty-print.h" /* for dump_function_header */ 5738fd1498Szrj #include "context.h" 5838fd1498Szrj #include "pass_manager.h" 5938fd1498Szrj #include "cfgrtl.h" 6038fd1498Szrj #include "tree-ssa-live.h" /* For remove_unused_locals. */ 6138fd1498Szrj #include "tree-cfgcleanup.h" 6238fd1498Szrj #include "insn-addr.h" /* for INSN_ADDRESSES_ALLOC. */ 6338fd1498Szrj #include "diagnostic-core.h" /* for fnotice */ 6438fd1498Szrj #include "stringpool.h" 6538fd1498Szrj #include "attribs.h" 6638fd1498Szrj 6738fd1498Szrj using namespace gcc; 6838fd1498Szrj 6938fd1498Szrj /* This is used for debugging. It allows the current pass to printed 7038fd1498Szrj from anywhere in compilation. 7138fd1498Szrj The variable current_pass is also used for statistics and plugins. */ 7238fd1498Szrj opt_pass *current_pass; 7338fd1498Szrj 7438fd1498Szrj /* Most passes are single-instance (within their context) and thus don't 7538fd1498Szrj need to implement cloning, but passes that support multiple instances 7638fd1498Szrj *must* provide their own implementation of the clone method. 7738fd1498Szrj 7838fd1498Szrj Handle this by providing a default implemenation, but make it a fatal 7938fd1498Szrj error to call it. */ 8038fd1498Szrj 8138fd1498Szrj opt_pass * 8238fd1498Szrj opt_pass::clone () 8338fd1498Szrj { 8438fd1498Szrj internal_error ("pass %s does not support cloning", name); 8538fd1498Szrj } 8638fd1498Szrj 8738fd1498Szrj void 8838fd1498Szrj opt_pass::set_pass_param (unsigned int, bool) 8938fd1498Szrj { 9038fd1498Szrj internal_error ("pass %s needs a set_pass_param implementation to handle the" 9138fd1498Szrj " extra argument in NEXT_PASS", name); 9238fd1498Szrj } 9338fd1498Szrj 9438fd1498Szrj bool 9538fd1498Szrj opt_pass::gate (function *) 9638fd1498Szrj { 9738fd1498Szrj return true; 9838fd1498Szrj } 9938fd1498Szrj 10038fd1498Szrj unsigned int 10138fd1498Szrj opt_pass::execute (function *) 10238fd1498Szrj { 10338fd1498Szrj return 0; 10438fd1498Szrj } 10538fd1498Szrj 10638fd1498Szrj opt_pass::opt_pass (const pass_data &data, context *ctxt) 10738fd1498Szrj : pass_data (data), 10838fd1498Szrj sub (NULL), 10938fd1498Szrj next (NULL), 11038fd1498Szrj static_pass_number (0), 11138fd1498Szrj m_ctxt (ctxt) 11238fd1498Szrj { 11338fd1498Szrj } 11438fd1498Szrj 11538fd1498Szrj 11638fd1498Szrj void 11738fd1498Szrj pass_manager::execute_early_local_passes () 11838fd1498Szrj { 11938fd1498Szrj execute_pass_list (cfun, pass_build_ssa_passes_1->sub); 12038fd1498Szrj if (flag_check_pointer_bounds) 12138fd1498Szrj execute_pass_list (cfun, pass_chkp_instrumentation_passes_1->sub); 12238fd1498Szrj execute_pass_list (cfun, pass_local_optimization_passes_1->sub); 12338fd1498Szrj } 12438fd1498Szrj 12538fd1498Szrj unsigned int 12638fd1498Szrj pass_manager::execute_pass_mode_switching () 12738fd1498Szrj { 12838fd1498Szrj return pass_mode_switching_1->execute (cfun); 12938fd1498Szrj } 13038fd1498Szrj 13138fd1498Szrj 13238fd1498Szrj /* Call from anywhere to find out what pass this is. Useful for 13338fd1498Szrj printing out debugging information deep inside an service 13438fd1498Szrj routine. */ 13538fd1498Szrj void 13638fd1498Szrj print_current_pass (FILE *file) 13738fd1498Szrj { 13838fd1498Szrj if (current_pass) 13938fd1498Szrj fprintf (file, "current pass = %s (%d)\n", 14038fd1498Szrj current_pass->name, current_pass->static_pass_number); 14138fd1498Szrj else 14238fd1498Szrj fprintf (file, "no current pass.\n"); 14338fd1498Szrj } 14438fd1498Szrj 14538fd1498Szrj 14638fd1498Szrj /* Call from the debugger to get the current pass name. */ 14738fd1498Szrj DEBUG_FUNCTION void 14838fd1498Szrj debug_pass (void) 14938fd1498Szrj { 15038fd1498Szrj print_current_pass (stderr); 15138fd1498Szrj } 15238fd1498Szrj 15338fd1498Szrj 15438fd1498Szrj 15538fd1498Szrj /* Global variables used to communicate with passes. */ 15638fd1498Szrj bool in_gimple_form; 15738fd1498Szrj 15838fd1498Szrj 15938fd1498Szrj /* This is called from various places for FUNCTION_DECL, VAR_DECL, 16038fd1498Szrj and TYPE_DECL nodes. 16138fd1498Szrj 16238fd1498Szrj This does nothing for local (non-static) variables, unless the 16338fd1498Szrj variable is a register variable with DECL_ASSEMBLER_NAME set. In 16438fd1498Szrj that case, or if the variable is not an automatic, it sets up the 16538fd1498Szrj RTL and outputs any assembler code (label definition, storage 16638fd1498Szrj allocation and initialization). 16738fd1498Szrj 16838fd1498Szrj DECL is the declaration. TOP_LEVEL is nonzero 16938fd1498Szrj if this declaration is not within a function. */ 17038fd1498Szrj 17138fd1498Szrj void 17238fd1498Szrj rest_of_decl_compilation (tree decl, 17338fd1498Szrj int top_level, 17438fd1498Szrj int at_end) 17538fd1498Szrj { 17638fd1498Szrj bool finalize = true; 17738fd1498Szrj 17838fd1498Szrj /* We deferred calling assemble_alias so that we could collect 17938fd1498Szrj other attributes such as visibility. Emit the alias now. */ 18038fd1498Szrj if (!in_lto_p) 18138fd1498Szrj { 18238fd1498Szrj tree alias; 18338fd1498Szrj alias = lookup_attribute ("alias", DECL_ATTRIBUTES (decl)); 18438fd1498Szrj if (alias) 18538fd1498Szrj { 18638fd1498Szrj alias = TREE_VALUE (TREE_VALUE (alias)); 18738fd1498Szrj alias = get_identifier (TREE_STRING_POINTER (alias)); 18838fd1498Szrj /* A quirk of the initial implementation of aliases required that the 18938fd1498Szrj user add "extern" to all of them. Which is silly, but now 19038fd1498Szrj historical. Do note that the symbol is in fact locally defined. */ 19138fd1498Szrj DECL_EXTERNAL (decl) = 0; 19238fd1498Szrj TREE_STATIC (decl) = 1; 19338fd1498Szrj assemble_alias (decl, alias); 19438fd1498Szrj finalize = false; 19538fd1498Szrj } 19638fd1498Szrj } 19738fd1498Szrj 19838fd1498Szrj /* Can't defer this, because it needs to happen before any 19938fd1498Szrj later function definitions are processed. */ 20038fd1498Szrj if (HAS_DECL_ASSEMBLER_NAME_P (decl) 20138fd1498Szrj && DECL_ASSEMBLER_NAME_SET_P (decl) 20238fd1498Szrj && DECL_REGISTER (decl)) 20338fd1498Szrj make_decl_rtl (decl); 20438fd1498Szrj 20538fd1498Szrj /* Forward declarations for nested functions are not "external", 20638fd1498Szrj but we need to treat them as if they were. */ 20738fd1498Szrj if (TREE_STATIC (decl) || DECL_EXTERNAL (decl) 20838fd1498Szrj || TREE_CODE (decl) == FUNCTION_DECL) 20938fd1498Szrj { 21038fd1498Szrj timevar_push (TV_VARCONST); 21138fd1498Szrj 21238fd1498Szrj /* Don't output anything when a tentative file-scope definition 21338fd1498Szrj is seen. But at end of compilation, do output code for them. 21438fd1498Szrj 21538fd1498Szrj We do output all variables and rely on 21638fd1498Szrj callgraph code to defer them except for forward declarations 21738fd1498Szrj (see gcc.c-torture/compile/920624-1.c) */ 21838fd1498Szrj if ((at_end 21938fd1498Szrj || !DECL_DEFER_OUTPUT (decl) 22038fd1498Szrj || DECL_INITIAL (decl)) 22138fd1498Szrj && (!VAR_P (decl) || !DECL_HAS_VALUE_EXPR_P (decl)) 22238fd1498Szrj && !DECL_EXTERNAL (decl)) 22338fd1498Szrj { 22438fd1498Szrj /* When reading LTO unit, we also read varpool, so do not 22538fd1498Szrj rebuild it. */ 22638fd1498Szrj if (in_lto_p && !at_end) 22738fd1498Szrj ; 22838fd1498Szrj else if (finalize && TREE_CODE (decl) != FUNCTION_DECL) 22938fd1498Szrj varpool_node::finalize_decl (decl); 23038fd1498Szrj } 23138fd1498Szrj 23238fd1498Szrj #ifdef ASM_FINISH_DECLARE_OBJECT 23338fd1498Szrj if (decl == last_assemble_variable_decl) 23438fd1498Szrj { 23538fd1498Szrj ASM_FINISH_DECLARE_OBJECT (asm_out_file, decl, 23638fd1498Szrj top_level, at_end); 23738fd1498Szrj } 23838fd1498Szrj #endif 23938fd1498Szrj 24038fd1498Szrj /* Now that we have activated any function-specific attributes 24138fd1498Szrj that might affect function decl, particularly align, relayout it. */ 24238fd1498Szrj if (TREE_CODE (decl) == FUNCTION_DECL) 24338fd1498Szrj targetm.target_option.relayout_function (decl); 24438fd1498Szrj 24538fd1498Szrj timevar_pop (TV_VARCONST); 24638fd1498Szrj } 24738fd1498Szrj else if (TREE_CODE (decl) == TYPE_DECL 24838fd1498Szrj /* Like in rest_of_type_compilation, avoid confusing the debug 24938fd1498Szrj information machinery when there are errors. */ 25038fd1498Szrj && !seen_error ()) 25138fd1498Szrj { 25238fd1498Szrj timevar_push (TV_SYMOUT); 25338fd1498Szrj debug_hooks->type_decl (decl, !top_level); 25438fd1498Szrj timevar_pop (TV_SYMOUT); 25538fd1498Szrj } 25638fd1498Szrj 25738fd1498Szrj /* Let cgraph know about the existence of variables. */ 25838fd1498Szrj if (in_lto_p && !at_end) 25938fd1498Szrj ; 26038fd1498Szrj else if (VAR_P (decl) && !DECL_EXTERNAL (decl) 26138fd1498Szrj && TREE_STATIC (decl)) 26238fd1498Szrj varpool_node::get_create (decl); 26338fd1498Szrj 26438fd1498Szrj /* Generate early debug for global variables. Any local variables will 26538fd1498Szrj be handled by either handling reachable functions from 26638fd1498Szrj finalize_compilation_unit (and by consequence, locally scoped 26738fd1498Szrj symbols), or by rest_of_type_compilation below. 26838fd1498Szrj 26938fd1498Szrj For Go's hijack of the debug_hooks to implement -fdump-go-spec, pick up 27038fd1498Szrj function prototypes. Go's debug_hooks will not forward them to the 27138fd1498Szrj wrapped hooks. */ 27238fd1498Szrj if (!in_lto_p 27338fd1498Szrj && (TREE_CODE (decl) != FUNCTION_DECL 27438fd1498Szrj /* This will pick up function prototypes with no bodies, 27538fd1498Szrj which are not visible in finalize_compilation_unit() 27638fd1498Szrj while iterating with FOR_EACH_*_FUNCTION through the 27738fd1498Szrj symbol table. */ 27838fd1498Szrj || (flag_dump_go_spec != NULL 27938fd1498Szrj && !DECL_SAVED_TREE (decl) 28038fd1498Szrj && DECL_STRUCT_FUNCTION (decl) == NULL)) 28138fd1498Szrj 28238fd1498Szrj /* We need to check both decl_function_context and 28338fd1498Szrj current_function_decl here to make sure local extern 28438fd1498Szrj declarations end up with the correct context. 28538fd1498Szrj 28638fd1498Szrj For local extern declarations, decl_function_context is 28738fd1498Szrj empty, but current_function_decl is set to the function where 28838fd1498Szrj the extern was declared . Without the check for 28938fd1498Szrj !current_function_decl below, the local extern ends up 29038fd1498Szrj incorrectly with a top-level context. 29138fd1498Szrj 29238fd1498Szrj For example: 29338fd1498Szrj 29438fd1498Szrj namespace S 29538fd1498Szrj { 29638fd1498Szrj int 29738fd1498Szrj f() 29838fd1498Szrj { 29938fd1498Szrj { 30038fd1498Szrj int i = 42; 30138fd1498Szrj { 30238fd1498Szrj extern int i; // Local extern declaration. 30338fd1498Szrj return i; 30438fd1498Szrj } 30538fd1498Szrj } 30638fd1498Szrj } 30738fd1498Szrj } 30838fd1498Szrj */ 30938fd1498Szrj && !decl_function_context (decl) 31038fd1498Szrj && !current_function_decl 31138fd1498Szrj && DECL_SOURCE_LOCATION (decl) != BUILTINS_LOCATION 31238fd1498Szrj && (!decl_type_context (decl) 31338fd1498Szrj /* If we created a varpool node for the decl make sure to 31438fd1498Szrj call early_global_decl. Otherwise we miss changes 31538fd1498Szrj introduced by member definitions like 31638fd1498Szrj struct A { static int staticdatamember; }; 31738fd1498Szrj int A::staticdatamember; 31838fd1498Szrj and thus have incomplete early debug and late debug 31938fd1498Szrj called from varpool node removal fails to handle it 32038fd1498Szrj properly. */ 32138fd1498Szrj || (finalize 32238fd1498Szrj && VAR_P (decl) 32338fd1498Szrj && TREE_STATIC (decl) && !DECL_EXTERNAL (decl))) 32438fd1498Szrj /* Avoid confusing the debug information machinery when there are 32538fd1498Szrj errors. */ 32638fd1498Szrj && !seen_error ()) 32738fd1498Szrj (*debug_hooks->early_global_decl) (decl); 32838fd1498Szrj } 32938fd1498Szrj 33038fd1498Szrj /* Called after finishing a record, union or enumeral type. */ 33138fd1498Szrj 33238fd1498Szrj void 33338fd1498Szrj rest_of_type_compilation (tree type, int toplev) 33438fd1498Szrj { 33538fd1498Szrj /* Avoid confusing the debug information machinery when there are 33638fd1498Szrj errors. */ 33738fd1498Szrj if (seen_error ()) 33838fd1498Szrj return; 33938fd1498Szrj 34038fd1498Szrj timevar_push (TV_SYMOUT); 34138fd1498Szrj debug_hooks->type_decl (TYPE_STUB_DECL (type), !toplev); 34238fd1498Szrj timevar_pop (TV_SYMOUT); 34338fd1498Szrj } 34438fd1498Szrj 34538fd1498Szrj 34638fd1498Szrj 34738fd1498Szrj void 34838fd1498Szrj pass_manager:: 34938fd1498Szrj finish_optimization_passes (void) 35038fd1498Szrj { 35138fd1498Szrj int i; 35238fd1498Szrj struct dump_file_info *dfi; 35338fd1498Szrj char *name; 35438fd1498Szrj gcc::dump_manager *dumps = m_ctxt->get_dumps (); 35538fd1498Szrj 35638fd1498Szrj timevar_push (TV_DUMP); 35738fd1498Szrj if (profile_arc_flag || flag_test_coverage || flag_branch_probabilities) 35838fd1498Szrj { 35938fd1498Szrj dumps->dump_start (pass_profile_1->static_pass_number, NULL); 36038fd1498Szrj end_branch_prob (); 36138fd1498Szrj dumps->dump_finish (pass_profile_1->static_pass_number); 36238fd1498Szrj } 36338fd1498Szrj 36438fd1498Szrj if (optimize > 0) 36538fd1498Szrj { 366*58e805e6Szrj dumps->dump_start (pass_combine_1->static_pass_number, NULL); 36738fd1498Szrj print_combine_total_stats (); 368*58e805e6Szrj dumps->dump_finish (pass_combine_1->static_pass_number); 36938fd1498Szrj } 37038fd1498Szrj 37138fd1498Szrj /* Do whatever is necessary to finish printing the graphs. */ 37238fd1498Szrj for (i = TDI_end; (dfi = dumps->get_dump_file_info (i)) != NULL; ++i) 37338fd1498Szrj if (dfi->graph_dump_initialized) 37438fd1498Szrj { 37538fd1498Szrj name = dumps->get_dump_file_name (dfi); 37638fd1498Szrj finish_graph_dump_file (name); 37738fd1498Szrj free (name); 37838fd1498Szrj } 37938fd1498Szrj 38038fd1498Szrj timevar_pop (TV_DUMP); 38138fd1498Szrj } 38238fd1498Szrj 38338fd1498Szrj static unsigned int 38438fd1498Szrj execute_build_ssa_passes (void) 38538fd1498Szrj { 38638fd1498Szrj /* Once this pass (and its sub-passes) are complete, all functions 38738fd1498Szrj will be in SSA form. Technically this state change is happening 38838fd1498Szrj a tad early, since the sub-passes have not yet run, but since 38938fd1498Szrj none of the sub-passes are IPA passes and do not create new 39038fd1498Szrj functions, this is ok. We're setting this value for the benefit 39138fd1498Szrj of IPA passes that follow. */ 39238fd1498Szrj if (symtab->state < IPA_SSA) 39338fd1498Szrj symtab->state = IPA_SSA; 39438fd1498Szrj return 0; 39538fd1498Szrj } 39638fd1498Szrj 39738fd1498Szrj namespace { 39838fd1498Szrj 39938fd1498Szrj const pass_data pass_data_build_ssa_passes = 40038fd1498Szrj { 40138fd1498Szrj SIMPLE_IPA_PASS, /* type */ 40238fd1498Szrj "build_ssa_passes", /* name */ 40338fd1498Szrj OPTGROUP_NONE, /* optinfo_flags */ 40438fd1498Szrj TV_EARLY_LOCAL, /* tv_id */ 40538fd1498Szrj 0, /* properties_required */ 40638fd1498Szrj 0, /* properties_provided */ 40738fd1498Szrj 0, /* properties_destroyed */ 40838fd1498Szrj 0, /* todo_flags_start */ 40938fd1498Szrj /* todo_flags_finish is executed before subpases. For this reason 41038fd1498Szrj it makes no sense to remove unreachable functions here. */ 41138fd1498Szrj 0, /* todo_flags_finish */ 41238fd1498Szrj }; 41338fd1498Szrj 41438fd1498Szrj class pass_build_ssa_passes : public simple_ipa_opt_pass 41538fd1498Szrj { 41638fd1498Szrj public: 41738fd1498Szrj pass_build_ssa_passes (gcc::context *ctxt) 41838fd1498Szrj : simple_ipa_opt_pass (pass_data_build_ssa_passes, ctxt) 41938fd1498Szrj {} 42038fd1498Szrj 42138fd1498Szrj /* opt_pass methods: */ 42238fd1498Szrj virtual bool gate (function *) 42338fd1498Szrj { 42438fd1498Szrj /* Don't bother doing anything if the program has errors. */ 42538fd1498Szrj return (!seen_error () && !in_lto_p); 42638fd1498Szrj } 42738fd1498Szrj 42838fd1498Szrj virtual unsigned int execute (function *) 42938fd1498Szrj { 43038fd1498Szrj return execute_build_ssa_passes (); 43138fd1498Szrj } 43238fd1498Szrj 43338fd1498Szrj }; // class pass_build_ssa_passes 43438fd1498Szrj 43538fd1498Szrj const pass_data pass_data_chkp_instrumentation_passes = 43638fd1498Szrj { 43738fd1498Szrj SIMPLE_IPA_PASS, /* type */ 43838fd1498Szrj "chkp_passes", /* name */ 43938fd1498Szrj OPTGROUP_NONE, /* optinfo_flags */ 44038fd1498Szrj TV_NONE, /* tv_id */ 44138fd1498Szrj 0, /* properties_required */ 44238fd1498Szrj 0, /* properties_provided */ 44338fd1498Szrj 0, /* properties_destroyed */ 44438fd1498Szrj 0, /* todo_flags_start */ 44538fd1498Szrj 0, /* todo_flags_finish */ 44638fd1498Szrj }; 44738fd1498Szrj 44838fd1498Szrj class pass_chkp_instrumentation_passes : public simple_ipa_opt_pass 44938fd1498Szrj { 45038fd1498Szrj public: 45138fd1498Szrj pass_chkp_instrumentation_passes (gcc::context *ctxt) 45238fd1498Szrj : simple_ipa_opt_pass (pass_data_chkp_instrumentation_passes, ctxt) 45338fd1498Szrj {} 45438fd1498Szrj 45538fd1498Szrj /* opt_pass methods: */ 45638fd1498Szrj virtual bool gate (function *) 45738fd1498Szrj { 45838fd1498Szrj /* Don't bother doing anything if the program has errors. */ 45938fd1498Szrj return (flag_check_pointer_bounds 46038fd1498Szrj && !seen_error () && !in_lto_p); 46138fd1498Szrj } 46238fd1498Szrj 46338fd1498Szrj }; // class pass_chkp_instrumentation_passes 46438fd1498Szrj 46538fd1498Szrj const pass_data pass_data_local_optimization_passes = 46638fd1498Szrj { 46738fd1498Szrj SIMPLE_IPA_PASS, /* type */ 46838fd1498Szrj "opt_local_passes", /* name */ 46938fd1498Szrj OPTGROUP_NONE, /* optinfo_flags */ 47038fd1498Szrj TV_NONE, /* tv_id */ 47138fd1498Szrj 0, /* properties_required */ 47238fd1498Szrj 0, /* properties_provided */ 47338fd1498Szrj 0, /* properties_destroyed */ 47438fd1498Szrj 0, /* todo_flags_start */ 47538fd1498Szrj 0, /* todo_flags_finish */ 47638fd1498Szrj }; 47738fd1498Szrj 47838fd1498Szrj class pass_local_optimization_passes : public simple_ipa_opt_pass 47938fd1498Szrj { 48038fd1498Szrj public: 48138fd1498Szrj pass_local_optimization_passes (gcc::context *ctxt) 48238fd1498Szrj : simple_ipa_opt_pass (pass_data_local_optimization_passes, ctxt) 48338fd1498Szrj {} 48438fd1498Szrj 48538fd1498Szrj /* opt_pass methods: */ 48638fd1498Szrj virtual bool gate (function *) 48738fd1498Szrj { 48838fd1498Szrj /* Don't bother doing anything if the program has errors. */ 48938fd1498Szrj return (!seen_error () && !in_lto_p); 49038fd1498Szrj } 49138fd1498Szrj 49238fd1498Szrj }; // class pass_local_optimization_passes 49338fd1498Szrj 49438fd1498Szrj } // anon namespace 49538fd1498Szrj 49638fd1498Szrj simple_ipa_opt_pass * 49738fd1498Szrj make_pass_build_ssa_passes (gcc::context *ctxt) 49838fd1498Szrj { 49938fd1498Szrj return new pass_build_ssa_passes (ctxt); 50038fd1498Szrj } 50138fd1498Szrj 50238fd1498Szrj simple_ipa_opt_pass * 50338fd1498Szrj make_pass_chkp_instrumentation_passes (gcc::context *ctxt) 50438fd1498Szrj { 50538fd1498Szrj return new pass_chkp_instrumentation_passes (ctxt); 50638fd1498Szrj } 50738fd1498Szrj 50838fd1498Szrj simple_ipa_opt_pass * 50938fd1498Szrj make_pass_local_optimization_passes (gcc::context *ctxt) 51038fd1498Szrj { 51138fd1498Szrj return new pass_local_optimization_passes (ctxt); 51238fd1498Szrj } 51338fd1498Szrj 51438fd1498Szrj namespace { 51538fd1498Szrj 51638fd1498Szrj const pass_data pass_data_all_early_optimizations = 51738fd1498Szrj { 51838fd1498Szrj GIMPLE_PASS, /* type */ 51938fd1498Szrj "early_optimizations", /* name */ 52038fd1498Szrj OPTGROUP_NONE, /* optinfo_flags */ 52138fd1498Szrj TV_NONE, /* tv_id */ 52238fd1498Szrj 0, /* properties_required */ 52338fd1498Szrj 0, /* properties_provided */ 52438fd1498Szrj 0, /* properties_destroyed */ 52538fd1498Szrj 0, /* todo_flags_start */ 52638fd1498Szrj 0, /* todo_flags_finish */ 52738fd1498Szrj }; 52838fd1498Szrj 52938fd1498Szrj class pass_all_early_optimizations : public gimple_opt_pass 53038fd1498Szrj { 53138fd1498Szrj public: 53238fd1498Szrj pass_all_early_optimizations (gcc::context *ctxt) 53338fd1498Szrj : gimple_opt_pass (pass_data_all_early_optimizations, ctxt) 53438fd1498Szrj {} 53538fd1498Szrj 53638fd1498Szrj /* opt_pass methods: */ 53738fd1498Szrj virtual bool gate (function *) 53838fd1498Szrj { 53938fd1498Szrj return (optimize >= 1 54038fd1498Szrj /* Don't bother doing anything if the program has errors. */ 54138fd1498Szrj && !seen_error ()); 54238fd1498Szrj } 54338fd1498Szrj 54438fd1498Szrj }; // class pass_all_early_optimizations 54538fd1498Szrj 54638fd1498Szrj } // anon namespace 54738fd1498Szrj 54838fd1498Szrj static gimple_opt_pass * 54938fd1498Szrj make_pass_all_early_optimizations (gcc::context *ctxt) 55038fd1498Szrj { 55138fd1498Szrj return new pass_all_early_optimizations (ctxt); 55238fd1498Szrj } 55338fd1498Szrj 55438fd1498Szrj namespace { 55538fd1498Szrj 55638fd1498Szrj const pass_data pass_data_all_optimizations = 55738fd1498Szrj { 55838fd1498Szrj GIMPLE_PASS, /* type */ 55938fd1498Szrj "*all_optimizations", /* name */ 56038fd1498Szrj OPTGROUP_NONE, /* optinfo_flags */ 56138fd1498Szrj TV_OPTIMIZE, /* tv_id */ 56238fd1498Szrj 0, /* properties_required */ 56338fd1498Szrj 0, /* properties_provided */ 56438fd1498Szrj 0, /* properties_destroyed */ 56538fd1498Szrj 0, /* todo_flags_start */ 56638fd1498Szrj 0, /* todo_flags_finish */ 56738fd1498Szrj }; 56838fd1498Szrj 56938fd1498Szrj class pass_all_optimizations : public gimple_opt_pass 57038fd1498Szrj { 57138fd1498Szrj public: 57238fd1498Szrj pass_all_optimizations (gcc::context *ctxt) 57338fd1498Szrj : gimple_opt_pass (pass_data_all_optimizations, ctxt) 57438fd1498Szrj {} 57538fd1498Szrj 57638fd1498Szrj /* opt_pass methods: */ 57738fd1498Szrj virtual bool gate (function *) { return optimize >= 1 && !optimize_debug; } 57838fd1498Szrj 57938fd1498Szrj }; // class pass_all_optimizations 58038fd1498Szrj 58138fd1498Szrj } // anon namespace 58238fd1498Szrj 58338fd1498Szrj static gimple_opt_pass * 58438fd1498Szrj make_pass_all_optimizations (gcc::context *ctxt) 58538fd1498Szrj { 58638fd1498Szrj return new pass_all_optimizations (ctxt); 58738fd1498Szrj } 58838fd1498Szrj 58938fd1498Szrj namespace { 59038fd1498Szrj 59138fd1498Szrj const pass_data pass_data_all_optimizations_g = 59238fd1498Szrj { 59338fd1498Szrj GIMPLE_PASS, /* type */ 59438fd1498Szrj "*all_optimizations_g", /* name */ 59538fd1498Szrj OPTGROUP_NONE, /* optinfo_flags */ 59638fd1498Szrj TV_OPTIMIZE, /* tv_id */ 59738fd1498Szrj 0, /* properties_required */ 59838fd1498Szrj 0, /* properties_provided */ 59938fd1498Szrj 0, /* properties_destroyed */ 60038fd1498Szrj 0, /* todo_flags_start */ 60138fd1498Szrj 0, /* todo_flags_finish */ 60238fd1498Szrj }; 60338fd1498Szrj 60438fd1498Szrj class pass_all_optimizations_g : public gimple_opt_pass 60538fd1498Szrj { 60638fd1498Szrj public: 60738fd1498Szrj pass_all_optimizations_g (gcc::context *ctxt) 60838fd1498Szrj : gimple_opt_pass (pass_data_all_optimizations_g, ctxt) 60938fd1498Szrj {} 61038fd1498Szrj 61138fd1498Szrj /* opt_pass methods: */ 61238fd1498Szrj virtual bool gate (function *) { return optimize >= 1 && optimize_debug; } 61338fd1498Szrj 61438fd1498Szrj }; // class pass_all_optimizations_g 61538fd1498Szrj 61638fd1498Szrj } // anon namespace 61738fd1498Szrj 61838fd1498Szrj static gimple_opt_pass * 61938fd1498Szrj make_pass_all_optimizations_g (gcc::context *ctxt) 62038fd1498Szrj { 62138fd1498Szrj return new pass_all_optimizations_g (ctxt); 62238fd1498Szrj } 62338fd1498Szrj 62438fd1498Szrj namespace { 62538fd1498Szrj 62638fd1498Szrj const pass_data pass_data_rest_of_compilation = 62738fd1498Szrj { 62838fd1498Szrj RTL_PASS, /* type */ 62938fd1498Szrj "*rest_of_compilation", /* name */ 63038fd1498Szrj OPTGROUP_NONE, /* optinfo_flags */ 63138fd1498Szrj TV_REST_OF_COMPILATION, /* tv_id */ 63238fd1498Szrj PROP_rtl, /* properties_required */ 63338fd1498Szrj 0, /* properties_provided */ 63438fd1498Szrj 0, /* properties_destroyed */ 63538fd1498Szrj 0, /* todo_flags_start */ 63638fd1498Szrj 0, /* todo_flags_finish */ 63738fd1498Szrj }; 63838fd1498Szrj 63938fd1498Szrj class pass_rest_of_compilation : public rtl_opt_pass 64038fd1498Szrj { 64138fd1498Szrj public: 64238fd1498Szrj pass_rest_of_compilation (gcc::context *ctxt) 64338fd1498Szrj : rtl_opt_pass (pass_data_rest_of_compilation, ctxt) 64438fd1498Szrj {} 64538fd1498Szrj 64638fd1498Szrj /* opt_pass methods: */ 64738fd1498Szrj virtual bool gate (function *) 64838fd1498Szrj { 64938fd1498Szrj /* Early return if there were errors. We can run afoul of our 65038fd1498Szrj consistency checks, and there's not really much point in fixing them. */ 65138fd1498Szrj return !(rtl_dump_and_exit || flag_syntax_only || seen_error ()); 65238fd1498Szrj } 65338fd1498Szrj 65438fd1498Szrj }; // class pass_rest_of_compilation 65538fd1498Szrj 65638fd1498Szrj } // anon namespace 65738fd1498Szrj 65838fd1498Szrj static rtl_opt_pass * 65938fd1498Szrj make_pass_rest_of_compilation (gcc::context *ctxt) 66038fd1498Szrj { 66138fd1498Szrj return new pass_rest_of_compilation (ctxt); 66238fd1498Szrj } 66338fd1498Szrj 66438fd1498Szrj namespace { 66538fd1498Szrj 66638fd1498Szrj const pass_data pass_data_postreload = 66738fd1498Szrj { 66838fd1498Szrj RTL_PASS, /* type */ 66938fd1498Szrj "*all-postreload", /* name */ 67038fd1498Szrj OPTGROUP_NONE, /* optinfo_flags */ 67138fd1498Szrj TV_POSTRELOAD, /* tv_id */ 67238fd1498Szrj PROP_rtl, /* properties_required */ 67338fd1498Szrj 0, /* properties_provided */ 67438fd1498Szrj 0, /* properties_destroyed */ 67538fd1498Szrj 0, /* todo_flags_start */ 67638fd1498Szrj 0, /* todo_flags_finish */ 67738fd1498Szrj }; 67838fd1498Szrj 67938fd1498Szrj class pass_postreload : public rtl_opt_pass 68038fd1498Szrj { 68138fd1498Szrj public: 68238fd1498Szrj pass_postreload (gcc::context *ctxt) 68338fd1498Szrj : rtl_opt_pass (pass_data_postreload, ctxt) 68438fd1498Szrj {} 68538fd1498Szrj 68638fd1498Szrj /* opt_pass methods: */ 68738fd1498Szrj virtual bool gate (function *) { return reload_completed; } 68838fd1498Szrj 68938fd1498Szrj }; // class pass_postreload 69038fd1498Szrj 69138fd1498Szrj } // anon namespace 69238fd1498Szrj 69338fd1498Szrj static rtl_opt_pass * 69438fd1498Szrj make_pass_postreload (gcc::context *ctxt) 69538fd1498Szrj { 69638fd1498Szrj return new pass_postreload (ctxt); 69738fd1498Szrj } 69838fd1498Szrj 69938fd1498Szrj namespace { 70038fd1498Szrj 70138fd1498Szrj const pass_data pass_data_late_compilation = 70238fd1498Szrj { 70338fd1498Szrj RTL_PASS, /* type */ 70438fd1498Szrj "*all-late_compilation", /* name */ 70538fd1498Szrj OPTGROUP_NONE, /* optinfo_flags */ 70638fd1498Szrj TV_LATE_COMPILATION, /* tv_id */ 70738fd1498Szrj PROP_rtl, /* properties_required */ 70838fd1498Szrj 0, /* properties_provided */ 70938fd1498Szrj 0, /* properties_destroyed */ 71038fd1498Szrj 0, /* todo_flags_start */ 71138fd1498Szrj 0, /* todo_flags_finish */ 71238fd1498Szrj }; 71338fd1498Szrj 71438fd1498Szrj class pass_late_compilation : public rtl_opt_pass 71538fd1498Szrj { 71638fd1498Szrj public: 71738fd1498Szrj pass_late_compilation (gcc::context *ctxt) 71838fd1498Szrj : rtl_opt_pass (pass_data_late_compilation, ctxt) 71938fd1498Szrj {} 72038fd1498Szrj 72138fd1498Szrj /* opt_pass methods: */ 72238fd1498Szrj virtual bool gate (function *) 72338fd1498Szrj { 72438fd1498Szrj return reload_completed || targetm.no_register_allocation; 72538fd1498Szrj } 72638fd1498Szrj 72738fd1498Szrj }; // class pass_late_compilation 72838fd1498Szrj 72938fd1498Szrj } // anon namespace 73038fd1498Szrj 73138fd1498Szrj static rtl_opt_pass * 73238fd1498Szrj make_pass_late_compilation (gcc::context *ctxt) 73338fd1498Szrj { 73438fd1498Szrj return new pass_late_compilation (ctxt); 73538fd1498Szrj } 73638fd1498Szrj 73738fd1498Szrj 73838fd1498Szrj 73938fd1498Szrj /* Set the static pass number of pass PASS to ID and record that 74038fd1498Szrj in the mapping from static pass number to pass. */ 74138fd1498Szrj 74238fd1498Szrj void 74338fd1498Szrj pass_manager:: 74438fd1498Szrj set_pass_for_id (int id, opt_pass *pass) 74538fd1498Szrj { 74638fd1498Szrj pass->static_pass_number = id; 74738fd1498Szrj if (passes_by_id_size <= id) 74838fd1498Szrj { 74938fd1498Szrj passes_by_id = XRESIZEVEC (opt_pass *, passes_by_id, id + 1); 75038fd1498Szrj memset (passes_by_id + passes_by_id_size, 0, 75138fd1498Szrj (id + 1 - passes_by_id_size) * sizeof (void *)); 75238fd1498Szrj passes_by_id_size = id + 1; 75338fd1498Szrj } 75438fd1498Szrj passes_by_id[id] = pass; 75538fd1498Szrj } 75638fd1498Szrj 75738fd1498Szrj /* Return the pass with the static pass number ID. */ 75838fd1498Szrj 75938fd1498Szrj opt_pass * 76038fd1498Szrj pass_manager::get_pass_for_id (int id) const 76138fd1498Szrj { 76238fd1498Szrj if (id >= passes_by_id_size) 76338fd1498Szrj return NULL; 76438fd1498Szrj return passes_by_id[id]; 76538fd1498Szrj } 76638fd1498Szrj 76738fd1498Szrj /* Iterate over the pass tree allocating dump file numbers. We want 76838fd1498Szrj to do this depth first, and independent of whether the pass is 76938fd1498Szrj enabled or not. */ 77038fd1498Szrj 77138fd1498Szrj void 77238fd1498Szrj register_one_dump_file (opt_pass *pass) 77338fd1498Szrj { 77438fd1498Szrj g->get_passes ()->register_one_dump_file (pass); 77538fd1498Szrj } 77638fd1498Szrj 77738fd1498Szrj void 77838fd1498Szrj pass_manager::register_one_dump_file (opt_pass *pass) 77938fd1498Szrj { 78038fd1498Szrj char *dot_name, *flag_name, *glob_name; 78138fd1498Szrj const char *name, *full_name, *prefix; 78238fd1498Szrj 78338fd1498Szrj /* Buffer big enough to format a 32-bit UINT_MAX into. */ 78438fd1498Szrj char num[11]; 78538fd1498Szrj dump_kind dkind; 78638fd1498Szrj int id; 78738fd1498Szrj int optgroup_flags = OPTGROUP_NONE; 78838fd1498Szrj gcc::dump_manager *dumps = m_ctxt->get_dumps (); 78938fd1498Szrj 79038fd1498Szrj /* See below in next_pass_1. */ 79138fd1498Szrj num[0] = '\0'; 79238fd1498Szrj if (pass->static_pass_number != -1) 79338fd1498Szrj sprintf (num, "%u", ((int) pass->static_pass_number < 0 79438fd1498Szrj ? 1 : pass->static_pass_number)); 79538fd1498Szrj 79638fd1498Szrj /* The name is both used to identify the pass for the purposes of plugins, 79738fd1498Szrj and to specify dump file name and option. 79838fd1498Szrj The latter two might want something short which is not quite unique; for 79938fd1498Szrj that reason, we may have a disambiguating prefix, followed by a space 80038fd1498Szrj to mark the start of the following dump file name / option string. */ 80138fd1498Szrj name = strchr (pass->name, ' '); 80238fd1498Szrj name = name ? name + 1 : pass->name; 80338fd1498Szrj dot_name = concat (".", name, num, NULL); 80438fd1498Szrj if (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS) 80538fd1498Szrj { 80638fd1498Szrj prefix = "ipa-"; 80738fd1498Szrj dkind = DK_ipa; 80838fd1498Szrj optgroup_flags |= OPTGROUP_IPA; 80938fd1498Szrj } 81038fd1498Szrj else if (pass->type == GIMPLE_PASS) 81138fd1498Szrj { 81238fd1498Szrj prefix = "tree-"; 81338fd1498Szrj dkind = DK_tree; 81438fd1498Szrj } 81538fd1498Szrj else 81638fd1498Szrj { 81738fd1498Szrj prefix = "rtl-"; 81838fd1498Szrj dkind = DK_rtl; 81938fd1498Szrj } 82038fd1498Szrj 82138fd1498Szrj flag_name = concat (prefix, name, num, NULL); 82238fd1498Szrj glob_name = concat (prefix, name, NULL); 82338fd1498Szrj optgroup_flags |= pass->optinfo_flags; 82438fd1498Szrj /* For any passes that do not have an optgroup set, and which are not 82538fd1498Szrj IPA passes setup above, set the optgroup to OPTGROUP_OTHER so that 82638fd1498Szrj any dump messages are emitted properly under -fopt-info(-optall). */ 82738fd1498Szrj if (optgroup_flags == OPTGROUP_NONE) 82838fd1498Szrj optgroup_flags = OPTGROUP_OTHER; 82938fd1498Szrj id = dumps->dump_register (dot_name, flag_name, glob_name, dkind, 83038fd1498Szrj optgroup_flags, 83138fd1498Szrj true); 83238fd1498Szrj set_pass_for_id (id, pass); 83338fd1498Szrj full_name = concat (prefix, pass->name, num, NULL); 83438fd1498Szrj register_pass_name (pass, full_name); 83538fd1498Szrj free (CONST_CAST (char *, full_name)); 83638fd1498Szrj } 83738fd1498Szrj 83838fd1498Szrj /* Register the dump files for the pass_manager starting at PASS. */ 83938fd1498Szrj 84038fd1498Szrj void 84138fd1498Szrj pass_manager::register_dump_files (opt_pass *pass) 84238fd1498Szrj { 84338fd1498Szrj do 84438fd1498Szrj { 84538fd1498Szrj if (pass->name && pass->name[0] != '*') 84638fd1498Szrj register_one_dump_file (pass); 84738fd1498Szrj 84838fd1498Szrj if (pass->sub) 84938fd1498Szrj register_dump_files (pass->sub); 85038fd1498Szrj 85138fd1498Szrj pass = pass->next; 85238fd1498Szrj } 85338fd1498Szrj while (pass); 85438fd1498Szrj } 85538fd1498Szrj 85638fd1498Szrj /* Register PASS with NAME. */ 85738fd1498Szrj 85838fd1498Szrj void 85938fd1498Szrj pass_manager::register_pass_name (opt_pass *pass, const char *name) 86038fd1498Szrj { 86138fd1498Szrj if (!m_name_to_pass_map) 86238fd1498Szrj m_name_to_pass_map = new hash_map<nofree_string_hash, opt_pass *> (256); 86338fd1498Szrj 86438fd1498Szrj if (m_name_to_pass_map->get (name)) 86538fd1498Szrj return; /* Ignore plugin passes. */ 86638fd1498Szrj 86738fd1498Szrj const char *unique_name = xstrdup (name); 86838fd1498Szrj m_name_to_pass_map->put (unique_name, pass); 86938fd1498Szrj } 87038fd1498Szrj 87138fd1498Szrj /* Map from pass id to canonicalized pass name. */ 87238fd1498Szrj 87338fd1498Szrj typedef const char *char_ptr; 87438fd1498Szrj static vec<char_ptr> pass_tab; 87538fd1498Szrj 87638fd1498Szrj /* Callback function for traversing NAME_TO_PASS_MAP. */ 87738fd1498Szrj 87838fd1498Szrj bool 87938fd1498Szrj passes_pass_traverse (const char *const &name, opt_pass *const &pass, void *) 88038fd1498Szrj { 88138fd1498Szrj gcc_assert (pass->static_pass_number > 0); 88238fd1498Szrj gcc_assert (pass_tab.exists ()); 88338fd1498Szrj 88438fd1498Szrj pass_tab[pass->static_pass_number] = name; 88538fd1498Szrj 88638fd1498Szrj return 1; 88738fd1498Szrj } 88838fd1498Szrj 88938fd1498Szrj /* The function traverses NAME_TO_PASS_MAP and creates a pass info 89038fd1498Szrj table for dumping purpose. */ 89138fd1498Szrj 89238fd1498Szrj void 89338fd1498Szrj pass_manager::create_pass_tab (void) const 89438fd1498Szrj { 89538fd1498Szrj if (!flag_dump_passes) 89638fd1498Szrj return; 89738fd1498Szrj 89838fd1498Szrj pass_tab.safe_grow_cleared (passes_by_id_size + 1); 89938fd1498Szrj m_name_to_pass_map->traverse <void *, passes_pass_traverse> (NULL); 90038fd1498Szrj } 90138fd1498Szrj 90238fd1498Szrj static bool override_gate_status (opt_pass *, tree, bool); 90338fd1498Szrj 90438fd1498Szrj /* Dump the instantiated name for PASS. IS_ON indicates if PASS 90538fd1498Szrj is turned on or not. */ 90638fd1498Szrj 90738fd1498Szrj static void 90838fd1498Szrj dump_one_pass (opt_pass *pass, int pass_indent) 90938fd1498Szrj { 91038fd1498Szrj int indent = 3 * pass_indent; 91138fd1498Szrj const char *pn; 91238fd1498Szrj bool is_on, is_really_on; 91338fd1498Szrj 91438fd1498Szrj is_on = pass->gate (cfun); 91538fd1498Szrj is_really_on = override_gate_status (pass, current_function_decl, is_on); 91638fd1498Szrj 91738fd1498Szrj if (pass->static_pass_number <= 0) 91838fd1498Szrj pn = pass->name; 91938fd1498Szrj else 92038fd1498Szrj pn = pass_tab[pass->static_pass_number]; 92138fd1498Szrj 92238fd1498Szrj fprintf (stderr, "%*s%-40s%*s:%s%s\n", indent, " ", pn, 92338fd1498Szrj (15 - indent < 0 ? 0 : 15 - indent), " ", 92438fd1498Szrj is_on ? " ON" : " OFF", 92538fd1498Szrj ((!is_on) == (!is_really_on) ? "" 92638fd1498Szrj : (is_really_on ? " (FORCED_ON)" : " (FORCED_OFF)"))); 92738fd1498Szrj } 92838fd1498Szrj 92938fd1498Szrj /* Dump pass list PASS with indentation INDENT. */ 93038fd1498Szrj 93138fd1498Szrj static void 93238fd1498Szrj dump_pass_list (opt_pass *pass, int indent) 93338fd1498Szrj { 93438fd1498Szrj do 93538fd1498Szrj { 93638fd1498Szrj dump_one_pass (pass, indent); 93738fd1498Szrj if (pass->sub) 93838fd1498Szrj dump_pass_list (pass->sub, indent + 1); 93938fd1498Szrj pass = pass->next; 94038fd1498Szrj } 94138fd1498Szrj while (pass); 94238fd1498Szrj } 94338fd1498Szrj 94438fd1498Szrj /* Dump all optimization passes. */ 94538fd1498Szrj 94638fd1498Szrj void 94738fd1498Szrj dump_passes (void) 94838fd1498Szrj { 94938fd1498Szrj g->get_passes ()->dump_passes (); 95038fd1498Szrj } 95138fd1498Szrj 95238fd1498Szrj void 95338fd1498Szrj pass_manager::dump_passes () const 95438fd1498Szrj { 95538fd1498Szrj push_dummy_function (true); 95638fd1498Szrj 95738fd1498Szrj create_pass_tab (); 95838fd1498Szrj 95938fd1498Szrj dump_pass_list (all_lowering_passes, 1); 96038fd1498Szrj dump_pass_list (all_small_ipa_passes, 1); 96138fd1498Szrj dump_pass_list (all_regular_ipa_passes, 1); 96238fd1498Szrj dump_pass_list (all_late_ipa_passes, 1); 96338fd1498Szrj dump_pass_list (all_passes, 1); 96438fd1498Szrj 96538fd1498Szrj pop_dummy_function (); 96638fd1498Szrj } 96738fd1498Szrj 96838fd1498Szrj /* Returns the pass with NAME. */ 96938fd1498Szrj 97038fd1498Szrj opt_pass * 97138fd1498Szrj pass_manager::get_pass_by_name (const char *name) 97238fd1498Szrj { 97338fd1498Szrj opt_pass **p = m_name_to_pass_map->get (name); 97438fd1498Szrj if (p) 97538fd1498Szrj return *p; 97638fd1498Szrj 97738fd1498Szrj return NULL; 97838fd1498Szrj } 97938fd1498Szrj 98038fd1498Szrj 98138fd1498Szrj /* Range [start, last]. */ 98238fd1498Szrj 98338fd1498Szrj struct uid_range 98438fd1498Szrj { 98538fd1498Szrj unsigned int start; 98638fd1498Szrj unsigned int last; 98738fd1498Szrj const char *assem_name; 98838fd1498Szrj struct uid_range *next; 98938fd1498Szrj }; 99038fd1498Szrj 99138fd1498Szrj typedef struct uid_range *uid_range_p; 99238fd1498Szrj 99338fd1498Szrj 99438fd1498Szrj static vec<uid_range_p> enabled_pass_uid_range_tab; 99538fd1498Szrj static vec<uid_range_p> disabled_pass_uid_range_tab; 99638fd1498Szrj 99738fd1498Szrj 99838fd1498Szrj /* Parse option string for -fdisable- and -fenable- 99938fd1498Szrj The syntax of the options: 100038fd1498Szrj 100138fd1498Szrj -fenable-<pass_name> 100238fd1498Szrj -fdisable-<pass_name> 100338fd1498Szrj 100438fd1498Szrj -fenable-<pass_name>=s1:e1,s2:e2,... 100538fd1498Szrj -fdisable-<pass_name>=s1:e1,s2:e2,... 100638fd1498Szrj */ 100738fd1498Szrj 100838fd1498Szrj static void 100938fd1498Szrj enable_disable_pass (const char *arg, bool is_enable) 101038fd1498Szrj { 101138fd1498Szrj opt_pass *pass; 101238fd1498Szrj char *range_str, *phase_name; 101338fd1498Szrj char *argstr = xstrdup (arg); 101438fd1498Szrj vec<uid_range_p> *tab = 0; 101538fd1498Szrj 101638fd1498Szrj range_str = strchr (argstr,'='); 101738fd1498Szrj if (range_str) 101838fd1498Szrj { 101938fd1498Szrj *range_str = '\0'; 102038fd1498Szrj range_str++; 102138fd1498Szrj } 102238fd1498Szrj 102338fd1498Szrj phase_name = argstr; 102438fd1498Szrj if (!*phase_name) 102538fd1498Szrj { 102638fd1498Szrj if (is_enable) 102738fd1498Szrj error ("unrecognized option -fenable"); 102838fd1498Szrj else 102938fd1498Szrj error ("unrecognized option -fdisable"); 103038fd1498Szrj free (argstr); 103138fd1498Szrj return; 103238fd1498Szrj } 103338fd1498Szrj pass = g->get_passes ()->get_pass_by_name (phase_name); 103438fd1498Szrj if (!pass || pass->static_pass_number == -1) 103538fd1498Szrj { 103638fd1498Szrj if (is_enable) 103738fd1498Szrj error ("unknown pass %s specified in -fenable", phase_name); 103838fd1498Szrj else 103938fd1498Szrj error ("unknown pass %s specified in -fdisable", phase_name); 104038fd1498Szrj free (argstr); 104138fd1498Szrj return; 104238fd1498Szrj } 104338fd1498Szrj 104438fd1498Szrj if (is_enable) 104538fd1498Szrj tab = &enabled_pass_uid_range_tab; 104638fd1498Szrj else 104738fd1498Szrj tab = &disabled_pass_uid_range_tab; 104838fd1498Szrj 104938fd1498Szrj if ((unsigned) pass->static_pass_number >= tab->length ()) 105038fd1498Szrj tab->safe_grow_cleared (pass->static_pass_number + 1); 105138fd1498Szrj 105238fd1498Szrj if (!range_str) 105338fd1498Szrj { 105438fd1498Szrj uid_range_p slot; 105538fd1498Szrj uid_range_p new_range = XCNEW (struct uid_range); 105638fd1498Szrj 105738fd1498Szrj new_range->start = 0; 105838fd1498Szrj new_range->last = (unsigned)-1; 105938fd1498Szrj 106038fd1498Szrj slot = (*tab)[pass->static_pass_number]; 106138fd1498Szrj new_range->next = slot; 106238fd1498Szrj (*tab)[pass->static_pass_number] = new_range; 106338fd1498Szrj if (is_enable) 106438fd1498Szrj inform (UNKNOWN_LOCATION, "enable pass %s for functions in the range " 106538fd1498Szrj "of [%u, %u]", phase_name, new_range->start, new_range->last); 106638fd1498Szrj else 106738fd1498Szrj inform (UNKNOWN_LOCATION, "disable pass %s for functions in the range " 106838fd1498Szrj "of [%u, %u]", phase_name, new_range->start, new_range->last); 106938fd1498Szrj } 107038fd1498Szrj else 107138fd1498Szrj { 107238fd1498Szrj char *next_range = NULL; 107338fd1498Szrj char *one_range = range_str; 107438fd1498Szrj char *end_val = NULL; 107538fd1498Szrj 107638fd1498Szrj do 107738fd1498Szrj { 107838fd1498Szrj uid_range_p slot; 107938fd1498Szrj uid_range_p new_range; 108038fd1498Szrj char *invalid = NULL; 108138fd1498Szrj long start; 108238fd1498Szrj char *func_name = NULL; 108338fd1498Szrj 108438fd1498Szrj next_range = strchr (one_range, ','); 108538fd1498Szrj if (next_range) 108638fd1498Szrj { 108738fd1498Szrj *next_range = '\0'; 108838fd1498Szrj next_range++; 108938fd1498Szrj } 109038fd1498Szrj 109138fd1498Szrj end_val = strchr (one_range, ':'); 109238fd1498Szrj if (end_val) 109338fd1498Szrj { 109438fd1498Szrj *end_val = '\0'; 109538fd1498Szrj end_val++; 109638fd1498Szrj } 109738fd1498Szrj start = strtol (one_range, &invalid, 10); 109838fd1498Szrj if (*invalid || start < 0) 109938fd1498Szrj { 110038fd1498Szrj if (end_val || (one_range[0] >= '0' 110138fd1498Szrj && one_range[0] <= '9')) 110238fd1498Szrj { 110338fd1498Szrj error ("Invalid range %s in option %s", 110438fd1498Szrj one_range, 110538fd1498Szrj is_enable ? "-fenable" : "-fdisable"); 110638fd1498Szrj free (argstr); 110738fd1498Szrj return; 110838fd1498Szrj } 110938fd1498Szrj func_name = one_range; 111038fd1498Szrj } 111138fd1498Szrj if (!end_val) 111238fd1498Szrj { 111338fd1498Szrj new_range = XCNEW (struct uid_range); 111438fd1498Szrj if (!func_name) 111538fd1498Szrj { 111638fd1498Szrj new_range->start = (unsigned) start; 111738fd1498Szrj new_range->last = (unsigned) start; 111838fd1498Szrj } 111938fd1498Szrj else 112038fd1498Szrj { 112138fd1498Szrj new_range->start = (unsigned) -1; 112238fd1498Szrj new_range->last = (unsigned) -1; 112338fd1498Szrj new_range->assem_name = xstrdup (func_name); 112438fd1498Szrj } 112538fd1498Szrj } 112638fd1498Szrj else 112738fd1498Szrj { 112838fd1498Szrj long last = strtol (end_val, &invalid, 10); 112938fd1498Szrj if (*invalid || last < start) 113038fd1498Szrj { 113138fd1498Szrj error ("Invalid range %s in option %s", 113238fd1498Szrj end_val, 113338fd1498Szrj is_enable ? "-fenable" : "-fdisable"); 113438fd1498Szrj free (argstr); 113538fd1498Szrj return; 113638fd1498Szrj } 113738fd1498Szrj new_range = XCNEW (struct uid_range); 113838fd1498Szrj new_range->start = (unsigned) start; 113938fd1498Szrj new_range->last = (unsigned) last; 114038fd1498Szrj } 114138fd1498Szrj 114238fd1498Szrj slot = (*tab)[pass->static_pass_number]; 114338fd1498Szrj new_range->next = slot; 114438fd1498Szrj (*tab)[pass->static_pass_number] = new_range; 114538fd1498Szrj if (is_enable) 114638fd1498Szrj { 114738fd1498Szrj if (new_range->assem_name) 114838fd1498Szrj inform (UNKNOWN_LOCATION, 114938fd1498Szrj "enable pass %s for function %s", 115038fd1498Szrj phase_name, new_range->assem_name); 115138fd1498Szrj else 115238fd1498Szrj inform (UNKNOWN_LOCATION, 115338fd1498Szrj "enable pass %s for functions in the range of [%u, %u]", 115438fd1498Szrj phase_name, new_range->start, new_range->last); 115538fd1498Szrj } 115638fd1498Szrj else 115738fd1498Szrj { 115838fd1498Szrj if (new_range->assem_name) 115938fd1498Szrj inform (UNKNOWN_LOCATION, 116038fd1498Szrj "disable pass %s for function %s", 116138fd1498Szrj phase_name, new_range->assem_name); 116238fd1498Szrj else 116338fd1498Szrj inform (UNKNOWN_LOCATION, 116438fd1498Szrj "disable pass %s for functions in the range of [%u, %u]", 116538fd1498Szrj phase_name, new_range->start, new_range->last); 116638fd1498Szrj } 116738fd1498Szrj 116838fd1498Szrj one_range = next_range; 116938fd1498Szrj } while (next_range); 117038fd1498Szrj } 117138fd1498Szrj 117238fd1498Szrj free (argstr); 117338fd1498Szrj } 117438fd1498Szrj 117538fd1498Szrj /* Enable pass specified by ARG. */ 117638fd1498Szrj 117738fd1498Szrj void 117838fd1498Szrj enable_pass (const char *arg) 117938fd1498Szrj { 118038fd1498Szrj enable_disable_pass (arg, true); 118138fd1498Szrj } 118238fd1498Szrj 118338fd1498Szrj /* Disable pass specified by ARG. */ 118438fd1498Szrj 118538fd1498Szrj void 118638fd1498Szrj disable_pass (const char *arg) 118738fd1498Szrj { 118838fd1498Szrj enable_disable_pass (arg, false); 118938fd1498Szrj } 119038fd1498Szrj 119138fd1498Szrj /* Returns true if PASS is explicitly enabled/disabled for FUNC. */ 119238fd1498Szrj 119338fd1498Szrj static bool 119438fd1498Szrj is_pass_explicitly_enabled_or_disabled (opt_pass *pass, 119538fd1498Szrj tree func, 119638fd1498Szrj vec<uid_range_p> tab) 119738fd1498Szrj { 119838fd1498Szrj uid_range_p slot, range; 119938fd1498Szrj int cgraph_uid; 120038fd1498Szrj const char *aname = NULL; 120138fd1498Szrj 120238fd1498Szrj if (!tab.exists () 120338fd1498Szrj || (unsigned) pass->static_pass_number >= tab.length () 120438fd1498Szrj || pass->static_pass_number == -1) 120538fd1498Szrj return false; 120638fd1498Szrj 120738fd1498Szrj slot = tab[pass->static_pass_number]; 120838fd1498Szrj if (!slot) 120938fd1498Szrj return false; 121038fd1498Szrj 121138fd1498Szrj cgraph_uid = func ? cgraph_node::get (func)->uid : 0; 121238fd1498Szrj if (func && DECL_ASSEMBLER_NAME_SET_P (func)) 121338fd1498Szrj aname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (func)); 121438fd1498Szrj 121538fd1498Szrj range = slot; 121638fd1498Szrj while (range) 121738fd1498Szrj { 121838fd1498Szrj if ((unsigned) cgraph_uid >= range->start 121938fd1498Szrj && (unsigned) cgraph_uid <= range->last) 122038fd1498Szrj return true; 122138fd1498Szrj if (range->assem_name && aname 122238fd1498Szrj && !strcmp (range->assem_name, aname)) 122338fd1498Szrj return true; 122438fd1498Szrj range = range->next; 122538fd1498Szrj } 122638fd1498Szrj 122738fd1498Szrj return false; 122838fd1498Szrj } 122938fd1498Szrj 123038fd1498Szrj 123138fd1498Szrj /* Update static_pass_number for passes (and the flag 123238fd1498Szrj TODO_mark_first_instance). 123338fd1498Szrj 123438fd1498Szrj Passes are constructed with static_pass_number preinitialized to 0 123538fd1498Szrj 123638fd1498Szrj This field is used in two different ways: initially as instance numbers 123738fd1498Szrj of their kind, and then as ids within the entire pass manager. 123838fd1498Szrj 123938fd1498Szrj Within pass_manager::pass_manager: 124038fd1498Szrj 124138fd1498Szrj * In add_pass_instance(), as called by next_pass_1 in 124238fd1498Szrj NEXT_PASS in init_optimization_passes 124338fd1498Szrj 124438fd1498Szrj * When the initial instance of a pass within a pass manager is seen, 124538fd1498Szrj it is flagged, and its static_pass_number is set to -1 124638fd1498Szrj 124738fd1498Szrj * On subsequent times that it is seen, the static pass number 124838fd1498Szrj is decremented each time, so that if there are e.g. 4 dups, 124938fd1498Szrj they have static_pass_number -4, 2, 3, 4 respectively (note 125038fd1498Szrj how the initial one is negative and gives the count); these 125138fd1498Szrj can be thought of as instance numbers of the specific pass 125238fd1498Szrj 125338fd1498Szrj * Within the register_dump_files () traversal, set_pass_for_id() 125438fd1498Szrj is called on each pass, using these instance numbers to create 125538fd1498Szrj dumpfile switches, and then overwriting them with a pass id, 125638fd1498Szrj which are global to the whole pass manager (based on 125738fd1498Szrj (TDI_end + current value of extra_dump_files_in_use) ) */ 125838fd1498Szrj 125938fd1498Szrj static void 126038fd1498Szrj add_pass_instance (opt_pass *new_pass, bool track_duplicates, 126138fd1498Szrj opt_pass *initial_pass) 126238fd1498Szrj { 126338fd1498Szrj /* Are we dealing with the first pass of its kind, or a clone? */ 126438fd1498Szrj if (new_pass != initial_pass) 126538fd1498Szrj { 126638fd1498Szrj /* We're dealing with a clone. */ 126738fd1498Szrj new_pass->todo_flags_start &= ~TODO_mark_first_instance; 126838fd1498Szrj 126938fd1498Szrj /* Indicate to register_dump_files that this pass has duplicates, 127038fd1498Szrj and so it should rename the dump file. The first instance will 127138fd1498Szrj be -1, and be number of duplicates = -static_pass_number - 1. 127238fd1498Szrj Subsequent instances will be > 0 and just the duplicate number. */ 127338fd1498Szrj if ((new_pass->name && new_pass->name[0] != '*') || track_duplicates) 127438fd1498Szrj { 127538fd1498Szrj initial_pass->static_pass_number -= 1; 127638fd1498Szrj new_pass->static_pass_number = -initial_pass->static_pass_number; 127738fd1498Szrj } 127838fd1498Szrj } 127938fd1498Szrj else 128038fd1498Szrj { 128138fd1498Szrj /* We're dealing with the first pass of its kind. */ 128238fd1498Szrj new_pass->todo_flags_start |= TODO_mark_first_instance; 128338fd1498Szrj new_pass->static_pass_number = -1; 128438fd1498Szrj 128538fd1498Szrj invoke_plugin_callbacks (PLUGIN_NEW_PASS, new_pass); 128638fd1498Szrj } 128738fd1498Szrj } 128838fd1498Szrj 128938fd1498Szrj /* Add a pass to the pass list. Duplicate the pass if it's already 129038fd1498Szrj in the list. */ 129138fd1498Szrj 129238fd1498Szrj static opt_pass ** 129338fd1498Szrj next_pass_1 (opt_pass **list, opt_pass *pass, opt_pass *initial_pass) 129438fd1498Szrj { 129538fd1498Szrj /* Every pass should have a name so that plugins can refer to them. */ 129638fd1498Szrj gcc_assert (pass->name != NULL); 129738fd1498Szrj 129838fd1498Szrj add_pass_instance (pass, false, initial_pass); 129938fd1498Szrj *list = pass; 130038fd1498Szrj 130138fd1498Szrj return &(*list)->next; 130238fd1498Szrj } 130338fd1498Szrj 130438fd1498Szrj /* List node for an inserted pass instance. We need to keep track of all 130538fd1498Szrj the newly-added pass instances (with 'added_pass_nodes' defined below) 130638fd1498Szrj so that we can register their dump files after pass-positioning is finished. 130738fd1498Szrj Registering dumping files needs to be post-processed or the 130838fd1498Szrj static_pass_number of the opt_pass object would be modified and mess up 130938fd1498Szrj the dump file names of future pass instances to be added. */ 131038fd1498Szrj 131138fd1498Szrj struct pass_list_node 131238fd1498Szrj { 131338fd1498Szrj opt_pass *pass; 131438fd1498Szrj struct pass_list_node *next; 131538fd1498Szrj }; 131638fd1498Szrj 131738fd1498Szrj static struct pass_list_node *added_pass_nodes = NULL; 131838fd1498Szrj static struct pass_list_node *prev_added_pass_node; 131938fd1498Szrj 132038fd1498Szrj /* Insert the pass at the proper position. Return true if the pass 132138fd1498Szrj is successfully added. 132238fd1498Szrj 132338fd1498Szrj NEW_PASS_INFO - new pass to be inserted 132438fd1498Szrj PASS_LIST - root of the pass list to insert the new pass to */ 132538fd1498Szrj 132638fd1498Szrj static bool 132738fd1498Szrj position_pass (struct register_pass_info *new_pass_info, opt_pass **pass_list) 132838fd1498Szrj { 132938fd1498Szrj opt_pass *pass = *pass_list, *prev_pass = NULL; 133038fd1498Szrj bool success = false; 133138fd1498Szrj 133238fd1498Szrj for ( ; pass; prev_pass = pass, pass = pass->next) 133338fd1498Szrj { 133438fd1498Szrj /* Check if the current pass is of the same type as the new pass and 133538fd1498Szrj matches the name and the instance number of the reference pass. */ 133638fd1498Szrj if (pass->type == new_pass_info->pass->type 133738fd1498Szrj && pass->name 133838fd1498Szrj && !strcmp (pass->name, new_pass_info->reference_pass_name) 133938fd1498Szrj && ((new_pass_info->ref_pass_instance_number == 0) 134038fd1498Szrj || (new_pass_info->ref_pass_instance_number == 134138fd1498Szrj pass->static_pass_number) 134238fd1498Szrj || (new_pass_info->ref_pass_instance_number == 1 134338fd1498Szrj && pass->todo_flags_start & TODO_mark_first_instance))) 134438fd1498Szrj { 134538fd1498Szrj opt_pass *new_pass; 134638fd1498Szrj struct pass_list_node *new_pass_node; 134738fd1498Szrj 134838fd1498Szrj if (new_pass_info->ref_pass_instance_number == 0) 134938fd1498Szrj { 135038fd1498Szrj new_pass = new_pass_info->pass->clone (); 135138fd1498Szrj add_pass_instance (new_pass, true, new_pass_info->pass); 135238fd1498Szrj } 135338fd1498Szrj else 135438fd1498Szrj { 135538fd1498Szrj new_pass = new_pass_info->pass; 135638fd1498Szrj add_pass_instance (new_pass, true, new_pass); 135738fd1498Szrj } 135838fd1498Szrj 135938fd1498Szrj /* Insert the new pass instance based on the positioning op. */ 136038fd1498Szrj switch (new_pass_info->pos_op) 136138fd1498Szrj { 136238fd1498Szrj case PASS_POS_INSERT_AFTER: 136338fd1498Szrj new_pass->next = pass->next; 136438fd1498Szrj pass->next = new_pass; 136538fd1498Szrj 136638fd1498Szrj /* Skip newly inserted pass to avoid repeated 136738fd1498Szrj insertions in the case where the new pass and the 136838fd1498Szrj existing one have the same name. */ 136938fd1498Szrj pass = new_pass; 137038fd1498Szrj break; 137138fd1498Szrj case PASS_POS_INSERT_BEFORE: 137238fd1498Szrj new_pass->next = pass; 137338fd1498Szrj if (prev_pass) 137438fd1498Szrj prev_pass->next = new_pass; 137538fd1498Szrj else 137638fd1498Szrj *pass_list = new_pass; 137738fd1498Szrj break; 137838fd1498Szrj case PASS_POS_REPLACE: 137938fd1498Szrj new_pass->next = pass->next; 138038fd1498Szrj if (prev_pass) 138138fd1498Szrj prev_pass->next = new_pass; 138238fd1498Szrj else 138338fd1498Szrj *pass_list = new_pass; 138438fd1498Szrj new_pass->sub = pass->sub; 138538fd1498Szrj new_pass->tv_id = pass->tv_id; 138638fd1498Szrj pass = new_pass; 138738fd1498Szrj break; 138838fd1498Szrj default: 138938fd1498Szrj error ("invalid pass positioning operation"); 139038fd1498Szrj return false; 139138fd1498Szrj } 139238fd1498Szrj 139338fd1498Szrj /* Save the newly added pass (instance) in the added_pass_nodes 139438fd1498Szrj list so that we can register its dump file later. Note that 139538fd1498Szrj we cannot register the dump file now because doing so will modify 139638fd1498Szrj the static_pass_number of the opt_pass object and therefore 139738fd1498Szrj mess up the dump file name of future instances. */ 139838fd1498Szrj new_pass_node = XCNEW (struct pass_list_node); 139938fd1498Szrj new_pass_node->pass = new_pass; 140038fd1498Szrj if (!added_pass_nodes) 140138fd1498Szrj added_pass_nodes = new_pass_node; 140238fd1498Szrj else 140338fd1498Szrj prev_added_pass_node->next = new_pass_node; 140438fd1498Szrj prev_added_pass_node = new_pass_node; 140538fd1498Szrj 140638fd1498Szrj success = true; 140738fd1498Szrj } 140838fd1498Szrj 140938fd1498Szrj if (pass->sub && position_pass (new_pass_info, &pass->sub)) 141038fd1498Szrj success = true; 141138fd1498Szrj } 141238fd1498Szrj 141338fd1498Szrj return success; 141438fd1498Szrj } 141538fd1498Szrj 141638fd1498Szrj /* Hooks a new pass into the pass lists. 141738fd1498Szrj 141838fd1498Szrj PASS_INFO - pass information that specifies the opt_pass object, 141938fd1498Szrj reference pass, instance number, and how to position 142038fd1498Szrj the pass */ 142138fd1498Szrj 142238fd1498Szrj void 142338fd1498Szrj register_pass (struct register_pass_info *pass_info) 142438fd1498Szrj { 142538fd1498Szrj g->get_passes ()->register_pass (pass_info); 142638fd1498Szrj } 142738fd1498Szrj 142838fd1498Szrj void 142938fd1498Szrj register_pass (opt_pass* pass, pass_positioning_ops pos, 143038fd1498Szrj const char* ref_pass_name, int ref_pass_inst_number) 143138fd1498Szrj { 143238fd1498Szrj register_pass_info i; 143338fd1498Szrj i.pass = pass; 143438fd1498Szrj i.reference_pass_name = ref_pass_name; 143538fd1498Szrj i.ref_pass_instance_number = ref_pass_inst_number; 143638fd1498Szrj i.pos_op = pos; 143738fd1498Szrj 143838fd1498Szrj g->get_passes ()->register_pass (&i); 143938fd1498Szrj } 144038fd1498Szrj 144138fd1498Szrj void 144238fd1498Szrj pass_manager::register_pass (struct register_pass_info *pass_info) 144338fd1498Szrj { 144438fd1498Szrj bool all_instances, success; 144538fd1498Szrj gcc::dump_manager *dumps = m_ctxt->get_dumps (); 144638fd1498Szrj 144738fd1498Szrj /* The checks below could fail in buggy plugins. Existing GCC 144838fd1498Szrj passes should never fail these checks, so we mention plugin in 144938fd1498Szrj the messages. */ 145038fd1498Szrj if (!pass_info->pass) 145138fd1498Szrj fatal_error (input_location, "plugin cannot register a missing pass"); 145238fd1498Szrj 145338fd1498Szrj if (!pass_info->pass->name) 145438fd1498Szrj fatal_error (input_location, "plugin cannot register an unnamed pass"); 145538fd1498Szrj 145638fd1498Szrj if (!pass_info->reference_pass_name) 145738fd1498Szrj fatal_error 145838fd1498Szrj (input_location, 145938fd1498Szrj "plugin cannot register pass %qs without reference pass name", 146038fd1498Szrj pass_info->pass->name); 146138fd1498Szrj 146238fd1498Szrj /* Try to insert the new pass to the pass lists. We need to check 146338fd1498Szrj all five lists as the reference pass could be in one (or all) of 146438fd1498Szrj them. */ 146538fd1498Szrj all_instances = pass_info->ref_pass_instance_number == 0; 146638fd1498Szrj success = position_pass (pass_info, &all_lowering_passes); 146738fd1498Szrj if (!success || all_instances) 146838fd1498Szrj success |= position_pass (pass_info, &all_small_ipa_passes); 146938fd1498Szrj if (!success || all_instances) 147038fd1498Szrj success |= position_pass (pass_info, &all_regular_ipa_passes); 147138fd1498Szrj if (!success || all_instances) 147238fd1498Szrj success |= position_pass (pass_info, &all_late_ipa_passes); 147338fd1498Szrj if (!success || all_instances) 147438fd1498Szrj success |= position_pass (pass_info, &all_passes); 147538fd1498Szrj if (!success) 147638fd1498Szrj fatal_error 147738fd1498Szrj (input_location, 147838fd1498Szrj "pass %qs not found but is referenced by new pass %qs", 147938fd1498Szrj pass_info->reference_pass_name, pass_info->pass->name); 148038fd1498Szrj 148138fd1498Szrj /* OK, we have successfully inserted the new pass. We need to register 148238fd1498Szrj the dump files for the newly added pass and its duplicates (if any). 148338fd1498Szrj Because the registration of plugin/backend passes happens after the 148438fd1498Szrj command-line options are parsed, the options that specify single 148538fd1498Szrj pass dumping (e.g. -fdump-tree-PASSNAME) cannot be used for new 148638fd1498Szrj passes. Therefore we currently can only enable dumping of 148738fd1498Szrj new passes when the 'dump-all' flags (e.g. -fdump-tree-all) 148838fd1498Szrj are specified. While doing so, we also delete the pass_list_node 148938fd1498Szrj objects created during pass positioning. */ 149038fd1498Szrj while (added_pass_nodes) 149138fd1498Szrj { 149238fd1498Szrj struct pass_list_node *next_node = added_pass_nodes->next; 149338fd1498Szrj enum tree_dump_index tdi; 149438fd1498Szrj register_one_dump_file (added_pass_nodes->pass); 149538fd1498Szrj if (added_pass_nodes->pass->type == SIMPLE_IPA_PASS 149638fd1498Szrj || added_pass_nodes->pass->type == IPA_PASS) 149738fd1498Szrj tdi = TDI_ipa_all; 149838fd1498Szrj else if (added_pass_nodes->pass->type == GIMPLE_PASS) 149938fd1498Szrj tdi = TDI_tree_all; 150038fd1498Szrj else 150138fd1498Szrj tdi = TDI_rtl_all; 150238fd1498Szrj /* Check if dump-all flag is specified. */ 150338fd1498Szrj if (dumps->get_dump_file_info (tdi)->pstate) 150438fd1498Szrj { 150538fd1498Szrj dumps->get_dump_file_info (added_pass_nodes->pass->static_pass_number) 150638fd1498Szrj ->pstate = dumps->get_dump_file_info (tdi)->pstate; 150738fd1498Szrj dumps->get_dump_file_info (added_pass_nodes->pass->static_pass_number) 150838fd1498Szrj ->pflags = dumps->get_dump_file_info (tdi)->pflags; 150938fd1498Szrj } 151038fd1498Szrj XDELETE (added_pass_nodes); 151138fd1498Szrj added_pass_nodes = next_node; 151238fd1498Szrj } 151338fd1498Szrj } 151438fd1498Szrj 151538fd1498Szrj /* Construct the pass tree. The sequencing of passes is driven by 151638fd1498Szrj the cgraph routines: 151738fd1498Szrj 151838fd1498Szrj finalize_compilation_unit () 151938fd1498Szrj for each node N in the cgraph 152038fd1498Szrj cgraph_analyze_function (N) 152138fd1498Szrj cgraph_lower_function (N) -> all_lowering_passes 152238fd1498Szrj 152338fd1498Szrj If we are optimizing, compile is then invoked: 152438fd1498Szrj 152538fd1498Szrj compile () 152638fd1498Szrj ipa_passes () -> all_small_ipa_passes 152738fd1498Szrj -> Analysis of all_regular_ipa_passes 152838fd1498Szrj * possible LTO streaming at copmilation time * 152938fd1498Szrj -> Execution of all_regular_ipa_passes 153038fd1498Szrj * possible LTO streaming at link time * 153138fd1498Szrj -> all_late_ipa_passes 153238fd1498Szrj expand_all_functions () 153338fd1498Szrj for each node N in the cgraph 153438fd1498Szrj expand_function (N) -> Transformation of all_regular_ipa_passes 153538fd1498Szrj -> all_passes 153638fd1498Szrj */ 153738fd1498Szrj 153838fd1498Szrj pass_manager::pass_manager (context *ctxt) 153938fd1498Szrj : all_passes (NULL), all_small_ipa_passes (NULL), all_lowering_passes (NULL), 154038fd1498Szrj all_regular_ipa_passes (NULL), 154138fd1498Szrj all_late_ipa_passes (NULL), passes_by_id (NULL), passes_by_id_size (0), 154238fd1498Szrj m_ctxt (ctxt), m_name_to_pass_map (NULL) 154338fd1498Szrj { 154438fd1498Szrj opt_pass **p; 154538fd1498Szrj 154638fd1498Szrj /* Zero-initialize pass members. */ 154738fd1498Szrj #define INSERT_PASSES_AFTER(PASS) 154838fd1498Szrj #define PUSH_INSERT_PASSES_WITHIN(PASS) 154938fd1498Szrj #define POP_INSERT_PASSES() 155038fd1498Szrj #define NEXT_PASS(PASS, NUM) PASS ## _ ## NUM = NULL 155138fd1498Szrj #define NEXT_PASS_WITH_ARG(PASS, NUM, ARG) NEXT_PASS (PASS, NUM) 155238fd1498Szrj #define TERMINATE_PASS_LIST(PASS) 155338fd1498Szrj #include "pass-instances.def" 155438fd1498Szrj #undef INSERT_PASSES_AFTER 155538fd1498Szrj #undef PUSH_INSERT_PASSES_WITHIN 155638fd1498Szrj #undef POP_INSERT_PASSES 155738fd1498Szrj #undef NEXT_PASS 155838fd1498Szrj #undef NEXT_PASS_WITH_ARG 155938fd1498Szrj #undef TERMINATE_PASS_LIST 156038fd1498Szrj 156138fd1498Szrj /* Initialize the pass_lists array. */ 156238fd1498Szrj #define DEF_PASS_LIST(LIST) pass_lists[PASS_LIST_NO_##LIST] = &LIST; 156338fd1498Szrj GCC_PASS_LISTS 156438fd1498Szrj #undef DEF_PASS_LIST 156538fd1498Szrj 156638fd1498Szrj /* Build the tree of passes. */ 156738fd1498Szrj 156838fd1498Szrj #define INSERT_PASSES_AFTER(PASS) \ 156938fd1498Szrj { \ 157038fd1498Szrj opt_pass **p_start; \ 157138fd1498Szrj p_start = p = &(PASS); 157238fd1498Szrj 157338fd1498Szrj #define TERMINATE_PASS_LIST(PASS) \ 157438fd1498Szrj gcc_assert (p_start == &PASS); \ 157538fd1498Szrj *p = NULL; \ 157638fd1498Szrj } 157738fd1498Szrj 157838fd1498Szrj #define PUSH_INSERT_PASSES_WITHIN(PASS) \ 157938fd1498Szrj { \ 158038fd1498Szrj opt_pass **p = &(PASS ## _1)->sub; 158138fd1498Szrj 158238fd1498Szrj #define POP_INSERT_PASSES() \ 158338fd1498Szrj } 158438fd1498Szrj 158538fd1498Szrj #define NEXT_PASS(PASS, NUM) \ 158638fd1498Szrj do { \ 158738fd1498Szrj gcc_assert (PASS ## _ ## NUM == NULL); \ 158838fd1498Szrj if ((NUM) == 1) \ 158938fd1498Szrj PASS ## _1 = make_##PASS (m_ctxt); \ 159038fd1498Szrj else \ 159138fd1498Szrj { \ 159238fd1498Szrj gcc_assert (PASS ## _1); \ 159338fd1498Szrj PASS ## _ ## NUM = PASS ## _1->clone (); \ 159438fd1498Szrj } \ 159538fd1498Szrj p = next_pass_1 (p, PASS ## _ ## NUM, PASS ## _1); \ 159638fd1498Szrj } while (0) 159738fd1498Szrj 159838fd1498Szrj #define NEXT_PASS_WITH_ARG(PASS, NUM, ARG) \ 159938fd1498Szrj do { \ 160038fd1498Szrj NEXT_PASS (PASS, NUM); \ 160138fd1498Szrj PASS ## _ ## NUM->set_pass_param (0, ARG); \ 160238fd1498Szrj } while (0) 160338fd1498Szrj 160438fd1498Szrj #include "pass-instances.def" 160538fd1498Szrj 160638fd1498Szrj #undef INSERT_PASSES_AFTER 160738fd1498Szrj #undef PUSH_INSERT_PASSES_WITHIN 160838fd1498Szrj #undef POP_INSERT_PASSES 160938fd1498Szrj #undef NEXT_PASS 161038fd1498Szrj #undef NEXT_PASS_WITH_ARG 161138fd1498Szrj #undef TERMINATE_PASS_LIST 161238fd1498Szrj 161338fd1498Szrj /* Register the passes with the tree dump code. */ 161438fd1498Szrj register_dump_files (all_lowering_passes); 161538fd1498Szrj register_dump_files (all_small_ipa_passes); 161638fd1498Szrj register_dump_files (all_regular_ipa_passes); 161738fd1498Szrj register_dump_files (all_late_ipa_passes); 161838fd1498Szrj register_dump_files (all_passes); 161938fd1498Szrj } 162038fd1498Szrj 162138fd1498Szrj static void 162238fd1498Szrj delete_pass_tree (opt_pass *pass) 162338fd1498Szrj { 162438fd1498Szrj while (pass) 162538fd1498Szrj { 162638fd1498Szrj /* Recurse into child passes. */ 162738fd1498Szrj delete_pass_tree (pass->sub); 162838fd1498Szrj 162938fd1498Szrj opt_pass *next = pass->next; 163038fd1498Szrj 163138fd1498Szrj /* Delete this pass. */ 163238fd1498Szrj delete pass; 163338fd1498Szrj 163438fd1498Szrj /* Iterate onto sibling passes. */ 163538fd1498Szrj pass = next; 163638fd1498Szrj } 163738fd1498Szrj } 163838fd1498Szrj 163938fd1498Szrj pass_manager::~pass_manager () 164038fd1498Szrj { 164138fd1498Szrj XDELETEVEC (passes_by_id); 164238fd1498Szrj 164338fd1498Szrj /* Call delete_pass_tree on each of the pass_lists. */ 164438fd1498Szrj #define DEF_PASS_LIST(LIST) \ 164538fd1498Szrj delete_pass_tree (*pass_lists[PASS_LIST_NO_##LIST]); 164638fd1498Szrj GCC_PASS_LISTS 164738fd1498Szrj #undef DEF_PASS_LIST 164838fd1498Szrj 164938fd1498Szrj } 165038fd1498Szrj 165138fd1498Szrj /* If we are in IPA mode (i.e., current_function_decl is NULL), call 165238fd1498Szrj function CALLBACK for every function in the call graph. Otherwise, 165338fd1498Szrj call CALLBACK on the current function. */ 165438fd1498Szrj 165538fd1498Szrj static void 165638fd1498Szrj do_per_function (void (*callback) (function *, void *data), void *data) 165738fd1498Szrj { 165838fd1498Szrj if (current_function_decl) 165938fd1498Szrj callback (cfun, data); 166038fd1498Szrj else 166138fd1498Szrj { 166238fd1498Szrj struct cgraph_node *node; 166338fd1498Szrj FOR_EACH_DEFINED_FUNCTION (node) 166438fd1498Szrj if (node->analyzed && (gimple_has_body_p (node->decl) && !in_lto_p) 166538fd1498Szrj && (!node->clone_of || node->decl != node->clone_of->decl)) 166638fd1498Szrj callback (DECL_STRUCT_FUNCTION (node->decl), data); 166738fd1498Szrj } 166838fd1498Szrj } 166938fd1498Szrj 167038fd1498Szrj /* Because inlining might remove no-longer reachable nodes, we need to 167138fd1498Szrj keep the array visible to garbage collector to avoid reading collected 167238fd1498Szrj out nodes. */ 167338fd1498Szrj static int nnodes; 167438fd1498Szrj static GTY ((length ("nnodes"))) cgraph_node **order; 167538fd1498Szrj 167638fd1498Szrj /* Hook called when NODE is removed and therefore should be 167738fd1498Szrj excluded from order vector. DATA is an array of integers. 167838fd1498Szrj DATA[0] holds max index it may be accessed by. For cgraph 167938fd1498Szrj node DATA[node->uid + 1] holds index of this node in order 168038fd1498Szrj vector. */ 168138fd1498Szrj static void 168238fd1498Szrj remove_cgraph_node_from_order (cgraph_node *node, void *data) 168338fd1498Szrj { 168438fd1498Szrj int *order_idx = (int *)data; 168538fd1498Szrj 168638fd1498Szrj if (node->uid >= order_idx[0]) 168738fd1498Szrj return; 168838fd1498Szrj 168938fd1498Szrj int idx = order_idx[node->uid + 1]; 169038fd1498Szrj if (idx >= 0 && idx < nnodes && order[idx] == node) 169138fd1498Szrj order[idx] = NULL; 169238fd1498Szrj } 169338fd1498Szrj 169438fd1498Szrj /* If we are in IPA mode (i.e., current_function_decl is NULL), call 169538fd1498Szrj function CALLBACK for every function in the call graph. Otherwise, 169638fd1498Szrj call CALLBACK on the current function. 169738fd1498Szrj This function is global so that plugins can use it. */ 169838fd1498Szrj void 169938fd1498Szrj do_per_function_toporder (void (*callback) (function *, void *data), void *data) 170038fd1498Szrj { 170138fd1498Szrj int i; 170238fd1498Szrj 170338fd1498Szrj if (current_function_decl) 170438fd1498Szrj callback (cfun, data); 170538fd1498Szrj else 170638fd1498Szrj { 170738fd1498Szrj cgraph_node_hook_list *hook; 170838fd1498Szrj int *order_idx; 170938fd1498Szrj gcc_assert (!order); 171038fd1498Szrj order = ggc_vec_alloc<cgraph_node *> (symtab->cgraph_count); 171138fd1498Szrj 171238fd1498Szrj order_idx = XALLOCAVEC (int, symtab->cgraph_max_uid + 1); 171338fd1498Szrj memset (order_idx + 1, -1, sizeof (int) * symtab->cgraph_max_uid); 171438fd1498Szrj order_idx[0] = symtab->cgraph_max_uid; 171538fd1498Szrj 171638fd1498Szrj nnodes = ipa_reverse_postorder (order); 171738fd1498Szrj for (i = nnodes - 1; i >= 0; i--) 171838fd1498Szrj { 171938fd1498Szrj order[i]->process = 1; 172038fd1498Szrj order_idx[order[i]->uid + 1] = i; 172138fd1498Szrj } 172238fd1498Szrj hook = symtab->add_cgraph_removal_hook (remove_cgraph_node_from_order, 172338fd1498Szrj order_idx); 172438fd1498Szrj for (i = nnodes - 1; i >= 0; i--) 172538fd1498Szrj { 172638fd1498Szrj /* Function could be inlined and removed as unreachable. */ 172738fd1498Szrj if (!order[i]) 172838fd1498Szrj continue; 172938fd1498Szrj 173038fd1498Szrj struct cgraph_node *node = order[i]; 173138fd1498Szrj 173238fd1498Szrj /* Allow possibly removed nodes to be garbage collected. */ 173338fd1498Szrj order[i] = NULL; 173438fd1498Szrj node->process = 0; 173538fd1498Szrj if (node->has_gimple_body_p ()) 173638fd1498Szrj { 173738fd1498Szrj struct function *fn = DECL_STRUCT_FUNCTION (node->decl); 173838fd1498Szrj push_cfun (fn); 173938fd1498Szrj callback (fn, data); 174038fd1498Szrj pop_cfun (); 174138fd1498Szrj } 174238fd1498Szrj } 174338fd1498Szrj symtab->remove_cgraph_removal_hook (hook); 174438fd1498Szrj } 174538fd1498Szrj ggc_free (order); 174638fd1498Szrj order = NULL; 174738fd1498Szrj nnodes = 0; 174838fd1498Szrj } 174938fd1498Szrj 175038fd1498Szrj /* Helper function to perform function body dump. */ 175138fd1498Szrj 175238fd1498Szrj static void 175338fd1498Szrj execute_function_dump (function *fn, void *data) 175438fd1498Szrj { 175538fd1498Szrj opt_pass *pass = (opt_pass *)data; 175638fd1498Szrj 175738fd1498Szrj if (dump_file) 175838fd1498Szrj { 175938fd1498Szrj push_cfun (fn); 176038fd1498Szrj 176138fd1498Szrj if (fn->curr_properties & PROP_trees) 176238fd1498Szrj dump_function_to_file (fn->decl, dump_file, dump_flags); 176338fd1498Szrj else 176438fd1498Szrj print_rtl_with_bb (dump_file, get_insns (), dump_flags); 176538fd1498Szrj 176638fd1498Szrj /* Flush the file. If verification fails, we won't be able to 176738fd1498Szrj close the file before aborting. */ 176838fd1498Szrj fflush (dump_file); 176938fd1498Szrj 177038fd1498Szrj if ((fn->curr_properties & PROP_cfg) 177138fd1498Szrj && (dump_flags & TDF_GRAPH)) 177238fd1498Szrj { 177338fd1498Szrj gcc::dump_manager *dumps = g->get_dumps (); 177438fd1498Szrj struct dump_file_info *dfi 177538fd1498Szrj = dumps->get_dump_file_info (pass->static_pass_number); 177638fd1498Szrj if (!dfi->graph_dump_initialized) 177738fd1498Szrj { 177838fd1498Szrj clean_graph_dump_file (dump_file_name); 177938fd1498Szrj dfi->graph_dump_initialized = true; 178038fd1498Szrj } 178138fd1498Szrj print_graph_cfg (dump_file_name, fn); 178238fd1498Szrj } 178338fd1498Szrj 178438fd1498Szrj pop_cfun (); 178538fd1498Szrj } 178638fd1498Szrj } 178738fd1498Szrj 178838fd1498Szrj /* This function is called when an internal compiler error is encountered. 178938fd1498Szrj Ensure that function dump is made available before compiler is aborted. */ 179038fd1498Szrj 179138fd1498Szrj void 179238fd1498Szrj emergency_dump_function () 179338fd1498Szrj { 179438fd1498Szrj if (!current_pass) 179538fd1498Szrj return; 179638fd1498Szrj enum opt_pass_type pt = current_pass->type; 179738fd1498Szrj fnotice (stderr, "during %s pass: %s\n", 179838fd1498Szrj pt == GIMPLE_PASS ? "GIMPLE" : pt == RTL_PASS ? "RTL" : "IPA", 179938fd1498Szrj current_pass->name); 180038fd1498Szrj if (!dump_file || !cfun) 180138fd1498Szrj return; 180238fd1498Szrj fnotice (stderr, "dump file: %s\n", dump_file_name); 180338fd1498Szrj fprintf (dump_file, "\n\n\nEMERGENCY DUMP:\n\n"); 180438fd1498Szrj execute_function_dump (cfun, current_pass); 180538fd1498Szrj } 180638fd1498Szrj 180738fd1498Szrj static struct profile_record *profile_record; 180838fd1498Szrj 180938fd1498Szrj /* Do profile consistency book-keeping for the pass with static number INDEX. 181038fd1498Szrj If SUBPASS is zero, we run _before_ the pass, and if SUBPASS is one, then 181138fd1498Szrj we run _after_ the pass. RUN is true if the pass really runs, or FALSE 181238fd1498Szrj if we are only book-keeping on passes that may have selectively disabled 181338fd1498Szrj themselves on a given function. */ 181438fd1498Szrj static void 181538fd1498Szrj check_profile_consistency (int index, int subpass, bool run) 181638fd1498Szrj { 181738fd1498Szrj pass_manager *passes = g->get_passes (); 181838fd1498Szrj if (index == -1) 181938fd1498Szrj return; 182038fd1498Szrj if (!profile_record) 182138fd1498Szrj profile_record = XCNEWVEC (struct profile_record, 182238fd1498Szrj passes->passes_by_id_size); 182338fd1498Szrj gcc_assert (index < passes->passes_by_id_size && index >= 0); 182438fd1498Szrj gcc_assert (subpass < 2); 182538fd1498Szrj profile_record[index].run |= run; 182638fd1498Szrj account_profile_record (&profile_record[index], subpass); 182738fd1498Szrj } 182838fd1498Szrj 182938fd1498Szrj /* Output profile consistency. */ 183038fd1498Szrj 183138fd1498Szrj void 183238fd1498Szrj dump_profile_report (void) 183338fd1498Szrj { 183438fd1498Szrj g->get_passes ()->dump_profile_report (); 183538fd1498Szrj } 183638fd1498Szrj 183738fd1498Szrj void 183838fd1498Szrj pass_manager::dump_profile_report () const 183938fd1498Szrj { 184038fd1498Szrj int i, j; 184138fd1498Szrj int last_freq_in = 0, last_count_in = 0, last_freq_out = 0, last_count_out = 0; 184238fd1498Szrj gcov_type last_time = 0, last_size = 0; 184338fd1498Szrj double rel_time_change, rel_size_change; 184438fd1498Szrj int last_reported = 0; 184538fd1498Szrj 184638fd1498Szrj if (!profile_record) 184738fd1498Szrj return; 184838fd1498Szrj fprintf (stderr, "\nProfile consistency report:\n\n"); 184938fd1498Szrj fprintf (stderr, "Pass name |mismatch in |mismated out|Overall\n"); 185038fd1498Szrj fprintf (stderr, " |freq count |freq count |size time\n"); 185138fd1498Szrj 185238fd1498Szrj for (i = 0; i < passes_by_id_size; i++) 185338fd1498Szrj for (j = 0 ; j < 2; j++) 185438fd1498Szrj if (profile_record[i].run) 185538fd1498Szrj { 185638fd1498Szrj if (last_time) 185738fd1498Szrj rel_time_change = (profile_record[i].time[j] 185838fd1498Szrj - (double)last_time) * 100 / (double)last_time; 185938fd1498Szrj else 186038fd1498Szrj rel_time_change = 0; 186138fd1498Szrj if (last_size) 186238fd1498Szrj rel_size_change = (profile_record[i].size[j] 186338fd1498Szrj - (double)last_size) * 100 / (double)last_size; 186438fd1498Szrj else 186538fd1498Szrj rel_size_change = 0; 186638fd1498Szrj 186738fd1498Szrj if (profile_record[i].num_mismatched_freq_in[j] != last_freq_in 186838fd1498Szrj || profile_record[i].num_mismatched_freq_out[j] != last_freq_out 186938fd1498Szrj || profile_record[i].num_mismatched_count_in[j] != last_count_in 187038fd1498Szrj || profile_record[i].num_mismatched_count_out[j] != last_count_out 187138fd1498Szrj || rel_time_change || rel_size_change) 187238fd1498Szrj { 187338fd1498Szrj last_reported = i; 187438fd1498Szrj fprintf (stderr, "%-20s %s", 187538fd1498Szrj passes_by_id [i]->name, 187638fd1498Szrj j ? "(after TODO)" : " "); 187738fd1498Szrj if (profile_record[i].num_mismatched_freq_in[j] != last_freq_in) 187838fd1498Szrj fprintf (stderr, "| %+5i", 187938fd1498Szrj profile_record[i].num_mismatched_freq_in[j] 188038fd1498Szrj - last_freq_in); 188138fd1498Szrj else 188238fd1498Szrj fprintf (stderr, "| "); 188338fd1498Szrj if (profile_record[i].num_mismatched_count_in[j] != last_count_in) 188438fd1498Szrj fprintf (stderr, " %+5i", 188538fd1498Szrj profile_record[i].num_mismatched_count_in[j] 188638fd1498Szrj - last_count_in); 188738fd1498Szrj else 188838fd1498Szrj fprintf (stderr, " "); 188938fd1498Szrj if (profile_record[i].num_mismatched_freq_out[j] != last_freq_out) 189038fd1498Szrj fprintf (stderr, "| %+5i", 189138fd1498Szrj profile_record[i].num_mismatched_freq_out[j] 189238fd1498Szrj - last_freq_out); 189338fd1498Szrj else 189438fd1498Szrj fprintf (stderr, "| "); 189538fd1498Szrj if (profile_record[i].num_mismatched_count_out[j] != last_count_out) 189638fd1498Szrj fprintf (stderr, " %+5i", 189738fd1498Szrj profile_record[i].num_mismatched_count_out[j] 189838fd1498Szrj - last_count_out); 189938fd1498Szrj else 190038fd1498Szrj fprintf (stderr, " "); 190138fd1498Szrj 190238fd1498Szrj /* Size/time units change across gimple and RTL. */ 190338fd1498Szrj if (i == pass_expand_1->static_pass_number) 190438fd1498Szrj fprintf (stderr, "|----------"); 190538fd1498Szrj else 190638fd1498Szrj { 190738fd1498Szrj if (rel_size_change) 190838fd1498Szrj fprintf (stderr, "| %+8.4f%%", rel_size_change); 190938fd1498Szrj else 191038fd1498Szrj fprintf (stderr, "| "); 191138fd1498Szrj if (rel_time_change) 191238fd1498Szrj fprintf (stderr, " %+8.4f%%", rel_time_change); 191338fd1498Szrj } 191438fd1498Szrj fprintf (stderr, "\n"); 191538fd1498Szrj last_freq_in = profile_record[i].num_mismatched_freq_in[j]; 191638fd1498Szrj last_freq_out = profile_record[i].num_mismatched_freq_out[j]; 191738fd1498Szrj last_count_in = profile_record[i].num_mismatched_count_in[j]; 191838fd1498Szrj last_count_out = profile_record[i].num_mismatched_count_out[j]; 191938fd1498Szrj } 192038fd1498Szrj else if (j && last_reported != i) 192138fd1498Szrj { 192238fd1498Szrj last_reported = i; 192338fd1498Szrj fprintf (stderr, "%-20s ------------| | |\n", 192438fd1498Szrj passes_by_id [i]->name); 192538fd1498Szrj } 192638fd1498Szrj last_time = profile_record[i].time[j]; 192738fd1498Szrj last_size = profile_record[i].size[j]; 192838fd1498Szrj } 192938fd1498Szrj } 193038fd1498Szrj 193138fd1498Szrj /* Perform all TODO actions that ought to be done on each function. */ 193238fd1498Szrj 193338fd1498Szrj static void 193438fd1498Szrj execute_function_todo (function *fn, void *data) 193538fd1498Szrj { 193638fd1498Szrj bool from_ipa_pass = (cfun == NULL); 193738fd1498Szrj unsigned int flags = (size_t)data; 193838fd1498Szrj flags &= ~fn->last_verified; 193938fd1498Szrj if (!flags) 194038fd1498Szrj return; 194138fd1498Szrj 194238fd1498Szrj push_cfun (fn); 194338fd1498Szrj 194438fd1498Szrj /* Always cleanup the CFG before trying to update SSA. */ 194538fd1498Szrj if (flags & TODO_cleanup_cfg) 194638fd1498Szrj { 194738fd1498Szrj cleanup_tree_cfg (); 194838fd1498Szrj 194938fd1498Szrj /* When cleanup_tree_cfg merges consecutive blocks, it may 195038fd1498Szrj perform some simplistic propagation when removing single 195138fd1498Szrj valued PHI nodes. This propagation may, in turn, cause the 195238fd1498Szrj SSA form to become out-of-date (see PR 22037). So, even 195338fd1498Szrj if the parent pass had not scheduled an SSA update, we may 195438fd1498Szrj still need to do one. */ 195538fd1498Szrj if (!(flags & TODO_update_ssa_any) && need_ssa_update_p (cfun)) 195638fd1498Szrj flags |= TODO_update_ssa; 195738fd1498Szrj } 195838fd1498Szrj 195938fd1498Szrj if (flags & TODO_update_ssa_any) 196038fd1498Szrj { 196138fd1498Szrj unsigned update_flags = flags & TODO_update_ssa_any; 196238fd1498Szrj update_ssa (update_flags); 196338fd1498Szrj } 196438fd1498Szrj 196538fd1498Szrj if (flag_tree_pta && (flags & TODO_rebuild_alias)) 196638fd1498Szrj compute_may_aliases (); 196738fd1498Szrj 196838fd1498Szrj if (optimize && (flags & TODO_update_address_taken)) 196938fd1498Szrj execute_update_addresses_taken (); 197038fd1498Szrj 197138fd1498Szrj if (flags & TODO_remove_unused_locals) 197238fd1498Szrj remove_unused_locals (); 197338fd1498Szrj 197438fd1498Szrj if (flags & TODO_rebuild_frequencies) 197538fd1498Szrj rebuild_frequencies (); 197638fd1498Szrj 197738fd1498Szrj if (flags & TODO_rebuild_cgraph_edges) 197838fd1498Szrj cgraph_edge::rebuild_edges (); 197938fd1498Szrj 198038fd1498Szrj gcc_assert (dom_info_state (fn, CDI_POST_DOMINATORS) == DOM_NONE); 198138fd1498Szrj /* If we've seen errors do not bother running any verifiers. */ 198238fd1498Szrj if (flag_checking && !seen_error ()) 198338fd1498Szrj { 198438fd1498Szrj dom_state pre_verify_state = dom_info_state (fn, CDI_DOMINATORS); 198538fd1498Szrj dom_state pre_verify_pstate = dom_info_state (fn, CDI_POST_DOMINATORS); 198638fd1498Szrj 198738fd1498Szrj if (flags & TODO_verify_il) 198838fd1498Szrj { 198938fd1498Szrj if (cfun->curr_properties & PROP_trees) 199038fd1498Szrj { 199138fd1498Szrj if (cfun->curr_properties & PROP_cfg) 199238fd1498Szrj /* IPA passes leave stmts to be fixed up, so make sure to 199338fd1498Szrj not verify stmts really throw. */ 199438fd1498Szrj verify_gimple_in_cfg (cfun, !from_ipa_pass); 199538fd1498Szrj else 199638fd1498Szrj verify_gimple_in_seq (gimple_body (cfun->decl)); 199738fd1498Szrj } 199838fd1498Szrj if (cfun->curr_properties & PROP_ssa) 199938fd1498Szrj /* IPA passes leave stmts to be fixed up, so make sure to 200038fd1498Szrj not verify SSA operands whose verifier will choke on that. */ 200138fd1498Szrj verify_ssa (true, !from_ipa_pass); 200238fd1498Szrj /* IPA passes leave basic-blocks unsplit, so make sure to 200338fd1498Szrj not trip on that. */ 200438fd1498Szrj if ((cfun->curr_properties & PROP_cfg) 200538fd1498Szrj && !from_ipa_pass) 200638fd1498Szrj verify_flow_info (); 200738fd1498Szrj if (current_loops 200838fd1498Szrj && ! loops_state_satisfies_p (LOOPS_NEED_FIXUP)) 200938fd1498Szrj { 201038fd1498Szrj verify_loop_structure (); 201138fd1498Szrj if (loops_state_satisfies_p (LOOP_CLOSED_SSA)) 201238fd1498Szrj verify_loop_closed_ssa (false); 201338fd1498Szrj } 201438fd1498Szrj if (cfun->curr_properties & PROP_rtl) 201538fd1498Szrj verify_rtl_sharing (); 201638fd1498Szrj } 201738fd1498Szrj 201838fd1498Szrj /* Make sure verifiers don't change dominator state. */ 201938fd1498Szrj gcc_assert (dom_info_state (fn, CDI_DOMINATORS) == pre_verify_state); 202038fd1498Szrj gcc_assert (dom_info_state (fn, CDI_POST_DOMINATORS) == pre_verify_pstate); 202138fd1498Szrj } 202238fd1498Szrj 202338fd1498Szrj fn->last_verified = flags & TODO_verify_all; 202438fd1498Szrj 202538fd1498Szrj pop_cfun (); 202638fd1498Szrj 202738fd1498Szrj /* For IPA passes make sure to release dominator info, it can be 202838fd1498Szrj computed by non-verifying TODOs. */ 202938fd1498Szrj if (from_ipa_pass) 203038fd1498Szrj { 203138fd1498Szrj free_dominance_info (fn, CDI_DOMINATORS); 203238fd1498Szrj free_dominance_info (fn, CDI_POST_DOMINATORS); 203338fd1498Szrj } 203438fd1498Szrj } 203538fd1498Szrj 203638fd1498Szrj /* Perform all TODO actions. */ 203738fd1498Szrj static void 203838fd1498Szrj execute_todo (unsigned int flags) 203938fd1498Szrj { 204038fd1498Szrj if (flag_checking 204138fd1498Szrj && cfun 204238fd1498Szrj && need_ssa_update_p (cfun)) 204338fd1498Szrj gcc_assert (flags & TODO_update_ssa_any); 204438fd1498Szrj 204538fd1498Szrj statistics_fini_pass (); 204638fd1498Szrj 204738fd1498Szrj if (flags) 204838fd1498Szrj do_per_function (execute_function_todo, (void *)(size_t) flags); 204938fd1498Szrj 205038fd1498Szrj /* At this point we should not have any unreachable code in the 205138fd1498Szrj CFG, so it is safe to flush the pending freelist for SSA_NAMES. */ 205238fd1498Szrj if (cfun && cfun->gimple_df) 205338fd1498Szrj flush_ssaname_freelist (); 205438fd1498Szrj 205538fd1498Szrj /* Always remove functions just as before inlining: IPA passes might be 205638fd1498Szrj interested to see bodies of extern inline functions that are not inlined 205738fd1498Szrj to analyze side effects. The full removal is done just at the end 205838fd1498Szrj of IPA pass queue. */ 205938fd1498Szrj if (flags & TODO_remove_functions) 206038fd1498Szrj { 206138fd1498Szrj gcc_assert (!cfun); 206238fd1498Szrj symtab->remove_unreachable_nodes (dump_file); 206338fd1498Szrj } 206438fd1498Szrj 206538fd1498Szrj if ((flags & TODO_dump_symtab) && dump_file && !current_function_decl) 206638fd1498Szrj { 206738fd1498Szrj gcc_assert (!cfun); 206838fd1498Szrj symtab->dump (dump_file); 206938fd1498Szrj /* Flush the file. If verification fails, we won't be able to 207038fd1498Szrj close the file before aborting. */ 207138fd1498Szrj fflush (dump_file); 207238fd1498Szrj } 207338fd1498Szrj 207438fd1498Szrj /* Now that the dumping has been done, we can get rid of the optional 207538fd1498Szrj df problems. */ 207638fd1498Szrj if (flags & TODO_df_finish) 207738fd1498Szrj df_finish_pass ((flags & TODO_df_verify) != 0); 207838fd1498Szrj } 207938fd1498Szrj 208038fd1498Szrj /* Verify invariants that should hold between passes. This is a place 208138fd1498Szrj to put simple sanity checks. */ 208238fd1498Szrj 208338fd1498Szrj static void 208438fd1498Szrj verify_interpass_invariants (void) 208538fd1498Szrj { 208638fd1498Szrj gcc_checking_assert (!fold_deferring_overflow_warnings_p ()); 208738fd1498Szrj } 208838fd1498Szrj 208938fd1498Szrj /* Clear the last verified flag. */ 209038fd1498Szrj 209138fd1498Szrj static void 209238fd1498Szrj clear_last_verified (function *fn, void *data ATTRIBUTE_UNUSED) 209338fd1498Szrj { 209438fd1498Szrj fn->last_verified = 0; 209538fd1498Szrj } 209638fd1498Szrj 209738fd1498Szrj /* Helper function. Verify that the properties has been turn into the 209838fd1498Szrj properties expected by the pass. */ 209938fd1498Szrj 210038fd1498Szrj static void 210138fd1498Szrj verify_curr_properties (function *fn, void *data) 210238fd1498Szrj { 210338fd1498Szrj unsigned int props = (size_t)data; 210438fd1498Szrj gcc_assert ((fn->curr_properties & props) == props); 210538fd1498Szrj } 210638fd1498Szrj 210738fd1498Szrj /* Release dump file name if set. */ 210838fd1498Szrj 210938fd1498Szrj static void 211038fd1498Szrj release_dump_file_name (void) 211138fd1498Szrj { 211238fd1498Szrj if (dump_file_name) 211338fd1498Szrj { 211438fd1498Szrj free (CONST_CAST (char *, dump_file_name)); 211538fd1498Szrj dump_file_name = NULL; 211638fd1498Szrj } 211738fd1498Szrj } 211838fd1498Szrj 211938fd1498Szrj /* Initialize pass dump file. */ 212038fd1498Szrj /* This is non-static so that the plugins can use it. */ 212138fd1498Szrj 212238fd1498Szrj bool 212338fd1498Szrj pass_init_dump_file (opt_pass *pass) 212438fd1498Szrj { 212538fd1498Szrj /* If a dump file name is present, open it if enabled. */ 212638fd1498Szrj if (pass->static_pass_number != -1) 212738fd1498Szrj { 212838fd1498Szrj timevar_push (TV_DUMP); 212938fd1498Szrj gcc::dump_manager *dumps = g->get_dumps (); 213038fd1498Szrj bool initializing_dump = 213138fd1498Szrj !dumps->dump_initialized_p (pass->static_pass_number); 213238fd1498Szrj release_dump_file_name (); 213338fd1498Szrj dump_file_name = dumps->get_dump_file_name (pass->static_pass_number); 213438fd1498Szrj dumps->dump_start (pass->static_pass_number, &dump_flags); 213538fd1498Szrj if (dump_file && current_function_decl && ! (dump_flags & TDF_GIMPLE)) 213638fd1498Szrj dump_function_header (dump_file, current_function_decl, dump_flags); 213738fd1498Szrj if (initializing_dump 213838fd1498Szrj && dump_file && (dump_flags & TDF_GRAPH) 213938fd1498Szrj && cfun && (cfun->curr_properties & PROP_cfg)) 214038fd1498Szrj { 214138fd1498Szrj clean_graph_dump_file (dump_file_name); 214238fd1498Szrj struct dump_file_info *dfi 214338fd1498Szrj = dumps->get_dump_file_info (pass->static_pass_number); 214438fd1498Szrj dfi->graph_dump_initialized = true; 214538fd1498Szrj } 214638fd1498Szrj timevar_pop (TV_DUMP); 214738fd1498Szrj return initializing_dump; 214838fd1498Szrj } 214938fd1498Szrj else 215038fd1498Szrj return false; 215138fd1498Szrj } 215238fd1498Szrj 215338fd1498Szrj /* Flush PASS dump file. */ 215438fd1498Szrj /* This is non-static so that plugins can use it. */ 215538fd1498Szrj 215638fd1498Szrj void 215738fd1498Szrj pass_fini_dump_file (opt_pass *pass) 215838fd1498Szrj { 215938fd1498Szrj timevar_push (TV_DUMP); 216038fd1498Szrj 216138fd1498Szrj /* Flush and close dump file. */ 216238fd1498Szrj release_dump_file_name (); 216338fd1498Szrj 216438fd1498Szrj g->get_dumps ()->dump_finish (pass->static_pass_number); 216538fd1498Szrj timevar_pop (TV_DUMP); 216638fd1498Szrj } 216738fd1498Szrj 216838fd1498Szrj /* After executing the pass, apply expected changes to the function 216938fd1498Szrj properties. */ 217038fd1498Szrj 217138fd1498Szrj static void 217238fd1498Szrj update_properties_after_pass (function *fn, void *data) 217338fd1498Szrj { 217438fd1498Szrj opt_pass *pass = (opt_pass *) data; 217538fd1498Szrj fn->curr_properties = (fn->curr_properties | pass->properties_provided) 217638fd1498Szrj & ~pass->properties_destroyed; 217738fd1498Szrj } 217838fd1498Szrj 217938fd1498Szrj /* Execute summary generation for all of the passes in IPA_PASS. */ 218038fd1498Szrj 218138fd1498Szrj void 218238fd1498Szrj execute_ipa_summary_passes (ipa_opt_pass_d *ipa_pass) 218338fd1498Szrj { 218438fd1498Szrj while (ipa_pass) 218538fd1498Szrj { 218638fd1498Szrj opt_pass *pass = ipa_pass; 218738fd1498Szrj 218838fd1498Szrj /* Execute all of the IPA_PASSes in the list. */ 218938fd1498Szrj if (ipa_pass->type == IPA_PASS 219038fd1498Szrj && pass->gate (cfun) 219138fd1498Szrj && ipa_pass->generate_summary) 219238fd1498Szrj { 219338fd1498Szrj pass_init_dump_file (pass); 219438fd1498Szrj 219538fd1498Szrj /* If a timevar is present, start it. */ 219638fd1498Szrj if (pass->tv_id) 219738fd1498Szrj timevar_push (pass->tv_id); 219838fd1498Szrj 219938fd1498Szrj current_pass = pass; 220038fd1498Szrj ipa_pass->generate_summary (); 220138fd1498Szrj 220238fd1498Szrj /* Stop timevar. */ 220338fd1498Szrj if (pass->tv_id) 220438fd1498Szrj timevar_pop (pass->tv_id); 220538fd1498Szrj 220638fd1498Szrj pass_fini_dump_file (pass); 220738fd1498Szrj } 220838fd1498Szrj ipa_pass = (ipa_opt_pass_d *)ipa_pass->next; 220938fd1498Szrj } 221038fd1498Szrj } 221138fd1498Szrj 221238fd1498Szrj /* Execute IPA_PASS function transform on NODE. */ 221338fd1498Szrj 221438fd1498Szrj static void 221538fd1498Szrj execute_one_ipa_transform_pass (struct cgraph_node *node, 221638fd1498Szrj ipa_opt_pass_d *ipa_pass) 221738fd1498Szrj { 221838fd1498Szrj opt_pass *pass = ipa_pass; 221938fd1498Szrj unsigned int todo_after = 0; 222038fd1498Szrj 222138fd1498Szrj current_pass = pass; 222238fd1498Szrj if (!ipa_pass->function_transform) 222338fd1498Szrj return; 222438fd1498Szrj 222538fd1498Szrj /* Note that the folders should only create gimple expressions. 222638fd1498Szrj This is a hack until the new folder is ready. */ 222738fd1498Szrj in_gimple_form = (cfun && (cfun->curr_properties & PROP_trees)) != 0; 222838fd1498Szrj 222938fd1498Szrj pass_init_dump_file (pass); 223038fd1498Szrj 223138fd1498Szrj /* If a timevar is present, start it. */ 223238fd1498Szrj if (pass->tv_id != TV_NONE) 223338fd1498Szrj timevar_push (pass->tv_id); 223438fd1498Szrj 223538fd1498Szrj /* Run pre-pass verification. */ 223638fd1498Szrj execute_todo (ipa_pass->function_transform_todo_flags_start); 223738fd1498Szrj 223838fd1498Szrj /* Do it! */ 223938fd1498Szrj todo_after = ipa_pass->function_transform (node); 224038fd1498Szrj 224138fd1498Szrj if (profile_report && cfun && (cfun->curr_properties & PROP_cfg)) 224238fd1498Szrj check_profile_consistency (pass->static_pass_number, 0, true); 224338fd1498Szrj 224438fd1498Szrj /* Run post-pass cleanup and verification. */ 224538fd1498Szrj execute_todo (todo_after); 224638fd1498Szrj verify_interpass_invariants (); 224738fd1498Szrj if (profile_report && cfun && (cfun->curr_properties & PROP_cfg)) 224838fd1498Szrj check_profile_consistency (pass->static_pass_number, 1, true); 224938fd1498Szrj 225038fd1498Szrj /* Stop timevar. */ 225138fd1498Szrj if (pass->tv_id != TV_NONE) 225238fd1498Szrj timevar_pop (pass->tv_id); 225338fd1498Szrj 225438fd1498Szrj if (dump_file) 225538fd1498Szrj do_per_function (execute_function_dump, pass); 225638fd1498Szrj pass_fini_dump_file (pass); 225738fd1498Szrj 225838fd1498Szrj current_pass = NULL; 225938fd1498Szrj redirect_edge_var_map_empty (); 226038fd1498Szrj 226138fd1498Szrj /* Signal this is a suitable GC collection point. */ 226238fd1498Szrj if (!(todo_after & TODO_do_not_ggc_collect)) 226338fd1498Szrj ggc_collect (); 226438fd1498Szrj } 226538fd1498Szrj 226638fd1498Szrj /* For the current function, execute all ipa transforms. */ 226738fd1498Szrj 226838fd1498Szrj void 226938fd1498Szrj execute_all_ipa_transforms (void) 227038fd1498Szrj { 227138fd1498Szrj struct cgraph_node *node; 227238fd1498Szrj if (!cfun) 227338fd1498Szrj return; 227438fd1498Szrj node = cgraph_node::get (current_function_decl); 227538fd1498Szrj 227638fd1498Szrj if (node->ipa_transforms_to_apply.exists ()) 227738fd1498Szrj { 227838fd1498Szrj unsigned int i; 227938fd1498Szrj 228038fd1498Szrj for (i = 0; i < node->ipa_transforms_to_apply.length (); i++) 228138fd1498Szrj execute_one_ipa_transform_pass (node, node->ipa_transforms_to_apply[i]); 228238fd1498Szrj node->ipa_transforms_to_apply.release (); 228338fd1498Szrj } 228438fd1498Szrj } 228538fd1498Szrj 228638fd1498Szrj /* Check if PASS is explicitly disabled or enabled and return 228738fd1498Szrj the gate status. FUNC is the function to be processed, and 228838fd1498Szrj GATE_STATUS is the gate status determined by pass manager by 228938fd1498Szrj default. */ 229038fd1498Szrj 229138fd1498Szrj static bool 229238fd1498Szrj override_gate_status (opt_pass *pass, tree func, bool gate_status) 229338fd1498Szrj { 229438fd1498Szrj bool explicitly_enabled = false; 229538fd1498Szrj bool explicitly_disabled = false; 229638fd1498Szrj 229738fd1498Szrj explicitly_enabled 229838fd1498Szrj = is_pass_explicitly_enabled_or_disabled (pass, func, 229938fd1498Szrj enabled_pass_uid_range_tab); 230038fd1498Szrj explicitly_disabled 230138fd1498Szrj = is_pass_explicitly_enabled_or_disabled (pass, func, 230238fd1498Szrj disabled_pass_uid_range_tab); 230338fd1498Szrj 230438fd1498Szrj gate_status = !explicitly_disabled && (gate_status || explicitly_enabled); 230538fd1498Szrj 230638fd1498Szrj return gate_status; 230738fd1498Szrj } 230838fd1498Szrj 230938fd1498Szrj /* Determine if PASS_NAME matches CRITERION. 231038fd1498Szrj Not a pure predicate, since it can update CRITERION, to support 231138fd1498Szrj matching the Nth invocation of a pass. 231238fd1498Szrj Subroutine of should_skip_pass_p. */ 231338fd1498Szrj 231438fd1498Szrj static bool 231538fd1498Szrj determine_pass_name_match (const char *pass_name, char *criterion) 231638fd1498Szrj { 231738fd1498Szrj size_t namelen = strlen (pass_name); 231838fd1498Szrj if (! strncmp (pass_name, criterion, namelen)) 231938fd1498Szrj { 232038fd1498Szrj /* The following supports starting with the Nth invocation 232138fd1498Szrj of a pass (where N does not necessarily is equal to the 232238fd1498Szrj dump file suffix). */ 232338fd1498Szrj if (criterion[namelen] == '\0' 232438fd1498Szrj || (criterion[namelen] == '1' 232538fd1498Szrj && criterion[namelen + 1] == '\0')) 232638fd1498Szrj return true; 232738fd1498Szrj else 232838fd1498Szrj { 232938fd1498Szrj if (criterion[namelen + 1] == '\0') 233038fd1498Szrj --criterion[namelen]; 233138fd1498Szrj return false; 233238fd1498Szrj } 233338fd1498Szrj } 233438fd1498Szrj else 233538fd1498Szrj return false; 233638fd1498Szrj } 233738fd1498Szrj 233838fd1498Szrj /* For skipping passes until "startwith" pass. 233938fd1498Szrj Return true iff PASS should be skipped. 234038fd1498Szrj Clear cfun->pass_startwith when encountering the "startwith" pass, 234138fd1498Szrj so that all subsequent passes are run. */ 234238fd1498Szrj 234338fd1498Szrj static bool 234438fd1498Szrj should_skip_pass_p (opt_pass *pass) 234538fd1498Szrj { 234638fd1498Szrj if (!cfun) 234738fd1498Szrj return false; 234838fd1498Szrj if (!cfun->pass_startwith) 234938fd1498Szrj return false; 235038fd1498Szrj 235138fd1498Szrj /* For __GIMPLE functions, we have to at least start when we leave 235238fd1498Szrj SSA. Hence, we need to detect the "expand" pass, and stop skipping 235338fd1498Szrj when we encounter it. A cheap way to identify "expand" is it to 235438fd1498Szrj detect the destruction of PROP_ssa. 235538fd1498Szrj For __RTL functions, we invoke "rest_of_compilation" directly, which 235638fd1498Szrj is after "expand", and hence we don't reach this conditional. */ 235738fd1498Szrj if (pass->properties_destroyed & PROP_ssa) 235838fd1498Szrj { 235938fd1498Szrj if (!quiet_flag) 236038fd1498Szrj fprintf (stderr, "starting anyway when leaving SSA: %s\n", pass->name); 236138fd1498Szrj cfun->pass_startwith = NULL; 236238fd1498Szrj return false; 236338fd1498Szrj } 236438fd1498Szrj 236538fd1498Szrj if (determine_pass_name_match (pass->name, cfun->pass_startwith)) 236638fd1498Szrj { 236738fd1498Szrj if (!quiet_flag) 236838fd1498Szrj fprintf (stderr, "found starting pass: %s\n", pass->name); 236938fd1498Szrj cfun->pass_startwith = NULL; 237038fd1498Szrj return false; 237138fd1498Szrj } 237238fd1498Szrj 237338fd1498Szrj /* For GIMPLE passes, run any property provider (but continue skipping 237438fd1498Szrj afterwards). 237538fd1498Szrj We don't want to force running RTL passes that are property providers: 237638fd1498Szrj "expand" is covered above, and the only pass other than "expand" that 237738fd1498Szrj provides a property is "into_cfglayout" (PROP_cfglayout), which does 237838fd1498Szrj too much for a dumped __RTL function. */ 237938fd1498Szrj if (pass->type == GIMPLE_PASS 238038fd1498Szrj && pass->properties_provided != 0) 238138fd1498Szrj return false; 238238fd1498Szrj 238338fd1498Szrj /* Don't skip df init; later RTL passes need it. */ 238438fd1498Szrj if (strstr (pass->name, "dfinit") != NULL) 238538fd1498Szrj return false; 238638fd1498Szrj 238738fd1498Szrj if (!quiet_flag) 238838fd1498Szrj fprintf (stderr, "skipping pass: %s\n", pass->name); 238938fd1498Szrj 239038fd1498Szrj /* If we get here, then we have a "startwith" that we haven't seen yet; 239138fd1498Szrj skip the pass. */ 239238fd1498Szrj return true; 239338fd1498Szrj } 239438fd1498Szrj 239538fd1498Szrj /* Skip the given pass, for handling passes before "startwith" 239638fd1498Szrj in __GIMPLE and__RTL-marked functions. 239738fd1498Szrj In theory, this ought to be a no-op, but some of the RTL passes 239838fd1498Szrj need additional processing here. */ 239938fd1498Szrj 240038fd1498Szrj static void 240138fd1498Szrj skip_pass (opt_pass *pass) 240238fd1498Szrj { 240338fd1498Szrj /* Pass "reload" sets the global "reload_completed", and many 240438fd1498Szrj things depend on this (e.g. instructions in .md files). */ 240538fd1498Szrj if (strcmp (pass->name, "reload") == 0) 240638fd1498Szrj reload_completed = 1; 240738fd1498Szrj 240838fd1498Szrj /* The INSN_ADDRESSES vec is normally set up by 240938fd1498Szrj shorten_branches; set it up for the benefit of passes that 241038fd1498Szrj run after this. */ 241138fd1498Szrj if (strcmp (pass->name, "shorten") == 0) 241238fd1498Szrj INSN_ADDRESSES_ALLOC (get_max_uid ()); 241338fd1498Szrj 241438fd1498Szrj /* Update the cfg hooks as appropriate. */ 241538fd1498Szrj if (strcmp (pass->name, "into_cfglayout") == 0) 241638fd1498Szrj { 241738fd1498Szrj cfg_layout_rtl_register_cfg_hooks (); 241838fd1498Szrj cfun->curr_properties |= PROP_cfglayout; 241938fd1498Szrj } 242038fd1498Szrj if (strcmp (pass->name, "outof_cfglayout") == 0) 242138fd1498Szrj { 242238fd1498Szrj rtl_register_cfg_hooks (); 242338fd1498Szrj cfun->curr_properties &= ~PROP_cfglayout; 242438fd1498Szrj } 242538fd1498Szrj } 242638fd1498Szrj 242738fd1498Szrj /* Execute PASS. */ 242838fd1498Szrj 242938fd1498Szrj bool 243038fd1498Szrj execute_one_pass (opt_pass *pass) 243138fd1498Szrj { 243238fd1498Szrj unsigned int todo_after = 0; 243338fd1498Szrj 243438fd1498Szrj bool gate_status; 243538fd1498Szrj 243638fd1498Szrj /* IPA passes are executed on whole program, so cfun should be NULL. 243738fd1498Szrj Other passes need function context set. */ 243838fd1498Szrj if (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS) 243938fd1498Szrj gcc_assert (!cfun && !current_function_decl); 244038fd1498Szrj else 244138fd1498Szrj gcc_assert (cfun && current_function_decl); 244238fd1498Szrj 244338fd1498Szrj current_pass = pass; 244438fd1498Szrj 244538fd1498Szrj /* Check whether gate check should be avoided. 244638fd1498Szrj User controls the value of the gate through the parameter "gate_status". */ 244738fd1498Szrj gate_status = pass->gate (cfun); 244838fd1498Szrj gate_status = override_gate_status (pass, current_function_decl, gate_status); 244938fd1498Szrj 245038fd1498Szrj /* Override gate with plugin. */ 245138fd1498Szrj invoke_plugin_callbacks (PLUGIN_OVERRIDE_GATE, &gate_status); 245238fd1498Szrj 245338fd1498Szrj if (!gate_status) 245438fd1498Szrj { 245538fd1498Szrj /* Run so passes selectively disabling themselves on a given function 245638fd1498Szrj are not miscounted. */ 245738fd1498Szrj if (profile_report && cfun && (cfun->curr_properties & PROP_cfg)) 245838fd1498Szrj { 245938fd1498Szrj check_profile_consistency (pass->static_pass_number, 0, false); 246038fd1498Szrj check_profile_consistency (pass->static_pass_number, 1, false); 246138fd1498Szrj } 246238fd1498Szrj current_pass = NULL; 246338fd1498Szrj return false; 246438fd1498Szrj } 246538fd1498Szrj 246638fd1498Szrj if (should_skip_pass_p (pass)) 246738fd1498Szrj { 246838fd1498Szrj skip_pass (pass); 246938fd1498Szrj return true; 247038fd1498Szrj } 247138fd1498Szrj 247238fd1498Szrj /* Pass execution event trigger: useful to identify passes being 247338fd1498Szrj executed. */ 247438fd1498Szrj invoke_plugin_callbacks (PLUGIN_PASS_EXECUTION, pass); 247538fd1498Szrj 247638fd1498Szrj if (!quiet_flag && !cfun) 247738fd1498Szrj fprintf (stderr, " <%s>", pass->name ? pass->name : ""); 247838fd1498Szrj 247938fd1498Szrj /* Note that the folders should only create gimple expressions. 248038fd1498Szrj This is a hack until the new folder is ready. */ 248138fd1498Szrj in_gimple_form = (cfun && (cfun->curr_properties & PROP_trees)) != 0; 248238fd1498Szrj 248338fd1498Szrj pass_init_dump_file (pass); 248438fd1498Szrj 248538fd1498Szrj /* If a timevar is present, start it. */ 248638fd1498Szrj if (pass->tv_id != TV_NONE) 248738fd1498Szrj timevar_push (pass->tv_id); 248838fd1498Szrj 248938fd1498Szrj /* Run pre-pass verification. */ 249038fd1498Szrj execute_todo (pass->todo_flags_start); 249138fd1498Szrj 249238fd1498Szrj if (flag_checking) 249338fd1498Szrj do_per_function (verify_curr_properties, 249438fd1498Szrj (void *)(size_t)pass->properties_required); 249538fd1498Szrj 249638fd1498Szrj /* Do it! */ 249738fd1498Szrj todo_after = pass->execute (cfun); 249838fd1498Szrj 249938fd1498Szrj if (todo_after & TODO_discard_function) 250038fd1498Szrj { 250138fd1498Szrj /* Stop timevar. */ 250238fd1498Szrj if (pass->tv_id != TV_NONE) 250338fd1498Szrj timevar_pop (pass->tv_id); 250438fd1498Szrj 250538fd1498Szrj pass_fini_dump_file (pass); 250638fd1498Szrj 250738fd1498Szrj gcc_assert (cfun); 250838fd1498Szrj /* As cgraph_node::release_body expects release dominators info, 250938fd1498Szrj we have to release it. */ 251038fd1498Szrj if (dom_info_available_p (CDI_DOMINATORS)) 251138fd1498Szrj free_dominance_info (CDI_DOMINATORS); 251238fd1498Szrj 251338fd1498Szrj if (dom_info_available_p (CDI_POST_DOMINATORS)) 251438fd1498Szrj free_dominance_info (CDI_POST_DOMINATORS); 251538fd1498Szrj 251638fd1498Szrj tree fn = cfun->decl; 251738fd1498Szrj pop_cfun (); 251838fd1498Szrj gcc_assert (!cfun); 251938fd1498Szrj cgraph_node::get (fn)->release_body (); 252038fd1498Szrj 252138fd1498Szrj current_pass = NULL; 252238fd1498Szrj redirect_edge_var_map_empty (); 252338fd1498Szrj 252438fd1498Szrj ggc_collect (); 252538fd1498Szrj 252638fd1498Szrj return true; 252738fd1498Szrj } 252838fd1498Szrj 252938fd1498Szrj do_per_function (clear_last_verified, NULL); 253038fd1498Szrj 253138fd1498Szrj do_per_function (update_properties_after_pass, pass); 253238fd1498Szrj 253338fd1498Szrj if (profile_report && cfun && (cfun->curr_properties & PROP_cfg)) 253438fd1498Szrj check_profile_consistency (pass->static_pass_number, 0, true); 253538fd1498Szrj 253638fd1498Szrj /* Run post-pass cleanup and verification. */ 253738fd1498Szrj execute_todo (todo_after | pass->todo_flags_finish | TODO_verify_il); 253838fd1498Szrj if (profile_report && cfun && (cfun->curr_properties & PROP_cfg)) 253938fd1498Szrj check_profile_consistency (pass->static_pass_number, 1, true); 254038fd1498Szrj 254138fd1498Szrj verify_interpass_invariants (); 254238fd1498Szrj 254338fd1498Szrj /* Stop timevar. */ 254438fd1498Szrj if (pass->tv_id != TV_NONE) 254538fd1498Szrj timevar_pop (pass->tv_id); 254638fd1498Szrj 254738fd1498Szrj if (pass->type == IPA_PASS 254838fd1498Szrj && ((ipa_opt_pass_d *)pass)->function_transform) 254938fd1498Szrj { 255038fd1498Szrj struct cgraph_node *node; 255138fd1498Szrj FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node) 255238fd1498Szrj node->ipa_transforms_to_apply.safe_push ((ipa_opt_pass_d *)pass); 255338fd1498Szrj } 255438fd1498Szrj else if (dump_file) 255538fd1498Szrj do_per_function (execute_function_dump, pass); 255638fd1498Szrj 255738fd1498Szrj if (!current_function_decl) 255838fd1498Szrj symtab->process_new_functions (); 255938fd1498Szrj 256038fd1498Szrj pass_fini_dump_file (pass); 256138fd1498Szrj 256238fd1498Szrj if (pass->type != SIMPLE_IPA_PASS && pass->type != IPA_PASS) 256338fd1498Szrj gcc_assert (!(cfun->curr_properties & PROP_trees) 256438fd1498Szrj || pass->type != RTL_PASS); 256538fd1498Szrj 256638fd1498Szrj current_pass = NULL; 256738fd1498Szrj redirect_edge_var_map_empty (); 256838fd1498Szrj 256938fd1498Szrj /* Signal this is a suitable GC collection point. */ 257038fd1498Szrj if (!((todo_after | pass->todo_flags_finish) & TODO_do_not_ggc_collect)) 257138fd1498Szrj ggc_collect (); 257238fd1498Szrj 257338fd1498Szrj return true; 257438fd1498Szrj } 257538fd1498Szrj 257638fd1498Szrj static void 257738fd1498Szrj execute_pass_list_1 (opt_pass *pass) 257838fd1498Szrj { 257938fd1498Szrj do 258038fd1498Szrj { 258138fd1498Szrj gcc_assert (pass->type == GIMPLE_PASS 258238fd1498Szrj || pass->type == RTL_PASS); 258338fd1498Szrj 258438fd1498Szrj if (cfun == NULL) 258538fd1498Szrj return; 258638fd1498Szrj if (execute_one_pass (pass) && pass->sub) 258738fd1498Szrj execute_pass_list_1 (pass->sub); 258838fd1498Szrj pass = pass->next; 258938fd1498Szrj } 259038fd1498Szrj while (pass); 259138fd1498Szrj } 259238fd1498Szrj 259338fd1498Szrj void 259438fd1498Szrj execute_pass_list (function *fn, opt_pass *pass) 259538fd1498Szrj { 259638fd1498Szrj gcc_assert (fn == cfun); 259738fd1498Szrj execute_pass_list_1 (pass); 259838fd1498Szrj if (cfun && fn->cfg) 259938fd1498Szrj { 260038fd1498Szrj free_dominance_info (CDI_DOMINATORS); 260138fd1498Szrj free_dominance_info (CDI_POST_DOMINATORS); 260238fd1498Szrj } 260338fd1498Szrj } 260438fd1498Szrj 260538fd1498Szrj /* Write out all LTO data. */ 260638fd1498Szrj static void 260738fd1498Szrj write_lto (void) 260838fd1498Szrj { 260938fd1498Szrj timevar_push (TV_IPA_LTO_GIMPLE_OUT); 261038fd1498Szrj lto_output (); 261138fd1498Szrj timevar_pop (TV_IPA_LTO_GIMPLE_OUT); 261238fd1498Szrj timevar_push (TV_IPA_LTO_DECL_OUT); 261338fd1498Szrj produce_asm_for_decls (); 261438fd1498Szrj timevar_pop (TV_IPA_LTO_DECL_OUT); 261538fd1498Szrj } 261638fd1498Szrj 261738fd1498Szrj /* Same as execute_pass_list but assume that subpasses of IPA passes 261838fd1498Szrj are local passes. If SET is not NULL, write out summaries of only 261938fd1498Szrj those node in SET. */ 262038fd1498Szrj 262138fd1498Szrj static void 262238fd1498Szrj ipa_write_summaries_2 (opt_pass *pass, struct lto_out_decl_state *state) 262338fd1498Szrj { 262438fd1498Szrj while (pass) 262538fd1498Szrj { 262638fd1498Szrj ipa_opt_pass_d *ipa_pass = (ipa_opt_pass_d *)pass; 262738fd1498Szrj gcc_assert (!current_function_decl); 262838fd1498Szrj gcc_assert (!cfun); 262938fd1498Szrj gcc_assert (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS); 263038fd1498Szrj if (pass->type == IPA_PASS 263138fd1498Szrj && ipa_pass->write_summary 263238fd1498Szrj && pass->gate (cfun)) 263338fd1498Szrj { 263438fd1498Szrj /* If a timevar is present, start it. */ 263538fd1498Szrj if (pass->tv_id) 263638fd1498Szrj timevar_push (pass->tv_id); 263738fd1498Szrj 263838fd1498Szrj pass_init_dump_file (pass); 263938fd1498Szrj 264038fd1498Szrj current_pass = pass; 264138fd1498Szrj ipa_pass->write_summary (); 264238fd1498Szrj 264338fd1498Szrj pass_fini_dump_file (pass); 264438fd1498Szrj 264538fd1498Szrj /* If a timevar is present, start it. */ 264638fd1498Szrj if (pass->tv_id) 264738fd1498Szrj timevar_pop (pass->tv_id); 264838fd1498Szrj } 264938fd1498Szrj 265038fd1498Szrj if (pass->sub && pass->sub->type != GIMPLE_PASS) 265138fd1498Szrj ipa_write_summaries_2 (pass->sub, state); 265238fd1498Szrj 265338fd1498Szrj pass = pass->next; 265438fd1498Szrj } 265538fd1498Szrj } 265638fd1498Szrj 265738fd1498Szrj /* Helper function of ipa_write_summaries. Creates and destroys the 265838fd1498Szrj decl state and calls ipa_write_summaries_2 for all passes that have 265938fd1498Szrj summaries. SET is the set of nodes to be written. */ 266038fd1498Szrj 266138fd1498Szrj static void 266238fd1498Szrj ipa_write_summaries_1 (lto_symtab_encoder_t encoder) 266338fd1498Szrj { 266438fd1498Szrj pass_manager *passes = g->get_passes (); 266538fd1498Szrj struct lto_out_decl_state *state = lto_new_out_decl_state (); 266638fd1498Szrj state->symtab_node_encoder = encoder; 266738fd1498Szrj 266838fd1498Szrj lto_output_init_mode_table (); 266938fd1498Szrj lto_push_out_decl_state (state); 267038fd1498Szrj 267138fd1498Szrj gcc_assert (!flag_wpa); 267238fd1498Szrj ipa_write_summaries_2 (passes->all_regular_ipa_passes, state); 267338fd1498Szrj 267438fd1498Szrj write_lto (); 267538fd1498Szrj 267638fd1498Szrj gcc_assert (lto_get_out_decl_state () == state); 267738fd1498Szrj lto_pop_out_decl_state (); 267838fd1498Szrj lto_delete_out_decl_state (state); 267938fd1498Szrj } 268038fd1498Szrj 268138fd1498Szrj /* Write out summaries for all the nodes in the callgraph. */ 268238fd1498Szrj 268338fd1498Szrj void 268438fd1498Szrj ipa_write_summaries (void) 268538fd1498Szrj { 268638fd1498Szrj lto_symtab_encoder_t encoder; 268738fd1498Szrj int i, order_pos; 268838fd1498Szrj varpool_node *vnode; 268938fd1498Szrj struct cgraph_node *node; 269038fd1498Szrj struct cgraph_node **order; 269138fd1498Szrj 269238fd1498Szrj if ((!flag_generate_lto && !flag_generate_offload) || seen_error ()) 269338fd1498Szrj return; 269438fd1498Szrj 269538fd1498Szrj select_what_to_stream (); 269638fd1498Szrj 269738fd1498Szrj encoder = lto_symtab_encoder_new (false); 269838fd1498Szrj 269938fd1498Szrj /* Create the callgraph set in the same order used in 270038fd1498Szrj cgraph_expand_all_functions. This mostly facilitates debugging, 270138fd1498Szrj since it causes the gimple file to be processed in the same order 270238fd1498Szrj as the source code. */ 270338fd1498Szrj order = XCNEWVEC (struct cgraph_node *, symtab->cgraph_count); 270438fd1498Szrj order_pos = ipa_reverse_postorder (order); 270538fd1498Szrj gcc_assert (order_pos == symtab->cgraph_count); 270638fd1498Szrj 270738fd1498Szrj for (i = order_pos - 1; i >= 0; i--) 270838fd1498Szrj { 270938fd1498Szrj struct cgraph_node *node = order[i]; 271038fd1498Szrj 271138fd1498Szrj if (node->has_gimple_body_p ()) 271238fd1498Szrj { 271338fd1498Szrj /* When streaming out references to statements as part of some IPA 271438fd1498Szrj pass summary, the statements need to have uids assigned and the 271538fd1498Szrj following does that for all the IPA passes here. Naturally, this 271638fd1498Szrj ordering then matches the one IPA-passes get in their stmt_fixup 271738fd1498Szrj hooks. */ 271838fd1498Szrj 271938fd1498Szrj push_cfun (DECL_STRUCT_FUNCTION (node->decl)); 272038fd1498Szrj renumber_gimple_stmt_uids (); 272138fd1498Szrj pop_cfun (); 272238fd1498Szrj } 272338fd1498Szrj if (node->definition && node->need_lto_streaming) 272438fd1498Szrj lto_set_symtab_encoder_in_partition (encoder, node); 272538fd1498Szrj } 272638fd1498Szrj 272738fd1498Szrj FOR_EACH_DEFINED_FUNCTION (node) 272838fd1498Szrj if (node->alias && node->need_lto_streaming) 272938fd1498Szrj lto_set_symtab_encoder_in_partition (encoder, node); 273038fd1498Szrj FOR_EACH_DEFINED_VARIABLE (vnode) 273138fd1498Szrj if (vnode->need_lto_streaming) 273238fd1498Szrj lto_set_symtab_encoder_in_partition (encoder, vnode); 273338fd1498Szrj 273438fd1498Szrj ipa_write_summaries_1 (compute_ltrans_boundary (encoder)); 273538fd1498Szrj 273638fd1498Szrj free (order); 273738fd1498Szrj } 273838fd1498Szrj 273938fd1498Szrj /* Same as execute_pass_list but assume that subpasses of IPA passes 274038fd1498Szrj are local passes. If SET is not NULL, write out optimization summaries of 274138fd1498Szrj only those node in SET. */ 274238fd1498Szrj 274338fd1498Szrj static void 274438fd1498Szrj ipa_write_optimization_summaries_1 (opt_pass *pass, 274538fd1498Szrj struct lto_out_decl_state *state) 274638fd1498Szrj { 274738fd1498Szrj while (pass) 274838fd1498Szrj { 274938fd1498Szrj ipa_opt_pass_d *ipa_pass = (ipa_opt_pass_d *)pass; 275038fd1498Szrj gcc_assert (!current_function_decl); 275138fd1498Szrj gcc_assert (!cfun); 275238fd1498Szrj gcc_assert (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS); 275338fd1498Szrj if (pass->type == IPA_PASS 275438fd1498Szrj && ipa_pass->write_optimization_summary 275538fd1498Szrj && pass->gate (cfun)) 275638fd1498Szrj { 275738fd1498Szrj /* If a timevar is present, start it. */ 275838fd1498Szrj if (pass->tv_id) 275938fd1498Szrj timevar_push (pass->tv_id); 276038fd1498Szrj 276138fd1498Szrj pass_init_dump_file (pass); 276238fd1498Szrj 276338fd1498Szrj current_pass = pass; 276438fd1498Szrj ipa_pass->write_optimization_summary (); 276538fd1498Szrj 276638fd1498Szrj pass_fini_dump_file (pass); 276738fd1498Szrj 276838fd1498Szrj /* If a timevar is present, start it. */ 276938fd1498Szrj if (pass->tv_id) 277038fd1498Szrj timevar_pop (pass->tv_id); 277138fd1498Szrj } 277238fd1498Szrj 277338fd1498Szrj if (pass->sub && pass->sub->type != GIMPLE_PASS) 277438fd1498Szrj ipa_write_optimization_summaries_1 (pass->sub, state); 277538fd1498Szrj 277638fd1498Szrj pass = pass->next; 277738fd1498Szrj } 277838fd1498Szrj } 277938fd1498Szrj 278038fd1498Szrj /* Write all the optimization summaries for the cgraph nodes in SET. If SET is 278138fd1498Szrj NULL, write out all summaries of all nodes. */ 278238fd1498Szrj 278338fd1498Szrj void 278438fd1498Szrj ipa_write_optimization_summaries (lto_symtab_encoder_t encoder) 278538fd1498Szrj { 278638fd1498Szrj struct lto_out_decl_state *state = lto_new_out_decl_state (); 278738fd1498Szrj lto_symtab_encoder_iterator lsei; 278838fd1498Szrj state->symtab_node_encoder = encoder; 278938fd1498Szrj 279038fd1498Szrj lto_output_init_mode_table (); 279138fd1498Szrj lto_push_out_decl_state (state); 279238fd1498Szrj for (lsei = lsei_start_function_in_partition (encoder); 279338fd1498Szrj !lsei_end_p (lsei); lsei_next_function_in_partition (&lsei)) 279438fd1498Szrj { 279538fd1498Szrj struct cgraph_node *node = lsei_cgraph_node (lsei); 279638fd1498Szrj /* When streaming out references to statements as part of some IPA 279738fd1498Szrj pass summary, the statements need to have uids assigned. 279838fd1498Szrj 279938fd1498Szrj For functions newly born at WPA stage we need to initialize 280038fd1498Szrj the uids here. */ 280138fd1498Szrj if (node->definition 280238fd1498Szrj && gimple_has_body_p (node->decl)) 280338fd1498Szrj { 280438fd1498Szrj push_cfun (DECL_STRUCT_FUNCTION (node->decl)); 280538fd1498Szrj renumber_gimple_stmt_uids (); 280638fd1498Szrj pop_cfun (); 280738fd1498Szrj } 280838fd1498Szrj } 280938fd1498Szrj 281038fd1498Szrj gcc_assert (flag_wpa); 281138fd1498Szrj pass_manager *passes = g->get_passes (); 281238fd1498Szrj ipa_write_optimization_summaries_1 (passes->all_regular_ipa_passes, state); 281338fd1498Szrj 281438fd1498Szrj write_lto (); 281538fd1498Szrj 281638fd1498Szrj gcc_assert (lto_get_out_decl_state () == state); 281738fd1498Szrj lto_pop_out_decl_state (); 281838fd1498Szrj lto_delete_out_decl_state (state); 281938fd1498Szrj } 282038fd1498Szrj 282138fd1498Szrj /* Same as execute_pass_list but assume that subpasses of IPA passes 282238fd1498Szrj are local passes. */ 282338fd1498Szrj 282438fd1498Szrj static void 282538fd1498Szrj ipa_read_summaries_1 (opt_pass *pass) 282638fd1498Szrj { 282738fd1498Szrj while (pass) 282838fd1498Szrj { 282938fd1498Szrj ipa_opt_pass_d *ipa_pass = (ipa_opt_pass_d *) pass; 283038fd1498Szrj 283138fd1498Szrj gcc_assert (!current_function_decl); 283238fd1498Szrj gcc_assert (!cfun); 283338fd1498Szrj gcc_assert (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS); 283438fd1498Szrj 283538fd1498Szrj if (pass->gate (cfun)) 283638fd1498Szrj { 283738fd1498Szrj if (pass->type == IPA_PASS && ipa_pass->read_summary) 283838fd1498Szrj { 283938fd1498Szrj /* If a timevar is present, start it. */ 284038fd1498Szrj if (pass->tv_id) 284138fd1498Szrj timevar_push (pass->tv_id); 284238fd1498Szrj 284338fd1498Szrj pass_init_dump_file (pass); 284438fd1498Szrj 284538fd1498Szrj current_pass = pass; 284638fd1498Szrj ipa_pass->read_summary (); 284738fd1498Szrj 284838fd1498Szrj pass_fini_dump_file (pass); 284938fd1498Szrj 285038fd1498Szrj /* Stop timevar. */ 285138fd1498Szrj if (pass->tv_id) 285238fd1498Szrj timevar_pop (pass->tv_id); 285338fd1498Szrj } 285438fd1498Szrj 285538fd1498Szrj if (pass->sub && pass->sub->type != GIMPLE_PASS) 285638fd1498Szrj ipa_read_summaries_1 (pass->sub); 285738fd1498Szrj } 285838fd1498Szrj pass = pass->next; 285938fd1498Szrj } 286038fd1498Szrj } 286138fd1498Szrj 286238fd1498Szrj 286338fd1498Szrj /* Read all the summaries for all_regular_ipa_passes. */ 286438fd1498Szrj 286538fd1498Szrj void 286638fd1498Szrj ipa_read_summaries (void) 286738fd1498Szrj { 286838fd1498Szrj pass_manager *passes = g->get_passes (); 286938fd1498Szrj ipa_read_summaries_1 (passes->all_regular_ipa_passes); 287038fd1498Szrj } 287138fd1498Szrj 287238fd1498Szrj /* Same as execute_pass_list but assume that subpasses of IPA passes 287338fd1498Szrj are local passes. */ 287438fd1498Szrj 287538fd1498Szrj static void 287638fd1498Szrj ipa_read_optimization_summaries_1 (opt_pass *pass) 287738fd1498Szrj { 287838fd1498Szrj while (pass) 287938fd1498Szrj { 288038fd1498Szrj ipa_opt_pass_d *ipa_pass = (ipa_opt_pass_d *) pass; 288138fd1498Szrj 288238fd1498Szrj gcc_assert (!current_function_decl); 288338fd1498Szrj gcc_assert (!cfun); 288438fd1498Szrj gcc_assert (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS); 288538fd1498Szrj 288638fd1498Szrj if (pass->gate (cfun)) 288738fd1498Szrj { 288838fd1498Szrj if (pass->type == IPA_PASS && ipa_pass->read_optimization_summary) 288938fd1498Szrj { 289038fd1498Szrj /* If a timevar is present, start it. */ 289138fd1498Szrj if (pass->tv_id) 289238fd1498Szrj timevar_push (pass->tv_id); 289338fd1498Szrj 289438fd1498Szrj pass_init_dump_file (pass); 289538fd1498Szrj 289638fd1498Szrj current_pass = pass; 289738fd1498Szrj ipa_pass->read_optimization_summary (); 289838fd1498Szrj 289938fd1498Szrj pass_fini_dump_file (pass); 290038fd1498Szrj 290138fd1498Szrj /* Stop timevar. */ 290238fd1498Szrj if (pass->tv_id) 290338fd1498Szrj timevar_pop (pass->tv_id); 290438fd1498Szrj } 290538fd1498Szrj 290638fd1498Szrj if (pass->sub && pass->sub->type != GIMPLE_PASS) 290738fd1498Szrj ipa_read_optimization_summaries_1 (pass->sub); 290838fd1498Szrj } 290938fd1498Szrj pass = pass->next; 291038fd1498Szrj } 291138fd1498Szrj } 291238fd1498Szrj 291338fd1498Szrj /* Read all the summaries for all_regular_ipa_passes. */ 291438fd1498Szrj 291538fd1498Szrj void 291638fd1498Szrj ipa_read_optimization_summaries (void) 291738fd1498Szrj { 291838fd1498Szrj pass_manager *passes = g->get_passes (); 291938fd1498Szrj ipa_read_optimization_summaries_1 (passes->all_regular_ipa_passes); 292038fd1498Szrj } 292138fd1498Szrj 292238fd1498Szrj /* Same as execute_pass_list but assume that subpasses of IPA passes 292338fd1498Szrj are local passes. */ 292438fd1498Szrj void 292538fd1498Szrj execute_ipa_pass_list (opt_pass *pass) 292638fd1498Szrj { 292738fd1498Szrj do 292838fd1498Szrj { 292938fd1498Szrj gcc_assert (!current_function_decl); 293038fd1498Szrj gcc_assert (!cfun); 293138fd1498Szrj gcc_assert (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS); 293238fd1498Szrj if (execute_one_pass (pass) && pass->sub) 293338fd1498Szrj { 293438fd1498Szrj if (pass->sub->type == GIMPLE_PASS) 293538fd1498Szrj { 293638fd1498Szrj invoke_plugin_callbacks (PLUGIN_EARLY_GIMPLE_PASSES_START, NULL); 293738fd1498Szrj do_per_function_toporder ((void (*)(function *, void *)) 293838fd1498Szrj execute_pass_list, 293938fd1498Szrj pass->sub); 294038fd1498Szrj invoke_plugin_callbacks (PLUGIN_EARLY_GIMPLE_PASSES_END, NULL); 294138fd1498Szrj } 294238fd1498Szrj else if (pass->sub->type == SIMPLE_IPA_PASS 294338fd1498Szrj || pass->sub->type == IPA_PASS) 294438fd1498Szrj execute_ipa_pass_list (pass->sub); 294538fd1498Szrj else 294638fd1498Szrj gcc_unreachable (); 294738fd1498Szrj } 294838fd1498Szrj gcc_assert (!current_function_decl); 294938fd1498Szrj symtab->process_new_functions (); 295038fd1498Szrj pass = pass->next; 295138fd1498Szrj } 295238fd1498Szrj while (pass); 295338fd1498Szrj } 295438fd1498Szrj 295538fd1498Szrj /* Execute stmt fixup hooks of all passes in PASS for NODE and STMTS. */ 295638fd1498Szrj 295738fd1498Szrj static void 295838fd1498Szrj execute_ipa_stmt_fixups (opt_pass *pass, 295938fd1498Szrj struct cgraph_node *node, gimple **stmts) 296038fd1498Szrj { 296138fd1498Szrj while (pass) 296238fd1498Szrj { 296338fd1498Szrj /* Execute all of the IPA_PASSes in the list. */ 296438fd1498Szrj if (pass->type == IPA_PASS 296538fd1498Szrj && pass->gate (cfun)) 296638fd1498Szrj { 296738fd1498Szrj ipa_opt_pass_d *ipa_pass = (ipa_opt_pass_d *) pass; 296838fd1498Szrj 296938fd1498Szrj if (ipa_pass->stmt_fixup) 297038fd1498Szrj { 297138fd1498Szrj pass_init_dump_file (pass); 297238fd1498Szrj /* If a timevar is present, start it. */ 297338fd1498Szrj if (pass->tv_id) 297438fd1498Szrj timevar_push (pass->tv_id); 297538fd1498Szrj 297638fd1498Szrj current_pass = pass; 297738fd1498Szrj ipa_pass->stmt_fixup (node, stmts); 297838fd1498Szrj 297938fd1498Szrj /* Stop timevar. */ 298038fd1498Szrj if (pass->tv_id) 298138fd1498Szrj timevar_pop (pass->tv_id); 298238fd1498Szrj pass_fini_dump_file (pass); 298338fd1498Szrj } 298438fd1498Szrj if (pass->sub) 298538fd1498Szrj execute_ipa_stmt_fixups (pass->sub, node, stmts); 298638fd1498Szrj } 298738fd1498Szrj pass = pass->next; 298838fd1498Szrj } 298938fd1498Szrj } 299038fd1498Szrj 299138fd1498Szrj /* Execute stmt fixup hooks of all IPA passes for NODE and STMTS. */ 299238fd1498Szrj 299338fd1498Szrj void 299438fd1498Szrj execute_all_ipa_stmt_fixups (struct cgraph_node *node, gimple **stmts) 299538fd1498Szrj { 299638fd1498Szrj pass_manager *passes = g->get_passes (); 299738fd1498Szrj execute_ipa_stmt_fixups (passes->all_regular_ipa_passes, node, stmts); 299838fd1498Szrj } 299938fd1498Szrj 300038fd1498Szrj 300138fd1498Szrj extern void debug_properties (unsigned int); 300238fd1498Szrj extern void dump_properties (FILE *, unsigned int); 300338fd1498Szrj 300438fd1498Szrj DEBUG_FUNCTION void 300538fd1498Szrj dump_properties (FILE *dump, unsigned int props) 300638fd1498Szrj { 300738fd1498Szrj fprintf (dump, "Properties:\n"); 300838fd1498Szrj if (props & PROP_gimple_any) 300938fd1498Szrj fprintf (dump, "PROP_gimple_any\n"); 301038fd1498Szrj if (props & PROP_gimple_lcf) 301138fd1498Szrj fprintf (dump, "PROP_gimple_lcf\n"); 301238fd1498Szrj if (props & PROP_gimple_leh) 301338fd1498Szrj fprintf (dump, "PROP_gimple_leh\n"); 301438fd1498Szrj if (props & PROP_cfg) 301538fd1498Szrj fprintf (dump, "PROP_cfg\n"); 301638fd1498Szrj if (props & PROP_ssa) 301738fd1498Szrj fprintf (dump, "PROP_ssa\n"); 301838fd1498Szrj if (props & PROP_no_crit_edges) 301938fd1498Szrj fprintf (dump, "PROP_no_crit_edges\n"); 302038fd1498Szrj if (props & PROP_rtl) 302138fd1498Szrj fprintf (dump, "PROP_rtl\n"); 302238fd1498Szrj if (props & PROP_gimple_lomp) 302338fd1498Szrj fprintf (dump, "PROP_gimple_lomp\n"); 302438fd1498Szrj if (props & PROP_gimple_lomp_dev) 302538fd1498Szrj fprintf (dump, "PROP_gimple_lomp_dev\n"); 302638fd1498Szrj if (props & PROP_gimple_lcx) 302738fd1498Szrj fprintf (dump, "PROP_gimple_lcx\n"); 302838fd1498Szrj if (props & PROP_gimple_lvec) 302938fd1498Szrj fprintf (dump, "PROP_gimple_lvec\n"); 303038fd1498Szrj if (props & PROP_cfglayout) 303138fd1498Szrj fprintf (dump, "PROP_cfglayout\n"); 303238fd1498Szrj } 303338fd1498Szrj 303438fd1498Szrj DEBUG_FUNCTION void 303538fd1498Szrj debug_properties (unsigned int props) 303638fd1498Szrj { 303738fd1498Szrj dump_properties (stderr, props); 303838fd1498Szrj } 303938fd1498Szrj 304038fd1498Szrj /* Called by local passes to see if function is called by already processed nodes. 304138fd1498Szrj Because we process nodes in topological order, this means that function is 304238fd1498Szrj in recursive cycle or we introduced new direct calls. */ 304338fd1498Szrj bool 304438fd1498Szrj function_called_by_processed_nodes_p (void) 304538fd1498Szrj { 304638fd1498Szrj struct cgraph_edge *e; 304738fd1498Szrj for (e = cgraph_node::get (current_function_decl)->callers; 304838fd1498Szrj e; 304938fd1498Szrj e = e->next_caller) 305038fd1498Szrj { 305138fd1498Szrj if (e->caller->decl == current_function_decl) 305238fd1498Szrj continue; 305338fd1498Szrj if (!e->caller->has_gimple_body_p ()) 305438fd1498Szrj continue; 305538fd1498Szrj if (TREE_ASM_WRITTEN (e->caller->decl)) 305638fd1498Szrj continue; 305738fd1498Szrj if (!e->caller->process && !e->caller->global.inlined_to) 305838fd1498Szrj break; 305938fd1498Szrj } 306038fd1498Szrj if (dump_file && e) 306138fd1498Szrj { 306238fd1498Szrj fprintf (dump_file, "Already processed call to:\n"); 306338fd1498Szrj e->caller->dump (dump_file); 306438fd1498Szrj } 306538fd1498Szrj return e != NULL; 306638fd1498Szrj } 306738fd1498Szrj 306838fd1498Szrj #include "gt-passes.h" 3069