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 *
clone()8238fd1498Szrj opt_pass::clone ()
8338fd1498Szrj {
8438fd1498Szrj internal_error ("pass %s does not support cloning", name);
8538fd1498Szrj }
8638fd1498Szrj
8738fd1498Szrj void
set_pass_param(unsigned int,bool)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
gate(function *)9538fd1498Szrj opt_pass::gate (function *)
9638fd1498Szrj {
9738fd1498Szrj return true;
9838fd1498Szrj }
9938fd1498Szrj
10038fd1498Szrj unsigned int
execute(function *)10138fd1498Szrj opt_pass::execute (function *)
10238fd1498Szrj {
10338fd1498Szrj return 0;
10438fd1498Szrj }
10538fd1498Szrj
opt_pass(const pass_data & data,context * ctxt)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
execute_early_local_passes()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
execute_pass_mode_switching()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
print_current_pass(FILE * file)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
debug_pass(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
rest_of_decl_compilation(tree decl,int top_level,int at_end)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
rest_of_type_compilation(tree type,int toplev)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::
finish_optimization_passes(void)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 {
36658e805e6Szrj dumps->dump_start (pass_combine_1->static_pass_number, NULL);
36738fd1498Szrj print_combine_total_stats ();
36858e805e6Szrj 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
execute_build_ssa_passes(void)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:
pass_build_ssa_passes(gcc::context * ctxt)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: */
gate(function *)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
execute(function *)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:
pass_chkp_instrumentation_passes(gcc::context * ctxt)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: */
gate(function *)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:
pass_local_optimization_passes(gcc::context * ctxt)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: */
gate(function *)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 *
make_pass_build_ssa_passes(gcc::context * ctxt)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 *
make_pass_chkp_instrumentation_passes(gcc::context * ctxt)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 *
make_pass_local_optimization_passes(gcc::context * ctxt)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:
pass_all_early_optimizations(gcc::context * ctxt)53238fd1498Szrj pass_all_early_optimizations (gcc::context *ctxt)
53338fd1498Szrj : gimple_opt_pass (pass_data_all_early_optimizations, ctxt)
53438fd1498Szrj {}
53538fd1498Szrj
53638fd1498Szrj /* opt_pass methods: */
gate(function *)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 *
make_pass_all_early_optimizations(gcc::context * ctxt)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:
pass_all_optimizations(gcc::context * ctxt)57238fd1498Szrj pass_all_optimizations (gcc::context *ctxt)
57338fd1498Szrj : gimple_opt_pass (pass_data_all_optimizations, ctxt)
57438fd1498Szrj {}
57538fd1498Szrj
57638fd1498Szrj /* opt_pass methods: */
gate(function *)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 *
make_pass_all_optimizations(gcc::context * ctxt)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:
pass_all_optimizations_g(gcc::context * ctxt)60738fd1498Szrj pass_all_optimizations_g (gcc::context *ctxt)
60838fd1498Szrj : gimple_opt_pass (pass_data_all_optimizations_g, ctxt)
60938fd1498Szrj {}
61038fd1498Szrj
61138fd1498Szrj /* opt_pass methods: */
gate(function *)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 *
make_pass_all_optimizations_g(gcc::context * ctxt)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:
pass_rest_of_compilation(gcc::context * ctxt)64238fd1498Szrj pass_rest_of_compilation (gcc::context *ctxt)
64338fd1498Szrj : rtl_opt_pass (pass_data_rest_of_compilation, ctxt)
64438fd1498Szrj {}
64538fd1498Szrj
64638fd1498Szrj /* opt_pass methods: */
gate(function *)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 *
make_pass_rest_of_compilation(gcc::context * ctxt)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:
pass_postreload(gcc::context * ctxt)68238fd1498Szrj pass_postreload (gcc::context *ctxt)
68338fd1498Szrj : rtl_opt_pass (pass_data_postreload, ctxt)
68438fd1498Szrj {}
68538fd1498Szrj
68638fd1498Szrj /* opt_pass methods: */
gate(function *)68738fd1498Szrj virtual bool gate (function *) { return reload_completed; }
68838fd1498Szrj
68938fd1498Szrj }; // class pass_postreload
69038fd1498Szrj
69138fd1498Szrj } // anon namespace
69238fd1498Szrj
69338fd1498Szrj static rtl_opt_pass *
make_pass_postreload(gcc::context * ctxt)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:
pass_late_compilation(gcc::context * ctxt)71738fd1498Szrj pass_late_compilation (gcc::context *ctxt)
71838fd1498Szrj : rtl_opt_pass (pass_data_late_compilation, ctxt)
71938fd1498Szrj {}
72038fd1498Szrj
72138fd1498Szrj /* opt_pass methods: */
gate(function *)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 *
make_pass_late_compilation(gcc::context * ctxt)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::
set_pass_for_id(int id,opt_pass * pass)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 *
get_pass_for_id(int id)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
register_one_dump_file(opt_pass * pass)77238fd1498Szrj register_one_dump_file (opt_pass *pass)
77338fd1498Szrj {
77438fd1498Szrj g->get_passes ()->register_one_dump_file (pass);
77538fd1498Szrj }
77638fd1498Szrj
77738fd1498Szrj void
register_one_dump_file(opt_pass * pass)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
register_dump_files(opt_pass * pass)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
register_pass_name(opt_pass * pass,const char * name)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
passes_pass_traverse(const char * const & name,opt_pass * const & pass,void *)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
create_pass_tab(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
dump_one_pass(opt_pass * pass,int pass_indent)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
dump_pass_list(opt_pass * pass,int indent)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
dump_passes(void)94738fd1498Szrj dump_passes (void)
94838fd1498Szrj {
94938fd1498Szrj g->get_passes ()->dump_passes ();
95038fd1498Szrj }
95138fd1498Szrj
95238fd1498Szrj void
dump_passes()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 *
get_pass_by_name(const char * name)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
enable_disable_pass(const char * arg,bool is_enable)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
enable_pass(const char * arg)117838fd1498Szrj enable_pass (const char *arg)
117938fd1498Szrj {
118038fd1498Szrj enable_disable_pass (arg, true);
118138fd1498Szrj }
118238fd1498Szrj
118338fd1498Szrj /* Disable pass specified by ARG. */
118438fd1498Szrj
118538fd1498Szrj void
disable_pass(const char * arg)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
is_pass_explicitly_enabled_or_disabled(opt_pass * pass,tree func,vec<uid_range_p> tab)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
add_pass_instance(opt_pass * new_pass,bool track_duplicates,opt_pass * initial_pass)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 **
next_pass_1(opt_pass ** list,opt_pass * pass,opt_pass * initial_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
position_pass(struct register_pass_info * new_pass_info,opt_pass ** pass_list)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
register_pass(struct register_pass_info * pass_info)142338fd1498Szrj register_pass (struct register_pass_info *pass_info)
142438fd1498Szrj {
142538fd1498Szrj g->get_passes ()->register_pass (pass_info);
142638fd1498Szrj }
142738fd1498Szrj
142838fd1498Szrj void
register_pass(opt_pass * pass,pass_positioning_ops pos,const char * ref_pass_name,int ref_pass_inst_number)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
register_pass(struct register_pass_info * pass_info)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
pass_manager(context * ctxt)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
delete_pass_tree(opt_pass * pass)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
~pass_manager()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
do_per_function(void (* callback)(function *,void * data),void * data)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
remove_cgraph_node_from_order(cgraph_node * node,void * data)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
do_per_function_toporder(void (* callback)(function *,void * data),void * data)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
execute_function_dump(function * fn,void * data)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
emergency_dump_function()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
check_profile_consistency(int index,int subpass,bool run)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
dump_profile_report(void)183238fd1498Szrj dump_profile_report (void)
183338fd1498Szrj {
183438fd1498Szrj g->get_passes ()->dump_profile_report ();
183538fd1498Szrj }
183638fd1498Szrj
183738fd1498Szrj void
dump_profile_report()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
execute_function_todo(function * fn,void * data)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 {
1947*e215fc28Szrj cleanup_tree_cfg (flags & TODO_update_ssa_any);
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
execute_todo(unsigned int flags)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
verify_interpass_invariants(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
clear_last_verified(function * fn,void * data ATTRIBUTE_UNUSED)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
verify_curr_properties(function * fn,void * data)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
release_dump_file_name(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
pass_init_dump_file(opt_pass * pass)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
pass_fini_dump_file(opt_pass * pass)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
update_properties_after_pass(function * fn,void * data)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
execute_ipa_summary_passes(ipa_opt_pass_d * ipa_pass)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
execute_one_ipa_transform_pass(struct cgraph_node * node,ipa_opt_pass_d * ipa_pass)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
execute_all_ipa_transforms(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
override_gate_status(opt_pass * pass,tree func,bool gate_status)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
determine_pass_name_match(const char * pass_name,char * criterion)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
should_skip_pass_p(opt_pass * pass)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
skip_pass(opt_pass * pass)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
execute_one_pass(opt_pass * pass)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
execute_pass_list_1(opt_pass * pass)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
execute_pass_list(function * fn,opt_pass * pass)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
write_lto(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
ipa_write_summaries_2(opt_pass * pass,struct lto_out_decl_state * state)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
ipa_write_summaries_1(lto_symtab_encoder_t encoder)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
ipa_write_summaries(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
ipa_write_optimization_summaries_1(opt_pass * pass,struct lto_out_decl_state * state)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
ipa_write_optimization_summaries(lto_symtab_encoder_t encoder)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
ipa_read_summaries_1(opt_pass * pass)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
ipa_read_summaries(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
ipa_read_optimization_summaries_1(opt_pass * pass)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
ipa_read_optimization_summaries(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
execute_ipa_pass_list(opt_pass * pass)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
execute_ipa_stmt_fixups(opt_pass * pass,struct cgraph_node * node,gimple ** stmts)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
execute_all_ipa_stmt_fixups(struct cgraph_node * node,gimple ** stmts)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
dump_properties(FILE * dump,unsigned int props)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
debug_properties(unsigned int props)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
function_called_by_processed_nodes_p(void)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