/* Top level of GCC compilers (cc1, cc1plus, etc.)
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+ Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
for more details.
You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
/* This is the top level of cc1/c++.
It parses command args, opens files, invokes the various passes
#include "intl.h"
#include "ggc.h"
#include "graph.h"
-#include "loop.h"
#include "regs.h"
#include "timevar.h"
#include "diagnostic.h"
#include "opts.h"
#include "coverage.h"
#include "value-prof.h"
-#include "alloc-pool.h"
+#include "tree-inline.h"
+#include "tree-flow.h"
#include "tree-pass.h"
+#include "tree-dump.h"
+#include "df.h"
+#include "predict.h"
#if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
#include "dwarf2out.h"
declarations for e.g. AIX 4.x. */
#endif
-#ifndef HAVE_conditional_execution
-#define HAVE_conditional_execution 0
-#endif
-
-/* Format to use to print dumpfile index value */
-#ifndef DUMPFILE_FORMAT
-#define DUMPFILE_FORMAT ".%02d."
-#endif
-
-/* Describes a dump file. */
-
-struct dump_file_info
-{
- /* The unique extension to apply, e.g. ".jump". */
- const char *const extension;
-
- /* The -d<c> character that enables this dump file. */
- char const debug_switch;
-
- /* True if there is a corresponding graph dump file. */
- char const graph_dump_p;
-
- /* True if the user selected this dump. */
- char enabled;
-
- /* True if the files have been initialized (ie truncated). */
- char initialized;
-};
-
-/* Enumerate the extant dump files. */
-
-enum dump_file_index
-{
- DFI_cgraph,
- DFI_rtl,
- DFI_sibling,
- DFI_eh,
- DFI_jump,
- DFI_null,
- DFI_cse,
- DFI_gcse,
- DFI_loop,
- DFI_bypass,
- DFI_cfg,
- DFI_bp,
- DFI_vpt,
- DFI_ce1,
- DFI_tracer,
- DFI_loop2,
- DFI_web,
- DFI_cse2,
- DFI_life,
- DFI_combine,
- DFI_ce2,
- DFI_regmove,
- DFI_sms,
- DFI_sched,
- DFI_lreg,
- DFI_greg,
- DFI_postreload,
- DFI_gcse2,
- DFI_flow2,
- DFI_peephole2,
- DFI_ce3,
- DFI_rnreg,
- DFI_bbro,
- DFI_branch_target_load,
- DFI_sched2,
- DFI_stack,
- DFI_vartrack,
- DFI_mach,
- DFI_dbr,
- DFI_MAX
-};
-
-/* Describes all the dump files. Should be kept in order of the
- pass and in sync with dump_file_index above.
+/* This is used for debugging. It allows the current pass to printed
+ from anywhere in compilation. */
+struct opt_pass *current_pass;
- Remaining -d letters:
-
- " e q "
- " F K O Q WXY "
-*/
-
-static struct dump_file_info dump_file_tbl[DFI_MAX] =
-{
- { "cgraph", 'U', 0, 0, 0 },
- { "rtl", 'r', 0, 0, 0 },
- { "sibling", 'i', 0, 0, 0 },
- { "eh", 'h', 0, 0, 0 },
- { "jump", 'j', 0, 0, 0 },
- { "null", 'u', 0, 0, 0 },
- { "cse", 's', 0, 0, 0 },
- { "gcse", 'G', 1, 0, 0 },
- { "loop", 'L', 1, 0, 0 },
- { "bypass", 'G', 1, 0, 0 }, /* Yes, duplicate enable switch. */
- { "cfg", 'f', 1, 0, 0 },
- { "bp", 'b', 1, 0, 0 },
- { "vpt", 'V', 1, 0, 0 },
- { "ce1", 'C', 1, 0, 0 },
- { "tracer", 'T', 1, 0, 0 },
- { "loop2", 'L', 1, 0, 0 },
- { "web", 'Z', 0, 0, 0 },
- { "cse2", 't', 1, 0, 0 },
- { "life", 'f', 1, 0, 0 }, /* Yes, duplicate enable switch. */
- { "combine", 'c', 1, 0, 0 },
- { "ce2", 'C', 1, 0, 0 },
- { "regmove", 'N', 1, 0, 0 },
- { "sms", 'm', 0, 0, 0 },
- { "sched", 'S', 1, 0, 0 },
- { "lreg", 'l', 1, 0, 0 },
- { "greg", 'g', 1, 0, 0 },
- { "postreload", 'o', 1, 0, 0 },
- { "gcse2", 'J', 0, 0, 0 },
- { "flow2", 'w', 1, 0, 0 },
- { "peephole2", 'z', 1, 0, 0 },
- { "ce3", 'E', 1, 0, 0 },
- { "rnreg", 'n', 1, 0, 0 },
- { "bbro", 'B', 1, 0, 0 },
- { "btl", 'd', 1, 0, 0 }, /* Yes, duplicate enable switch. */
- { "sched2", 'R', 1, 0, 0 },
- { "stack", 'k', 1, 0, 0 },
- { "vartrack", 'V', 1, 0, 0 }, /* Yes, duplicate enable switch. */
- { "mach", 'M', 1, 0, 0 },
- { "dbr", 'd', 0, 0, 0 },
-};
-
-/* Routine to open a dump file. Return true if the dump file is enabled. */
-
-static int
-open_dump_file (enum dump_file_index index, tree decl)
+/* Call from anywhere to find out what pass this is. Useful for
+ printing out debugging information deep inside an service
+ routine. */
+void
+print_current_pass (FILE *file)
{
- char *dump_name;
- const char *open_arg;
- char seq[16];
-
- if (! dump_file_tbl[index].enabled)
- return 0;
-
- timevar_push (TV_DUMP);
- if (dump_file != NULL)
- fclose (dump_file);
-
- sprintf (seq, DUMPFILE_FORMAT, index);
-
- if (! dump_file_tbl[index].initialized)
- {
- /* If we've not initialized the files, do so now. */
- if (graph_dump_format != no_graph
- && dump_file_tbl[index].graph_dump_p)
- {
- dump_name = concat (seq, dump_file_tbl[index].extension, NULL);
- clean_graph_dump_file (dump_base_name, dump_name);
- free (dump_name);
- }
- dump_file_tbl[index].initialized = 1;
- open_arg = "w";
- }
+ if (current_pass)
+ fprintf (file, "current pass = %s (%d)\n",
+ current_pass->name, current_pass->static_pass_number);
else
- open_arg = "a";
-
- dump_name = concat (dump_base_name, seq,
- dump_file_tbl[index].extension, NULL);
-
- dump_file = fopen (dump_name, open_arg);
- if (dump_file == NULL)
- fatal_error ("can't open %s: %m", dump_name);
-
- free (dump_name);
-
- if (decl)
- fprintf (dump_file, "\n;; Function %s%s\n\n",
- lang_hooks.decl_printable_name (decl, 2),
- cfun->function_frequency == FUNCTION_FREQUENCY_HOT
- ? " (hot)"
- : cfun->function_frequency == FUNCTION_FREQUENCY_UNLIKELY_EXECUTED
- ? " (unlikely executed)"
- : "");
-
- timevar_pop (TV_DUMP);
- return 1;
+ fprintf (file, "no current pass.\n");
}
-/* Routine to close a dump file. */
-static void
-close_dump_file (enum dump_file_index index,
- void (*func) (FILE *, rtx),
- rtx insns)
+/* Call from the debugger to get the current pass name. */
+void
+debug_pass (void)
{
- if (! dump_file)
- return;
-
- timevar_push (TV_DUMP);
- if (insns
- && graph_dump_format != no_graph
- && dump_file_tbl[index].graph_dump_p)
- {
- char seq[16];
- char *suffix;
+ print_current_pass (stderr);
+}
- sprintf (seq, DUMPFILE_FORMAT, index);
- suffix = concat (seq, dump_file_tbl[index].extension, NULL);
- print_rtl_graph_with_bb (dump_base_name, suffix, insns);
- free (suffix);
- }
- if (func && insns)
- func (dump_file, insns);
- fflush (dump_file);
- fclose (dump_file);
+/* Global variables used to communicate with passes. */
+int dump_flags;
+bool in_gimple_form;
+bool first_pass_instance;
- dump_file = NULL;
- timevar_pop (TV_DUMP);
-}
/* This is called from various places for FUNCTION_DECL, VAR_DECL,
and TYPE_DECL nodes.
This does nothing for local (non-static) variables, unless the
- variable is a register variable with an ASMSPEC. In that case, or
- if the variable is not an automatic, it sets up the RTL and
- outputs any assembler code (label definition, storage allocation
- and initialization).
+ variable is a register variable with DECL_ASSEMBLER_NAME set. In
+ that case, or if the variable is not an automatic, it sets up the
+ RTL and outputs any assembler code (label definition, storage
+ allocation and initialization).
- DECL is the declaration. If ASMSPEC is nonzero, it specifies
- the assembler symbol name to be used. TOP_LEVEL is nonzero
+ DECL is the declaration. TOP_LEVEL is nonzero
if this declaration is not within a function. */
void
rest_of_decl_compilation (tree decl,
- const char *asmspec,
int top_level,
int at_end)
{
}
}
+ /* Can't defer this, because it needs to happen before any
+ later function definitions are processed. */
+ if (DECL_ASSEMBLER_NAME_SET_P (decl) && DECL_REGISTER (decl))
+ make_decl_rtl (decl);
+
/* Forward declarations for nested functions are not "external",
but we need to treat them as if they were. */
if (TREE_STATIC (decl) || DECL_EXTERNAL (decl)
{
timevar_push (TV_VARCONST);
- if (asmspec)
- make_decl_rtl (decl, asmspec);
-
/* Don't output anything when a tentative file-scope definition
is seen. But at end of compilation, do output code for them.
- We do output all variables when unit-at-a-time is active and rely on
+ We do output all variables and rely on
callgraph code to defer them except for forward declarations
(see gcc.c-torture/compile/920624-1.c) */
if ((at_end
|| !DECL_DEFER_OUTPUT (decl)
- || (flag_unit_at_a_time && DECL_INITIAL (decl)))
+ || DECL_INITIAL (decl))
&& !DECL_EXTERNAL (decl))
{
- if (flag_unit_at_a_time && !cgraph_global_info_ready
- && TREE_CODE (decl) != FUNCTION_DECL && top_level
- /* If we defer processing of decls that have had their
- DECL_RTL set above (say, in make_decl_rtl),
- check_global_declarations() will clear it before
- assemble_variable has a chance to act on it. This
- would remove all traces of the register name in a
- global register variable, for example. */
- && !DECL_RTL_SET_P (decl))
- cgraph_varpool_finalize_decl (decl);
+ if (TREE_CODE (decl) != FUNCTION_DECL)
+ varpool_finalize_decl (decl);
else
assemble_variable (decl, top_level, at_end, 0);
}
timevar_pop (TV_VARCONST);
}
- else if (DECL_REGISTER (decl) && asmspec != 0)
- {
- if (decode_reg_name (asmspec) >= 0)
- {
- SET_DECL_RTL (decl, NULL_RTX);
- make_decl_rtl (decl, asmspec);
- }
- else
- {
- error ("%Hinvalid register name `%s' for register variable",
- &DECL_SOURCE_LOCATION (decl), asmspec);
- DECL_REGISTER (decl) = 0;
- if (!top_level)
- expand_decl (decl);
- }
- }
- else if (TREE_CODE (decl) == TYPE_DECL)
+ else if (TREE_CODE (decl) == TYPE_DECL
+ /* Like in rest_of_type_compilation, avoid confusing the debug
+ information machinery when there are errors. */
+ && !(sorrycount || errorcount))
{
timevar_push (TV_SYMOUT);
debug_hooks->type_decl (decl, !top_level);
timevar_pop (TV_SYMOUT);
}
+
+ /* Let cgraph know about the existence of variables. */
+ if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl))
+ varpool_node (decl);
}
/* Called after finishing a record, union or enumeral type. */
timevar_pop (TV_SYMOUT);
}
-/* Turn the RTL into assembly. */
-static void
-rest_of_handle_final (void)
-{
- timevar_push (TV_FINAL);
- {
- rtx x;
- const char *fnname;
-
- /* Get the function's name, as described by its RTL. This may be
- different from the DECL_NAME name used in the source file. */
-
- x = DECL_RTL (current_function_decl);
- if (!MEM_P (x))
- abort ();
- x = XEXP (x, 0);
- if (GET_CODE (x) != SYMBOL_REF)
- abort ();
- fnname = XSTR (x, 0);
-
- assemble_start_function (current_function_decl, fnname);
- final_start_function (get_insns (), asm_out_file, optimize);
- final (get_insns (), asm_out_file, optimize, 0);
- final_end_function ();
-
-#ifdef TARGET_UNWIND_INFO
- /* ??? The IA-64 ".handlerdata" directive must be issued before
- the ".endp" directive that closes the procedure descriptor. */
- output_function_exception_table ();
-#endif
-
- assemble_end_function (current_function_decl, fnname);
+\f
-#ifndef TARGET_UNWIND_INFO
- /* Otherwise, it feels unclean to switch sections in the middle. */
- output_function_exception_table ();
-#endif
+void
+finish_optimization_passes (void)
+{
+ enum tree_dump_index i;
+ struct dump_file_info *dfi;
+ char *name;
- if (! quiet_flag)
- fflush (asm_out_file);
+ timevar_push (TV_DUMP);
+ if (profile_arc_flag || flag_test_coverage || flag_branch_probabilities)
+ {
+ dump_file = dump_begin (pass_profile.pass.static_pass_number, NULL);
+ end_branch_prob ();
+ if (dump_file)
+ dump_end (pass_profile.pass.static_pass_number, dump_file);
+ }
- /* Release all memory allocated by flow. */
- free_basic_block_vars ();
+ if (optimize > 0)
+ {
+ dump_file = dump_begin (pass_combine.pass.static_pass_number, NULL);
+ if (dump_file)
+ {
+ dump_combine_total_stats (dump_file);
+ dump_end (pass_combine.pass.static_pass_number, dump_file);
+ }
+ }
- /* Release all memory held by regsets now. */
- regset_release_memory ();
- }
+ /* Do whatever is necessary to finish printing the graphs. */
+ if (graph_dump_format != no_graph)
+ for (i = TDI_end; (dfi = get_dump_file_info (i)) != NULL; ++i)
+ if (dump_initialized_p (i)
+ && (dfi->flags & TDF_GRAPH) != 0
+ && (name = get_dump_file_name (i)) != NULL)
+ {
+ finish_graph_dump_file (name);
+ free (name);
+ }
- /* Write DBX symbols if requested. */
+ timevar_pop (TV_DUMP);
+}
- /* Note that for those inline functions where we don't initially
- know for certain that we will be generating an out-of-line copy,
- the first invocation of this routine (rest_of_compilation) will
- skip over this code by doing a `goto exit_rest_of_compilation;'.
- Later on, wrapup_global_declarations will (indirectly) call
- rest_of_compilation again for those inline functions that need
- to have out-of-line copies generated. During that call, we
- *will* be routed past here. */
+static bool
+gate_rest_of_compilation (void)
+{
+ /* Early return if there were errors. We can run afoul of our
+ consistency checks, and there's not really much point in fixing them. */
+ return !(rtl_dump_and_exit || flag_syntax_only || errorcount || sorrycount);
+}
- timevar_push (TV_SYMOUT);
- (*debug_hooks->function_decl) (current_function_decl);
- timevar_pop (TV_SYMOUT);
+struct gimple_opt_pass pass_rest_of_compilation =
+{
+ {
+ GIMPLE_PASS,
+ NULL, /* name */
+ gate_rest_of_compilation, /* gate */
+ NULL, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ TV_REST_OF_COMPILATION, /* tv_id */
+ PROP_rtl, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_ggc_collect /* todo_flags_finish */
+ }
+};
- ggc_collect ();
- timevar_pop (TV_FINAL);
+static bool
+gate_postreload (void)
+{
+ return reload_completed;
}
-#ifdef DELAY_SLOTS
-/* Run delay slot optimization. */
-static void
-rest_of_handle_delay_slots (void)
+struct rtl_opt_pass pass_postreload =
{
- timevar_push (TV_DBR_SCHED);
- open_dump_file (DFI_dbr, current_function_decl);
+ {
+ RTL_PASS,
+ NULL, /* name */
+ gate_postreload, /* gate */
+ NULL, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ 0, /* tv_id */
+ PROP_rtl, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_ggc_collect | TODO_verify_rtl_sharing /* todo_flags_finish */
+ }
+};
- dbr_schedule (get_insns (), dump_file);
- close_dump_file (DFI_dbr, print_rtl, get_insns ());
- ggc_collect ();
+/* The root of the compilation pass tree, once constructed. */
+struct opt_pass *all_passes, *all_ipa_passes, *all_lowering_passes;
- timevar_pop (TV_DBR_SCHED);
-}
-#endif
+/* A map from static pass id to optimization pass. */
+struct opt_pass **passes_by_id;
+int passes_by_id_size;
+
+/* Set the static pass number of pass PASS to ID and record that
+ in the mapping from static pass number to pass. */
-#ifdef STACK_REGS
-/* Convert register usage from flat register file usage to a stack
- register file. */
static void
-rest_of_handle_stack_regs (void)
+set_pass_for_id (int id, struct opt_pass *pass)
{
-#if defined (HAVE_ATTR_length)
- /* If flow2 creates new instructions which need splitting
- and scheduling after reload is not done, they might not be
- split until final which doesn't allow splitting
- if HAVE_ATTR_length. */
-#ifdef INSN_SCHEDULING
- if (optimize && !flag_schedule_insns_after_reload)
-#else
- if (optimize)
-#endif
- {
- timevar_push (TV_SHORTEN_BRANCH);
- split_all_insns (1);
- timevar_pop (TV_SHORTEN_BRANCH);
- }
-#endif
-
- timevar_push (TV_REG_STACK);
- open_dump_file (DFI_stack, current_function_decl);
-
- if (reg_to_stack (dump_file) && optimize)
+ pass->static_pass_number = id;
+ if (passes_by_id_size <= id)
{
- if (cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_POST_REGSTACK
- | (flag_crossjumping ? CLEANUP_CROSSJUMP : 0))
- && (flag_reorder_blocks || flag_reorder_blocks_and_partition))
- {
- reorder_basic_blocks ();
- cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_POST_REGSTACK);
- }
+ passes_by_id = XRESIZEVEC (struct opt_pass *, passes_by_id, id + 1);
+ memset (passes_by_id + passes_by_id_size, 0,
+ (id + 1 - passes_by_id_size) * sizeof (void *));
+ passes_by_id_size = id + 1;
}
+ passes_by_id[id] = pass;
+}
- close_dump_file (DFI_stack, print_rtl_with_bb, get_insns ());
+/* Return the pass with the static pass number ID. */
- ggc_collect ();
- timevar_pop (TV_REG_STACK);
+struct opt_pass *
+get_pass_for_id (int id)
+{
+ if (id >= passes_by_id_size)
+ return NULL;
+ return passes_by_id[id];
}
-#endif
-/* Track the variables, ie. compute where the variable is stored at each position in function. */
+/* Iterate over the pass tree allocating dump file numbers. We want
+ to do this depth first, and independent of whether the pass is
+ enabled or not. */
+
static void
-rest_of_handle_variable_tracking (void)
+register_one_dump_file (struct opt_pass *pass)
{
- timevar_push (TV_VAR_TRACKING);
- open_dump_file (DFI_vartrack, current_function_decl);
-
- variable_tracking_main ();
+ char *dot_name, *flag_name, *glob_name;
+ const char *prefix;
+ char num[10];
+ int flags, id;
+
+ /* See below in next_pass_1. */
+ num[0] = '\0';
+ if (pass->static_pass_number != -1)
+ sprintf (num, "%d", ((int) pass->static_pass_number < 0
+ ? 1 : pass->static_pass_number));
+
+ dot_name = concat (".", pass->name, num, NULL);
+ if (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS)
+ prefix = "ipa-", flags = TDF_IPA;
+ else if (pass->type == GIMPLE_PASS)
+ prefix = "tree-", flags = TDF_TREE;
+ else
+ prefix = "rtl-", flags = TDF_RTL;
- close_dump_file (DFI_vartrack, print_rtl_with_bb, get_insns ());
- timevar_pop (TV_VAR_TRACKING);
+ flag_name = concat (prefix, pass->name, num, NULL);
+ glob_name = concat (prefix, pass->name, NULL);
+ id = dump_register (dot_name, flag_name, glob_name, flags);
+ set_pass_for_id (id, pass);
}
-/* Machine dependent reorg pass. */
-static void
-rest_of_handle_machine_reorg (void)
+/* Recursive worker function for register_dump_files. */
+
+static int
+register_dump_files_1 (struct opt_pass *pass, int properties)
{
- timevar_push (TV_MACH_DEP);
- open_dump_file (DFI_mach, current_function_decl);
+ do
+ {
+ int new_properties = (properties | pass->properties_provided)
+ & ~pass->properties_destroyed;
+
+ if (pass->name)
+ register_one_dump_file (pass);
- targetm.machine_dependent_reorg ();
+ if (pass->sub)
+ new_properties = register_dump_files_1 (pass->sub, new_properties);
+
+ /* If we have a gate, combine the properties that we could have with
+ and without the pass being examined. */
+ if (pass->gate)
+ properties &= new_properties;
+ else
+ properties = new_properties;
- close_dump_file (DFI_mach, print_rtl, get_insns ());
+ pass = pass->next;
+ }
+ while (pass);
- ggc_collect ();
- timevar_pop (TV_MACH_DEP);
+ return properties;
}
+/* Register the dump files for the pipeline starting at PASS.
+ PROPERTIES reflects the properties that are guaranteed to be available at
+ the beginning of the pipeline. */
-/* Run new register allocator. Return TRUE if we must exit
- rest_of_compilation upon return. */
-static bool
-rest_of_handle_new_regalloc (void)
+static void
+register_dump_files (struct opt_pass *pass,int properties)
{
- int failure;
+ pass->properties_required |= properties;
+ register_dump_files_1 (pass, properties);
+}
- timevar_push (TV_LOCAL_ALLOC);
- open_dump_file (DFI_lreg, current_function_decl);
+/* Add a pass to the pass list. Duplicate the pass if it's already
+ in the list. */
- delete_trivially_dead_insns (get_insns (), max_reg_num ());
- reg_alloc ();
+static struct opt_pass **
+next_pass_1 (struct opt_pass **list, struct opt_pass *pass)
+{
+ /* A nonzero static_pass_number indicates that the
+ pass is already in the list. */
+ if (pass->static_pass_number)
+ {
+ struct opt_pass *new;
+
+ new = XNEW (struct opt_pass);
+ memcpy (new, pass, sizeof (*new));
+ new->next = NULL;
+
+ new->todo_flags_start &= ~TODO_mark_first_instance;
+
+ /* Indicate to register_dump_files that this pass has duplicates,
+ and so it should rename the dump file. The first instance will
+ be -1, and be number of duplicates = -static_pass_number - 1.
+ Subsequent instances will be > 0 and just the duplicate number. */
+ if (pass->name)
+ {
+ pass->static_pass_number -= 1;
+ new->static_pass_number = -pass->static_pass_number;
+ }
+
+ *list = new;
+ }
+ else
+ {
+ pass->todo_flags_start |= TODO_mark_first_instance;
+ pass->static_pass_number = -1;
+ *list = pass;
+ }
+
+ return &(*list)->next;
+
+}
- timevar_pop (TV_LOCAL_ALLOC);
- close_dump_file (DFI_lreg, NULL, NULL);
- /* XXX clean up the whole mess to bring live info in shape again. */
- timevar_push (TV_GLOBAL_ALLOC);
- open_dump_file (DFI_greg, current_function_decl);
+/* Construct the pass tree. The sequencing of passes is driven by
+ the cgraph routines:
- build_insn_chain (get_insns ());
- failure = reload (get_insns (), 0);
+ cgraph_finalize_compilation_unit ()
+ for each node N in the cgraph
+ cgraph_analyze_function (N)
+ cgraph_lower_function (N) -> all_lowering_passes
- timevar_pop (TV_GLOBAL_ALLOC);
+ If we are optimizing, cgraph_optimize is then invoked:
- ggc_collect ();
+ cgraph_optimize ()
+ ipa_passes () -> all_ipa_passes
+ cgraph_expand_all_functions ()
+ for each node N in the cgraph
+ cgraph_expand_function (N)
+ tree_rest_of_compilation (DECL (N)) -> all_passes
+*/
- if (dump_file_tbl[DFI_greg].enabled)
+void
+init_optimization_passes (void)
+{
+ struct opt_pass **p;
+
+#define NEXT_PASS(PASS) (p = next_pass_1 (p, &((PASS).pass)))
+
+ /* All passes needed to lower the function into shape optimizers can
+ operate on. These passes are always run first on the function, but
+ backend might produce already lowered functions that are not processed
+ by these passes. */
+ p = &all_lowering_passes;
+ NEXT_PASS (pass_remove_useless_stmts);
+ NEXT_PASS (pass_mudflap_1);
+ NEXT_PASS (pass_lower_omp);
+ NEXT_PASS (pass_lower_cf);
+ NEXT_PASS (pass_refactor_eh);
+ NEXT_PASS (pass_lower_eh);
+ NEXT_PASS (pass_build_cfg);
+ NEXT_PASS (pass_lower_complex_O0);
+ NEXT_PASS (pass_lower_vector);
+ NEXT_PASS (pass_warn_function_return);
+ NEXT_PASS (pass_build_cgraph_edges);
+ NEXT_PASS (pass_inline_parameters);
+ *p = NULL;
+
+ /* Interprocedural optimization passes. */
+ p = &all_ipa_passes;
+ NEXT_PASS (pass_ipa_function_and_variable_visibility);
+ NEXT_PASS (pass_ipa_early_inline);
{
- timevar_push (TV_DUMP);
- dump_global_regs (dump_file);
- timevar_pop (TV_DUMP);
- close_dump_file (DFI_greg, print_rtl_with_bb, get_insns ());
+ struct opt_pass **p = &pass_ipa_early_inline.pass.sub;
+ NEXT_PASS (pass_early_inline);
+ NEXT_PASS (pass_inline_parameters);
+ NEXT_PASS (pass_rebuild_cgraph_edges);
}
+ NEXT_PASS (pass_early_local_passes);
+ {
+ struct opt_pass **p = &pass_early_local_passes.pass.sub;
+ NEXT_PASS (pass_tree_profile);
+ NEXT_PASS (pass_cleanup_cfg);
+ NEXT_PASS (pass_init_datastructures);
+ NEXT_PASS (pass_expand_omp);
+
+ NEXT_PASS (pass_referenced_vars);
+ NEXT_PASS (pass_reset_cc_flags);
+ NEXT_PASS (pass_build_ssa);
+ NEXT_PASS (pass_all_early_optimizations);
+ {
+ struct opt_pass **p = &pass_all_early_optimizations.pass.sub;
+ NEXT_PASS (pass_early_warn_uninitialized);
+ NEXT_PASS (pass_rebuild_cgraph_edges);
+ NEXT_PASS (pass_early_inline);
+ NEXT_PASS (pass_cleanup_cfg);
+ NEXT_PASS (pass_rename_ssa_copies);
+ NEXT_PASS (pass_ccp);
+ NEXT_PASS (pass_forwprop);
+ NEXT_PASS (pass_update_address_taken);
+ NEXT_PASS (pass_simple_dse);
+ NEXT_PASS (pass_sra_early);
+ NEXT_PASS (pass_copy_prop);
+ NEXT_PASS (pass_merge_phi);
+ NEXT_PASS (pass_dce);
+ /* Ideally the function call conditional
+ dead code elimination phase can be delayed
+ till later where potentially more opportunities
+ can be found. Due to lack of good ways to
+ update VDEFs associated with the shrink-wrapped
+ calls, it is better to do the transformation
+ here where memory SSA is not built yet. */
+ NEXT_PASS (pass_call_cdce);
+ NEXT_PASS (pass_update_address_taken);
+ NEXT_PASS (pass_simple_dse);
+ NEXT_PASS (pass_tail_recursion);
+ NEXT_PASS (pass_convert_switch);
+ NEXT_PASS (pass_profile);
+ }
+ NEXT_PASS (pass_release_ssa_names);
+ NEXT_PASS (pass_rebuild_cgraph_edges);
+ }
+ NEXT_PASS (pass_ipa_increase_alignment);
+ NEXT_PASS (pass_ipa_matrix_reorg);
+ NEXT_PASS (pass_ipa_cp);
+ NEXT_PASS (pass_ipa_inline);
+ NEXT_PASS (pass_ipa_reference);
+ NEXT_PASS (pass_ipa_pure_const);
+ NEXT_PASS (pass_ipa_type_escape);
+ NEXT_PASS (pass_ipa_pta);
+ NEXT_PASS (pass_ipa_struct_reorg);
+ *p = NULL;
+
+ /* These passes are run after IPA passes on every function that is being
+ output to the assembler file. */
+ p = &all_passes;
+ NEXT_PASS (pass_all_optimizations);
+ {
+ struct opt_pass **p = &pass_all_optimizations.pass.sub;
+ /* pass_build_alias is a dummy pass that ensures that we
+ execute TODO_rebuild_alias at this point. */
+ NEXT_PASS (pass_build_alias);
+ NEXT_PASS (pass_return_slot);
+ NEXT_PASS (pass_rename_ssa_copies);
+
+ /* Initial scalar cleanups. */
+ NEXT_PASS (pass_complete_unrolli);
+ NEXT_PASS (pass_ccp);
+ NEXT_PASS (pass_phiprop);
+ NEXT_PASS (pass_fre);
+ NEXT_PASS (pass_dce);
+ NEXT_PASS (pass_forwprop);
+ NEXT_PASS (pass_copy_prop);
+ NEXT_PASS (pass_merge_phi);
+ NEXT_PASS (pass_vrp);
+ NEXT_PASS (pass_dce);
+ NEXT_PASS (pass_cselim);
+ NEXT_PASS (pass_dominator);
+ /* The only const/copy propagation opportunities left after
+ DOM should be due to degenerate PHI nodes. So rather than
+ run the full propagators, run a specialized pass which
+ only examines PHIs to discover const/copy propagation
+ opportunities. */
+ NEXT_PASS (pass_phi_only_cprop);
+ NEXT_PASS (pass_tree_ifcombine);
+ NEXT_PASS (pass_phiopt);
+ NEXT_PASS (pass_tail_recursion);
+ NEXT_PASS (pass_ch);
+ NEXT_PASS (pass_stdarg);
+ NEXT_PASS (pass_lower_complex);
+ NEXT_PASS (pass_sra);
+ NEXT_PASS (pass_rename_ssa_copies);
+ NEXT_PASS (pass_dominator);
+
+ /* The only const/copy propagation opportunities left after
+ DOM should be due to degenerate PHI nodes. So rather than
+ run the full propagators, run a specialized pass which
+ only examines PHIs to discover const/copy propagation
+ opportunities. */
+ NEXT_PASS (pass_phi_only_cprop);
+
+ NEXT_PASS (pass_reassoc);
+ NEXT_PASS (pass_dce);
+ NEXT_PASS (pass_dse);
+ NEXT_PASS (pass_forwprop);
+ NEXT_PASS (pass_phiopt);
+ NEXT_PASS (pass_object_sizes);
+ NEXT_PASS (pass_store_ccp);
+ NEXT_PASS (pass_copy_prop);
+ NEXT_PASS (pass_fold_builtins);
+ NEXT_PASS (pass_cse_sincos);
+ NEXT_PASS (pass_split_crit_edges);
+ NEXT_PASS (pass_pre);
+ NEXT_PASS (pass_sink_code);
+ NEXT_PASS (pass_tree_loop);
+ {
+ struct opt_pass **p = &pass_tree_loop.pass.sub;
+ NEXT_PASS (pass_tree_loop_init);
+ NEXT_PASS (pass_copy_prop);
+ NEXT_PASS (pass_dce_loop);
+ NEXT_PASS (pass_lim);
+ NEXT_PASS (pass_predcom);
+ NEXT_PASS (pass_tree_unswitch);
+ NEXT_PASS (pass_scev_cprop);
+ NEXT_PASS (pass_empty_loop);
+ NEXT_PASS (pass_record_bounds);
+ NEXT_PASS (pass_check_data_deps);
+ NEXT_PASS (pass_loop_distribution);
+ NEXT_PASS (pass_linear_transform);
+ NEXT_PASS (pass_iv_canon);
+ NEXT_PASS (pass_if_conversion);
+ NEXT_PASS (pass_vectorize);
+ {
+ struct opt_pass **p = &pass_vectorize.pass.sub;
+ NEXT_PASS (pass_lower_vector_ssa);
+ NEXT_PASS (pass_dce_loop);
+ }
+ NEXT_PASS (pass_complete_unroll);
+ NEXT_PASS (pass_parallelize_loops);
+ NEXT_PASS (pass_loop_prefetch);
+ NEXT_PASS (pass_iv_optimize);
+ NEXT_PASS (pass_tree_loop_done);
+ }
+ NEXT_PASS (pass_cse_reciprocals);
+ NEXT_PASS (pass_convert_to_rsqrt);
+ NEXT_PASS (pass_reassoc);
+ NEXT_PASS (pass_vrp);
+ NEXT_PASS (pass_dominator);
+
+ /* The only const/copy propagation opportunities left after
+ DOM should be due to degenerate PHI nodes. So rather than
+ run the full propagators, run a specialized pass which
+ only examines PHIs to discover const/copy propagation
+ opportunities. */
+ NEXT_PASS (pass_phi_only_cprop);
+
+ NEXT_PASS (pass_cd_dce);
+ NEXT_PASS (pass_tracer);
+
+ /* FIXME: If DCE is not run before checking for uninitialized uses,
+ we may get false warnings (e.g., testsuite/gcc.dg/uninit-5.c).
+ However, this also causes us to misdiagnose cases that should be
+ real warnings (e.g., testsuite/gcc.dg/pr18501.c).
+
+ To fix the false positives in uninit-5.c, we would have to
+ account for the predicates protecting the set and the use of each
+ variable. Using a representation like Gated Single Assignment
+ may help. */
+ NEXT_PASS (pass_late_warn_uninitialized);
+ NEXT_PASS (pass_dse);
+ NEXT_PASS (pass_forwprop);
+ NEXT_PASS (pass_phiopt);
+ NEXT_PASS (pass_tail_calls);
+ NEXT_PASS (pass_rename_ssa_copies);
+ NEXT_PASS (pass_uncprop);
+ }
+ NEXT_PASS (pass_del_ssa);
+ NEXT_PASS (pass_nrv);
+ NEXT_PASS (pass_mark_used_blocks);
+ NEXT_PASS (pass_cleanup_cfg_post_optimizing);
+
+ NEXT_PASS (pass_warn_function_noreturn);
+ NEXT_PASS (pass_free_datastructures);
+ NEXT_PASS (pass_mudflap_2);
+ NEXT_PASS (pass_free_cfg_annotations);
+ NEXT_PASS (pass_expand);
+ NEXT_PASS (pass_rest_of_compilation);
+ {
+ struct opt_pass **p = &pass_rest_of_compilation.pass.sub;
+ NEXT_PASS (pass_init_function);
+ NEXT_PASS (pass_jump);
+ NEXT_PASS (pass_rtl_eh);
+ NEXT_PASS (pass_initial_value_sets);
+ NEXT_PASS (pass_unshare_all_rtl);
+ NEXT_PASS (pass_instantiate_virtual_regs);
+ NEXT_PASS (pass_into_cfg_layout_mode);
+ NEXT_PASS (pass_jump2);
+ NEXT_PASS (pass_lower_subreg);
+ NEXT_PASS (pass_df_initialize_opt);
+ NEXT_PASS (pass_cse);
+ NEXT_PASS (pass_rtl_fwprop);
+ NEXT_PASS (pass_gcse);
+ NEXT_PASS (pass_rtl_ifcvt);
+ /* Perform loop optimizations. It might be better to do them a bit
+ sooner, but we want the profile feedback to work more
+ efficiently. */
+ NEXT_PASS (pass_loop2);
+ {
+ struct opt_pass **p = &pass_loop2.pass.sub;
+ NEXT_PASS (pass_rtl_loop_init);
+ NEXT_PASS (pass_rtl_move_loop_invariants);
+ NEXT_PASS (pass_rtl_unswitch);
+ NEXT_PASS (pass_rtl_unroll_and_peel_loops);
+ NEXT_PASS (pass_rtl_doloop);
+ NEXT_PASS (pass_rtl_loop_done);
+ *p = NULL;
+ }
+ NEXT_PASS (pass_web);
+ NEXT_PASS (pass_jump_bypass);
+ NEXT_PASS (pass_cse2);
+ NEXT_PASS (pass_rtl_dse1);
+ NEXT_PASS (pass_rtl_fwprop_addr);
+ NEXT_PASS (pass_regclass_init);
+ NEXT_PASS (pass_inc_dec);
+ NEXT_PASS (pass_initialize_regs);
+ NEXT_PASS (pass_outof_cfg_layout_mode);
+ NEXT_PASS (pass_ud_rtl_dce);
+ NEXT_PASS (pass_combine);
+ NEXT_PASS (pass_if_after_combine);
+ NEXT_PASS (pass_partition_blocks);
+ NEXT_PASS (pass_regmove);
+ NEXT_PASS (pass_split_all_insns);
+ NEXT_PASS (pass_lower_subreg2);
+ NEXT_PASS (pass_df_initialize_no_opt);
+ NEXT_PASS (pass_stack_ptr_mod);
+ NEXT_PASS (pass_mode_switching);
+ NEXT_PASS (pass_see);
+ NEXT_PASS (pass_match_asm_constraints);
+ NEXT_PASS (pass_sms);
+ NEXT_PASS (pass_sched);
+ NEXT_PASS (pass_subregs_of_mode_init);
+ NEXT_PASS (pass_local_alloc);
+ NEXT_PASS (pass_global_alloc);
+ NEXT_PASS (pass_subregs_of_mode_finish);
+ NEXT_PASS (pass_postreload);
+ {
+ struct opt_pass **p = &pass_postreload.pass.sub;
+ NEXT_PASS (pass_postreload_cse);
+ NEXT_PASS (pass_gcse2);
+ NEXT_PASS (pass_split_after_reload);
+ NEXT_PASS (pass_branch_target_load_optimize1);
+ NEXT_PASS (pass_thread_prologue_and_epilogue);
+ NEXT_PASS (pass_rtl_dse2);
+ NEXT_PASS (pass_rtl_seqabstr);
+ NEXT_PASS (pass_stack_adjustments);
+ NEXT_PASS (pass_peephole2);
+ NEXT_PASS (pass_if_after_reload);
+ NEXT_PASS (pass_regrename);
+ NEXT_PASS (pass_cprop_hardreg);
+ NEXT_PASS (pass_fast_rtl_dce);
+ NEXT_PASS (pass_reorder_blocks);
+ NEXT_PASS (pass_branch_target_load_optimize2);
+ NEXT_PASS (pass_leaf_regs);
+ NEXT_PASS (pass_split_before_sched2);
+ NEXT_PASS (pass_sched2);
+ NEXT_PASS (pass_stack_regs);
+ {
+ struct opt_pass **p = &pass_stack_regs.pass.sub;
+ NEXT_PASS (pass_split_before_regstack);
+ NEXT_PASS (pass_stack_regs_run);
+ }
+ NEXT_PASS (pass_compute_alignments);
+ NEXT_PASS (pass_duplicate_computed_gotos);
+ NEXT_PASS (pass_variable_tracking);
+ NEXT_PASS (pass_free_cfg);
+ NEXT_PASS (pass_machine_reorg);
+ NEXT_PASS (pass_cleanup_barriers);
+ NEXT_PASS (pass_delay_slots);
+ NEXT_PASS (pass_split_for_shorten_branches);
+ NEXT_PASS (pass_convert_to_eh_region_ranges);
+ NEXT_PASS (pass_shorten_branches);
+ NEXT_PASS (pass_set_nothrow_function_flags);
+ NEXT_PASS (pass_final);
+ }
+ NEXT_PASS (pass_df_finish);
+ }
+ NEXT_PASS (pass_clean_state);
+ *p = NULL;
+
+#undef NEXT_PASS
+
+ /* Register the passes with the tree dump code. */
+ register_dump_files (all_lowering_passes, PROP_gimple_any);
+ all_lowering_passes->todo_flags_start |= TODO_set_props;
+ register_dump_files (all_ipa_passes,
+ PROP_gimple_any | PROP_gimple_lcf | PROP_gimple_leh
+ | PROP_cfg);
+ register_dump_files (all_passes,
+ PROP_gimple_any | PROP_gimple_lcf | PROP_gimple_leh
+ | PROP_cfg);
+}
- if (failure)
- return true;
-
- reload_completed = 1;
+/* If we are in IPA mode (i.e., current_function_decl is NULL), call
+ function CALLBACK for every function in the call graph. Otherwise,
+ call CALLBACK on the current function. */
- return false;
+static void
+do_per_function (void (*callback) (void *data), void *data)
+{
+ if (current_function_decl)
+ callback (data);
+ else
+ {
+ struct cgraph_node *node;
+ for (node = cgraph_nodes; node; node = node->next)
+ if (node->analyzed)
+ {
+ push_cfun (DECL_STRUCT_FUNCTION (node->decl));
+ current_function_decl = node->decl;
+ callback (data);
+ free_dominance_info (CDI_DOMINATORS);
+ free_dominance_info (CDI_POST_DOMINATORS);
+ current_function_decl = NULL;
+ pop_cfun ();
+ ggc_collect ();
+ }
+ }
}
-/* Run old register allocator. Return TRUE if we must exit
- rest_of_compilation upon return. */
-static bool
-rest_of_handle_old_regalloc (void)
-{
- int failure;
- int rebuild_notes;
+/* Because inlining might remove no-longer reachable nodes, we need to
+ keep the array visible to garbage collector to avoid reading collected
+ out nodes. */
+static int nnodes;
+static GTY ((length ("nnodes"))) struct cgraph_node **order;
+
+/* If we are in IPA mode (i.e., current_function_decl is NULL), call
+ function CALLBACK for every function in the call graph. Otherwise,
+ call CALLBACK on the current function. */
- timevar_push (TV_LOCAL_ALLOC);
- open_dump_file (DFI_lreg, current_function_decl);
+static void
+do_per_function_toporder (void (*callback) (void *data), void *data)
+{
+ int i;
- /* Allocate the reg_renumber array. */
- allocate_reg_info (max_regno, FALSE, TRUE);
+ if (current_function_decl)
+ callback (data);
+ else
+ {
+ gcc_assert (!order);
+ order = GGC_NEWVEC (struct cgraph_node *, cgraph_n_nodes);
+ nnodes = cgraph_postorder (order);
+ for (i = nnodes - 1; i >= 0; i--)
+ {
+ struct cgraph_node *node = order[i];
+
+ /* Allow possibly removed nodes to be garbage collected. */
+ order[i] = NULL;
+ if (node->analyzed && (node->needed || node->reachable))
+ {
+ push_cfun (DECL_STRUCT_FUNCTION (node->decl));
+ current_function_decl = node->decl;
+ callback (data);
+ free_dominance_info (CDI_DOMINATORS);
+ free_dominance_info (CDI_POST_DOMINATORS);
+ current_function_decl = NULL;
+ pop_cfun ();
+ ggc_collect ();
+ }
+ }
+ }
+ ggc_free (order);
+ order = NULL;
+ nnodes = 0;
+}
- /* And the reg_equiv_memory_loc array. */
- VARRAY_GROW (reg_equiv_memory_loc_varray, max_regno);
- reg_equiv_memory_loc = &VARRAY_RTX (reg_equiv_memory_loc_varray, 0);
+/* Perform all TODO actions that ought to be done on each function. */
- allocate_initial_values (reg_equiv_memory_loc);
+static void
+execute_function_todo (void *data)
+{
+ unsigned int flags = (size_t)data;
+ if (cfun->curr_properties & PROP_ssa)
+ flags |= TODO_verify_ssa;
+ flags &= ~cfun->last_verified;
+ if (!flags)
+ return;
- regclass (get_insns (), max_reg_num (), dump_file);
- rebuild_notes = local_alloc ();
+ statistics_fini_pass ();
- timevar_pop (TV_LOCAL_ALLOC);
+ /* Always cleanup the CFG before trying to update SSA. */
+ if (flags & TODO_cleanup_cfg)
+ {
+ bool cleanup = cleanup_tree_cfg ();
+
+ if (cleanup && (cfun->curr_properties & PROP_ssa))
+ flags |= TODO_remove_unused_locals;
+
+ /* When cleanup_tree_cfg merges consecutive blocks, it may
+ perform some simplistic propagation when removing single
+ valued PHI nodes. This propagation may, in turn, cause the
+ SSA form to become out-of-date (see PR 22037). So, even
+ if the parent pass had not scheduled an SSA update, we may
+ still need to do one. */
+ if (!(flags & TODO_update_ssa_any) && need_ssa_update_p ())
+ flags |= TODO_update_ssa;
+ }
- /* Local allocation may have turned an indirect jump into a direct
- jump. If so, we must rebuild the JUMP_LABEL fields of jumping
- instructions. */
- if (rebuild_notes)
+ if (flags & TODO_update_ssa_any)
+ {
+ unsigned update_flags = flags & TODO_update_ssa_any;
+ update_ssa (update_flags);
+ cfun->last_verified &= ~TODO_verify_ssa;
+ }
+
+ if (flags & TODO_rebuild_alias)
{
- timevar_push (TV_JUMP);
+ compute_may_aliases ();
+ cfun->curr_properties |= PROP_alias;
+ }
+
+ if (flags & TODO_remove_unused_locals)
+ remove_unused_locals ();
- rebuild_jump_labels (get_insns ());
- purge_all_dead_edges (0);
+ if ((flags & TODO_dump_func)
+ && dump_file && current_function_decl)
+ {
+ if (cfun->curr_properties & PROP_trees)
+ dump_function_to_file (current_function_decl,
+ dump_file, dump_flags);
+ else
+ {
+ if (dump_flags & TDF_SLIM)
+ print_rtl_slim_with_bb (dump_file, get_insns (), dump_flags);
+ else if ((cfun->curr_properties & PROP_cfg)
+ && (dump_flags & TDF_BLOCKS))
+ print_rtl_with_bb (dump_file, get_insns ());
+ else
+ print_rtl (dump_file, get_insns ());
+
+ if (cfun->curr_properties & PROP_cfg
+ && graph_dump_format != no_graph
+ && (dump_flags & TDF_GRAPH))
+ print_rtl_graph_with_bb (dump_file_name, get_insns ());
+ }
- timevar_pop (TV_JUMP);
+ /* Flush the file. If verification fails, we won't be able to
+ close the file before aborting. */
+ fflush (dump_file);
}
- if (dump_file_tbl[DFI_lreg].enabled)
+ if (flags & TODO_rebuild_frequencies)
{
- timevar_push (TV_DUMP);
- dump_flow_info (dump_file);
- dump_local_alloc (dump_file);
- timevar_pop (TV_DUMP);
+ if (profile_status == PROFILE_GUESSED)
+ {
+ loop_optimizer_init (0);
+ add_noreturn_fake_exit_edges ();
+ mark_irreducible_loops ();
+ connect_infinite_loops_to_exit ();
+ estimate_bb_frequencies ();
+ remove_fake_exit_edges ();
+ loop_optimizer_finalize ();
+ }
+ else if (profile_status == PROFILE_READ)
+ counts_to_freqs ();
+ else
+ gcc_unreachable ();
}
- close_dump_file (DFI_lreg, print_rtl_with_bb, get_insns ());
+#if defined ENABLE_CHECKING
+ if (flags & TODO_verify_ssa)
+ verify_ssa (true);
+ if (flags & TODO_verify_flow)
+ verify_flow_info ();
+ if (flags & TODO_verify_stmts)
+ verify_stmts ();
+ if (flags & TODO_verify_loops)
+ verify_loop_closed_ssa ();
+ if (flags & TODO_verify_rtl_sharing)
+ verify_rtl_sharing ();
+#endif
+
+ cfun->last_verified = flags & TODO_verify_all;
+}
- ggc_collect ();
+/* Perform all TODO actions. */
+static void
+execute_todo (unsigned int flags)
+{
+#if defined ENABLE_CHECKING
+ if (need_ssa_update_p ())
+ gcc_assert (flags & TODO_update_ssa_any);
+#endif
- timevar_push (TV_GLOBAL_ALLOC);
- open_dump_file (DFI_greg, current_function_decl);
+ /* Inform the pass whether it is the first time it is run. */
+ first_pass_instance = (flags & TODO_mark_first_instance) != 0;
- /* If optimizing, allocate remaining pseudo-regs. Do the reload
- pass fixing up any insns that are invalid. */
+ do_per_function (execute_function_todo, (void *)(size_t) flags);
- if (optimize)
- failure = global_alloc (dump_file);
- else
+ /* Always remove functions just as before inlining: IPA passes might be
+ interested to see bodies of extern inline functions that are not inlined
+ to analyze side effects. The full removal is done just at the end
+ of IPA pass queue. */
+ if (flags & TODO_remove_functions)
{
- build_insn_chain (get_insns ());
- failure = reload (get_insns (), 0);
+ gcc_assert (!cfun);
+ cgraph_remove_unreachable_nodes (true, dump_file);
}
- if (dump_file_tbl[DFI_greg].enabled)
+ if ((flags & TODO_dump_cgraph)
+ && dump_file && !current_function_decl)
{
- timevar_push (TV_DUMP);
- dump_global_regs (dump_file);
- timevar_pop (TV_DUMP);
-
- close_dump_file (DFI_greg, print_rtl_with_bb, get_insns ());
+ gcc_assert (!cfun);
+ dump_cgraph (dump_file);
+ /* Flush the file. If verification fails, we won't be able to
+ close the file before aborting. */
+ fflush (dump_file);
}
- ggc_collect ();
-
- timevar_pop (TV_GLOBAL_ALLOC);
+ if (flags & TODO_ggc_collect)
+ {
+ ggc_collect ();
+ }
- return failure;
+ /* Now that the dumping has been done, we can get rid of the optional
+ df problems. */
+ if (flags & TODO_df_finish)
+ df_finish_pass ((flags & TODO_df_verify) != 0);
}
-/* Run the regrename and cprop passes. */
+/* Verify invariants that should hold between passes. This is a place
+ to put simple sanity checks. */
+
static void
-rest_of_handle_regrename (void)
+verify_interpass_invariants (void)
{
- timevar_push (TV_RENAME_REGISTERS);
- open_dump_file (DFI_rnreg, current_function_decl);
-
- if (flag_rename_registers)
- regrename_optimize ();
- if (flag_cprop_registers)
- copyprop_hardreg_forward ();
-
- close_dump_file (DFI_rnreg, print_rtl_with_bb, get_insns ());
- timevar_pop (TV_RENAME_REGISTERS);
+#ifdef ENABLE_CHECKING
+ gcc_assert (!fold_deferring_overflow_warnings_p ());
+#endif
}
-/* Reorder basic blocks. */
+/* Clear the last verified flag. */
+
static void
-rest_of_handle_reorder_blocks (void)
+clear_last_verified (void *data ATTRIBUTE_UNUSED)
{
- bool changed;
- open_dump_file (DFI_bbro, current_function_decl);
-
- /* Last attempt to optimize CFG, as scheduling, peepholing and insn
- splitting possibly introduced more crossjumping opportunities. */
- changed = cleanup_cfg (CLEANUP_EXPENSIVE
- | (!HAVE_conditional_execution
- ? CLEANUP_UPDATE_LIFE : 0));
-
- if (flag_sched2_use_traces && flag_schedule_insns_after_reload)
- tracer ();
- if (flag_reorder_blocks || flag_reorder_blocks_and_partition)
- reorder_basic_blocks ();
- if (flag_reorder_blocks || flag_reorder_blocks_and_partition
- || (flag_sched2_use_traces && flag_schedule_insns_after_reload))
- changed |= cleanup_cfg (CLEANUP_EXPENSIVE
- | (!HAVE_conditional_execution
- ? CLEANUP_UPDATE_LIFE : 0));
-
- /* On conditional execution targets we can not update the life cheaply, so
- we deffer the updating to after both cleanups. This may lose some cases
- but should not be terribly bad. */
- if (changed && HAVE_conditional_execution)
- update_life_info (NULL, UPDATE_LIFE_GLOBAL_RM_NOTES,
- PROP_DEATH_NOTES);
- close_dump_file (DFI_bbro, print_rtl_with_bb, get_insns ());
+ cfun->last_verified = 0;
}
-/* Partition hot and cold basic blocks. */
+/* Helper function. Verify that the properties has been turn into the
+ properties expected by the pass. */
+
+#ifdef ENABLE_CHECKING
static void
-rest_of_handle_partition_blocks (void)
+verify_curr_properties (void *data)
{
- no_new_pseudos = 0;
- partition_hot_cold_basic_blocks ();
- allocate_reg_life_data ();
- update_life_info (NULL, UPDATE_LIFE_GLOBAL_RM_NOTES,
- PROP_LOG_LINKS | PROP_REG_INFO | PROP_DEATH_NOTES);
- no_new_pseudos = 1;
+ unsigned int props = (size_t)data;
+ gcc_assert ((cfun->curr_properties & props) == props);
}
+#endif
-#ifdef INSN_SCHEDULING
-/* Run instruction scheduler. */
-/* Perform SMS module scheduling. */
-static void
-rest_of_handle_sms (void)
+/* Initialize pass dump file. */
+
+static bool
+pass_init_dump_file (struct opt_pass *pass)
{
- timevar_push (TV_SMS);
- open_dump_file (DFI_sms, current_function_decl);
-
- /* We want to be able to create new pseudos. */
- no_new_pseudos = 0;
- sms_schedule (dump_file);
- close_dump_file (DFI_sms, print_rtl, get_insns ());
-
-
- /* Update the life information, because we add pseudos. */
- max_regno = max_reg_num ();
- allocate_reg_info (max_regno, FALSE, FALSE);
- update_life_info_in_dirty_blocks (UPDATE_LIFE_GLOBAL_RM_NOTES,
- (PROP_DEATH_NOTES
- | PROP_KILL_DEAD_CODE
- | PROP_SCAN_DEAD_CODE));
- no_new_pseudos = 1;
-
- ggc_collect ();
- timevar_pop (TV_SMS);
+ /* If a dump file name is present, open it if enabled. */
+ if (pass->static_pass_number != -1)
+ {
+ bool initializing_dump = !dump_initialized_p (pass->static_pass_number);
+ dump_file_name = get_dump_file_name (pass->static_pass_number);
+ dump_file = dump_begin (pass->static_pass_number, &dump_flags);
+ if (dump_file && current_function_decl)
+ {
+ const char *dname, *aname;
+ dname = lang_hooks.decl_printable_name (current_function_decl, 2);
+ aname = (IDENTIFIER_POINTER
+ (DECL_ASSEMBLER_NAME (current_function_decl)));
+ fprintf (dump_file, "\n;; Function %s (%s)%s\n\n", dname, aname,
+ cfun->function_frequency == FUNCTION_FREQUENCY_HOT
+ ? " (hot)"
+ : cfun->function_frequency == FUNCTION_FREQUENCY_UNLIKELY_EXECUTED
+ ? " (unlikely executed)"
+ : "");
+ }
+ return initializing_dump;
+ }
+ else
+ return false;
}
-/* Run instruction scheduler. */
+/* Flush PASS dump file. */
+
static void
-rest_of_handle_sched (void)
+pass_fini_dump_file (struct opt_pass *pass)
{
- timevar_push (TV_SCHED);
+ /* Flush and close dump file. */
+ if (dump_file_name)
+ {
+ free (CONST_CAST (char *, dump_file_name));
+ dump_file_name = NULL;
+ }
- /* Print function header into sched dump now
- because doing the sched analysis makes some of the dump. */
- open_dump_file (DFI_sched, current_function_decl);
+ if (dump_file)
+ {
+ dump_end (pass->static_pass_number, dump_file);
+ dump_file = NULL;
+ }
+}
- /* Do control and data sched analysis,
- and write some of the results to dump file. */
+/* After executing the pass, apply expected changes to the function
+ properties. */
- schedule_insns (dump_file);
+static void
+update_properties_after_pass (void *data)
+{
+ struct opt_pass *pass = (struct opt_pass *) data;
+ cfun->curr_properties = (cfun->curr_properties | pass->properties_provided)
+ & ~pass->properties_destroyed;
+}
- close_dump_file (DFI_sched, print_rtl_with_bb, get_insns ());
+/* Schedule IPA transform pass DATA for CFUN. */
- ggc_collect ();
- timevar_pop (TV_SCHED);
+static void
+add_ipa_transform_pass (void *data)
+{
+ struct ipa_opt_pass *ipa_pass = (struct ipa_opt_pass *) data;
+ VEC_safe_push (ipa_opt_pass, heap, cfun->ipa_transforms_to_apply, ipa_pass);
}
-/* Run second scheduling pass after reload. */
+/* Execute summary generation for all of the passes in IPA_PASS. */
+
static void
-rest_of_handle_sched2 (void)
+execute_ipa_summary_passes (struct ipa_opt_pass *ipa_pass)
{
- timevar_push (TV_SCHED2);
- open_dump_file (DFI_sched2, current_function_decl);
+ while (ipa_pass)
+ {
+ struct opt_pass *pass = &ipa_pass->pass;
- /* Do control and data sched analysis again,
- and write some more of the results to dump file. */
+ /* Execute all of the IPA_PASSes in the list. */
+ if (ipa_pass->pass.type == IPA_PASS
+ && (!pass->gate || pass->gate ()))
+ {
+ pass_init_dump_file (pass);
+ ipa_pass->generate_summary ();
+ pass_fini_dump_file (pass);
+ }
+ ipa_pass = (struct ipa_opt_pass *)ipa_pass->pass.next;
+ }
+}
- split_all_insns (1);
+/* Execute IPA_PASS function transform on NODE. */
- if (flag_sched2_use_superblocks || flag_sched2_use_traces)
- {
- schedule_ebbs (dump_file);
- /* No liveness updating code yet, but it should be easy to do.
- reg-stack recomputes the liveness when needed for now. */
- count_or_remove_death_notes (NULL, 1);
- cleanup_cfg (CLEANUP_EXPENSIVE);
- }
- else
- schedule_insns (dump_file);
-
- close_dump_file (DFI_sched2, print_rtl_with_bb, get_insns ());
-
- ggc_collect ();
-
- timevar_pop (TV_SCHED2);
-}
-#endif
-
-static void
-rest_of_handle_gcse2 (void)
-{
- timevar_push (TV_RELOAD_CSE_REGS);
- open_dump_file (DFI_gcse2, current_function_decl);
-
- gcse_after_reload_main (get_insns (), dump_file);
- rebuild_jump_labels (get_insns ());
- delete_trivially_dead_insns (get_insns (), max_reg_num ());
- close_dump_file (DFI_gcse2, print_rtl_with_bb, get_insns ());
-
- ggc_collect ();
-
-#ifdef ENABLE_CHECKING
- verify_flow_info ();
-#endif
-
- timevar_pop (TV_RELOAD_CSE_REGS);
-}
-
-/* Register allocation pre-pass, to reduce number of moves necessary
- for two-address machines. */
-static void
-rest_of_handle_regmove (void)
-{
- timevar_push (TV_REGMOVE);
- open_dump_file (DFI_regmove, current_function_decl);
-
- regmove_optimize (get_insns (), max_reg_num (), dump_file);
-
- cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_UPDATE_LIFE);
- close_dump_file (DFI_regmove, print_rtl_with_bb, get_insns ());
-
- ggc_collect ();
- timevar_pop (TV_REGMOVE);
-}
-
-/* Run tracer. */
-static void
-rest_of_handle_tracer (void)
-{
- open_dump_file (DFI_tracer, current_function_decl);
- if (dump_file)
- dump_flow_info (dump_file);
- tracer ();
- cleanup_cfg (CLEANUP_EXPENSIVE);
- reg_scan (get_insns (), max_reg_num (), 0);
- close_dump_file (DFI_tracer, print_rtl_with_bb, get_insns ());
-}
-
-/* If-conversion and CFG cleanup. */
-static void
-rest_of_handle_if_conversion (void)
-{
- timevar_push (TV_IFCVT);
- open_dump_file (DFI_ce1, current_function_decl);
-
- if (flag_if_conversion)
- {
- if (dump_file)
- dump_flow_info (dump_file);
- cleanup_cfg (CLEANUP_EXPENSIVE);
- reg_scan (get_insns (), max_reg_num (), 0);
- if_convert (0);
- }
-
- timevar_push (TV_JUMP);
- cleanup_cfg (CLEANUP_EXPENSIVE);
- reg_scan (get_insns (), max_reg_num (), 0);
- timevar_pop (TV_JUMP);
-
- close_dump_file (DFI_ce1, print_rtl_with_bb, get_insns ());
- timevar_pop (TV_IFCVT);
-}
-
-/* Rerun if-conversion, as combine may have simplified things enough
- to now meet sequence length restrictions. */
-static void
-rest_of_handle_if_after_combine (void)
-{
- timevar_push (TV_IFCVT);
- open_dump_file (DFI_ce2, current_function_decl);
-
- no_new_pseudos = 0;
- if_convert (1);
- no_new_pseudos = 1;
-
- close_dump_file (DFI_ce2, print_rtl_with_bb, get_insns ());
- timevar_pop (TV_IFCVT);
-}
-
-static void
-rest_of_handle_if_after_reload (void)
-{
- timevar_push (TV_IFCVT2);
- open_dump_file (DFI_ce3, current_function_decl);
-
- /* Last attempt to optimize CFG, as scheduling, peepholing and insn
- splitting possibly introduced more crossjumping opportunities. */
- cleanup_cfg (CLEANUP_EXPENSIVE
- | CLEANUP_UPDATE_LIFE
- | (flag_crossjumping ? CLEANUP_CROSSJUMP : 0));
- if (flag_if_conversion2)
- if_convert (1);
- close_dump_file (DFI_ce3, print_rtl_with_bb, get_insns ());
- timevar_pop (TV_IFCVT2);
-}
-
-static void
-rest_of_handle_web (void)
-{
- open_dump_file (DFI_web, current_function_decl);
- timevar_push (TV_WEB);
- web_main ();
- delete_trivially_dead_insns (get_insns (), max_reg_num ());
- cleanup_cfg (CLEANUP_EXPENSIVE);
-
- timevar_pop (TV_WEB);
- close_dump_file (DFI_web, print_rtl_with_bb, get_insns ());
- reg_scan (get_insns (), max_reg_num (), 0);
-}
-
-/* Do branch profiling and static profile estimation passes. */
-static void
-rest_of_handle_branch_prob (void)
-{
- struct loops loops;
-
- timevar_push (TV_BRANCH_PROB);
- open_dump_file (DFI_bp, current_function_decl);
-
- if (profile_arc_flag || flag_test_coverage || flag_branch_probabilities)
- branch_prob ();
-
- /* Discover and record the loop depth at the head of each basic
- block. The loop infrastructure does the real job for us. */
- flow_loops_find (&loops, LOOP_TREE);
-
- if (dump_file)
- flow_loops_dump (&loops, dump_file, NULL, 0);
-
- /* Estimate using heuristics if no profiling info is available. */
- if (flag_guess_branch_prob)
- estimate_probability (&loops);
-
- flow_loops_free (&loops);
- free_dominance_info (CDI_DOMINATORS);
- close_dump_file (DFI_bp, print_rtl_with_bb, get_insns ());
- timevar_pop (TV_BRANCH_PROB);
-}
-
-/* Do optimizations based on expression value profiles. */
-static void
-rest_of_handle_value_profile_transformations (void)
-{
- open_dump_file (DFI_vpt, current_function_decl);
- timevar_push (TV_VPT);
-
- if (value_profile_transformations ())
- cleanup_cfg (CLEANUP_EXPENSIVE);
-
- timevar_pop (TV_VPT);
- close_dump_file (DFI_vpt, print_rtl_with_bb, get_insns ());
-}
-
-/* Do control and data flow analysis; write some of the results to the
- dump file. */
-static void
-rest_of_handle_cfg (void)
-{
- open_dump_file (DFI_cfg, current_function_decl);
- if (dump_file)
- dump_flow_info (dump_file);
- if (optimize)
- cleanup_cfg (CLEANUP_EXPENSIVE
- | (flag_thread_jumps ? CLEANUP_THREADING : 0));
-
- /* It may make more sense to mark constant functions after dead code is
- eliminated by life_analysis, but we need to do it early, as -fprofile-arcs
- may insert code making function non-constant, but we still must consider
- it as constant, otherwise -fbranch-probabilities will not read data back.
-
- life_analysis rarely eliminates modification of external memory.
- */
- if (optimize)
- {
- /* Alias analysis depends on this information and mark_constant_function
- depends on alias analysis. */
- reg_scan (get_insns (), max_reg_num (), 1);
- mark_constant_function ();
- }
-
- close_dump_file (DFI_cfg, print_rtl_with_bb, get_insns ());
-}
-
-/* Perform jump bypassing and control flow optimizations. */
static void
-rest_of_handle_jump_bypass (void)
+execute_one_ipa_transform_pass (struct cgraph_node *node,
+ struct ipa_opt_pass *ipa_pass)
{
- timevar_push (TV_BYPASS);
- open_dump_file (DFI_bypass, current_function_decl);
+ struct opt_pass *pass = &ipa_pass->pass;
+ unsigned int todo_after = 0;
- cleanup_cfg (CLEANUP_EXPENSIVE);
- reg_scan (get_insns (), max_reg_num (), 1);
-
- if (bypass_jumps (dump_file))
- {
- rebuild_jump_labels (get_insns ());
- cleanup_cfg (CLEANUP_EXPENSIVE);
- delete_trivially_dead_insns (get_insns (), max_reg_num ());
- }
-
- close_dump_file (DFI_bypass, print_rtl_with_bb, get_insns ());
- timevar_pop (TV_BYPASS);
-
- ggc_collect ();
-
-#ifdef ENABLE_CHECKING
- verify_flow_info ();
-#endif
-}
-
-/* Try combining insns through substitution. */
-static void
-rest_of_handle_combine (void)
-{
- int rebuild_jump_labels_after_combine = 0;
-
- timevar_push (TV_COMBINE);
- open_dump_file (DFI_combine, current_function_decl);
-
- rebuild_jump_labels_after_combine
- = combine_instructions (get_insns (), max_reg_num ());
-
- /* Combining insns may have turned an indirect jump into a
- direct jump. Rebuild the JUMP_LABEL fields of jumping
- instructions. */
- if (rebuild_jump_labels_after_combine)
- {
- timevar_push (TV_JUMP);
- rebuild_jump_labels (get_insns ());
- timevar_pop (TV_JUMP);
-
- cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_UPDATE_LIFE);
- }
-
- close_dump_file (DFI_combine, print_rtl_with_bb, get_insns ());
- timevar_pop (TV_COMBINE);
-
- ggc_collect ();
-}
-
-/* Perform life analysis. */
-static void
-rest_of_handle_life (void)
-{
- open_dump_file (DFI_life, current_function_decl);
- regclass_init ();
-
-#ifdef ENABLE_CHECKING
- verify_flow_info ();
-#endif
- life_analysis (dump_file, PROP_FINAL);
- if (optimize)
- cleanup_cfg ((optimize ? CLEANUP_EXPENSIVE : 0) | CLEANUP_UPDATE_LIFE
- | CLEANUP_LOG_LINKS
- | (flag_thread_jumps ? CLEANUP_THREADING : 0));
-
- if (extra_warnings)
- {
- setjmp_vars_warning (DECL_INITIAL (current_function_decl));
- setjmp_args_warning ();
- }
-
- if (optimize)
- {
- if (!flag_new_regalloc && initialize_uninitialized_subregs ())
- {
- /* Insns were inserted, and possibly pseudos created, so
- things might look a bit different. */
- allocate_reg_life_data ();
- update_life_info (NULL, UPDATE_LIFE_GLOBAL_RM_NOTES,
- PROP_LOG_LINKS | PROP_REG_INFO | PROP_DEATH_NOTES);
- }
- }
-
- no_new_pseudos = 1;
-
- close_dump_file (DFI_life, print_rtl_with_bb, get_insns ());
-
- ggc_collect ();
-}
-
-/* Perform common subexpression elimination. Nonzero value from
- `cse_main' means that jumps were simplified and some code may now
- be unreachable, so do jump optimization again. */
-static void
-rest_of_handle_cse (void)
-{
- int tem;
-
- open_dump_file (DFI_cse, current_function_decl);
- if (dump_file)
- dump_flow_info (dump_file);
- timevar_push (TV_CSE);
-
- reg_scan (get_insns (), max_reg_num (), 1);
-
- tem = cse_main (get_insns (), max_reg_num (), 0, dump_file);
- if (tem)
- rebuild_jump_labels (get_insns ());
- if (purge_all_dead_edges (0))
- delete_unreachable_blocks ();
-
- delete_trivially_dead_insns (get_insns (), max_reg_num ());
-
- /* If we are not running more CSE passes, then we are no longer
- expecting CSE to be run. But always rerun it in a cheap mode. */
- cse_not_expected = !flag_rerun_cse_after_loop && !flag_gcse;
-
- if (tem || optimize > 1)
- cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP);
-
- timevar_pop (TV_CSE);
- close_dump_file (DFI_cse, print_rtl_with_bb, get_insns ());
-
- ggc_collect ();
-}
-
-/* Run second CSE pass after loop optimizations. */
-static void
-rest_of_handle_cse2 (void)
-{
- int tem;
-
- timevar_push (TV_CSE2);
- open_dump_file (DFI_cse2, current_function_decl);
- if (dump_file)
- dump_flow_info (dump_file);
- /* CFG is no longer maintained up-to-date. */
- tem = cse_main (get_insns (), max_reg_num (), 1, dump_file);
-
- /* Run a pass to eliminate duplicated assignments to condition code
- registers. We have to run this after bypass_jumps, because it
- makes it harder for that pass to determine whether a jump can be
- bypassed safely. */
- cse_condition_code_reg ();
-
- purge_all_dead_edges (0);
- delete_trivially_dead_insns (get_insns (), max_reg_num ());
-
- if (tem)
- {
- timevar_push (TV_JUMP);
- rebuild_jump_labels (get_insns ());
- cleanup_cfg (CLEANUP_EXPENSIVE);
- timevar_pop (TV_JUMP);
- }
- reg_scan (get_insns (), max_reg_num (), 0);
- close_dump_file (DFI_cse2, print_rtl_with_bb, get_insns ());
- timevar_pop (TV_CSE2);
-
- ggc_collect ();
-}
-
-/* Perform global cse. */
-static void
-rest_of_handle_gcse (void)
-{
- int save_csb, save_cfj;
- int tem2 = 0, tem;
-
- timevar_push (TV_GCSE);
- open_dump_file (DFI_gcse, current_function_decl);
-
- tem = gcse_main (get_insns (), dump_file);
- rebuild_jump_labels (get_insns ());
- delete_trivially_dead_insns (get_insns (), max_reg_num ());
-
- save_csb = flag_cse_skip_blocks;
- save_cfj = flag_cse_follow_jumps;
- flag_cse_skip_blocks = flag_cse_follow_jumps = 0;
-
- /* If -fexpensive-optimizations, re-run CSE to clean up things done
- by gcse. */
- if (flag_expensive_optimizations)
- {
- timevar_push (TV_CSE);
- reg_scan (get_insns (), max_reg_num (), 1);
- tem2 = cse_main (get_insns (), max_reg_num (), 0, dump_file);
- purge_all_dead_edges (0);
- delete_trivially_dead_insns (get_insns (), max_reg_num ());
- timevar_pop (TV_CSE);
- cse_not_expected = !flag_rerun_cse_after_loop;
- }
-
- /* If gcse or cse altered any jumps, rerun jump optimizations to clean
- things up. Then possibly re-run CSE again. */
- while (tem || tem2)
- {
- tem = tem2 = 0;
- timevar_push (TV_JUMP);
- rebuild_jump_labels (get_insns ());
- cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP);
- timevar_pop (TV_JUMP);
-
- if (flag_expensive_optimizations)
- {
- timevar_push (TV_CSE);
- reg_scan (get_insns (), max_reg_num (), 1);
- tem2 = cse_main (get_insns (), max_reg_num (), 0, dump_file);
- purge_all_dead_edges (0);
- delete_trivially_dead_insns (get_insns (), max_reg_num ());
- timevar_pop (TV_CSE);
- }
- }
-
- close_dump_file (DFI_gcse, print_rtl_with_bb, get_insns ());
- timevar_pop (TV_GCSE);
-
- ggc_collect ();
- flag_cse_skip_blocks = save_csb;
- flag_cse_follow_jumps = save_cfj;
-#ifdef ENABLE_CHECKING
- verify_flow_info ();
-#endif
-}
-
-/* Move constant computations out of loops. */
-static void
-rest_of_handle_loop_optimize (void)
-{
- int do_unroll, do_prefetch;
-
- timevar_push (TV_LOOP);
- delete_dead_jumptables ();
- cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP);
- open_dump_file (DFI_loop, current_function_decl);
-
- /* CFG is no longer maintained up-to-date. */
- free_bb_for_insn ();
-
- if (flag_unroll_loops)
- do_unroll = LOOP_AUTO_UNROLL; /* Having two unrollers is useless. */
- else
- do_unroll = flag_old_unroll_loops ? LOOP_UNROLL : LOOP_AUTO_UNROLL;
- do_prefetch = flag_prefetch_loop_arrays ? LOOP_PREFETCH : 0;
-
- if (flag_rerun_loop_opt)
- {
- cleanup_barriers ();
-
- /* We only want to perform unrolling once. */
- loop_optimize (get_insns (), dump_file, do_unroll);
- do_unroll = 0;
-
- /* The first call to loop_optimize makes some instructions
- trivially dead. We delete those instructions now in the
- hope that doing so will make the heuristics in loop work
- better and possibly speed up compilation. */
- delete_trivially_dead_insns (get_insns (), max_reg_num ());
-
- /* The regscan pass is currently necessary as the alias
- analysis code depends on this information. */
- reg_scan (get_insns (), max_reg_num (), 1);
- }
- cleanup_barriers ();
- loop_optimize (get_insns (), dump_file, do_unroll | do_prefetch);
-
- /* Loop can create trivially dead instructions. */
- delete_trivially_dead_insns (get_insns (), max_reg_num ());
- find_basic_blocks (get_insns (), max_reg_num (), dump_file);
- close_dump_file (DFI_loop, print_rtl, get_insns ());
- timevar_pop (TV_LOOP);
-
- ggc_collect ();
-}
-
-/* Perform loop optimizations. It might be better to do them a bit
- sooner, but we want the profile feedback to work more
- efficiently. */
-static void
-rest_of_handle_loop2 (void)
-{
- struct loops *loops;
- basic_block bb;
-
- if (!flag_move_loop_invariants
- && !flag_unswitch_loops
- && !flag_peel_loops
- && !flag_unroll_loops
- && !flag_branch_on_count_reg)
+ current_pass = pass;
+ if (!ipa_pass->function_transform)
return;
- timevar_push (TV_LOOP);
- open_dump_file (DFI_loop2, current_function_decl);
- if (dump_file)
- dump_flow_info (dump_file);
-
- /* Initialize structures for layout changes. */
- cfg_layout_initialize ();
-
- loops = loop_optimizer_init (dump_file);
-
- if (loops)
- {
- /* The optimizations: */
- if (flag_move_loop_invariants)
- move_loop_invariants (loops);
-
- if (flag_unswitch_loops)
- unswitch_loops (loops);
-
- if (flag_peel_loops || flag_unroll_loops)
- unroll_and_peel_loops (loops,
- (flag_peel_loops ? UAP_PEEL : 0) |
- (flag_unroll_loops ? UAP_UNROLL : 0) |
- (flag_unroll_all_loops ? UAP_UNROLL_ALL : 0));
-
-#ifdef HAVE_doloop_end
- if (flag_branch_on_count_reg && HAVE_doloop_end)
- doloop_optimize_loops (loops);
-#endif /* HAVE_doloop_end */
-
- loop_optimizer_finalize (loops, dump_file);
- }
-
- free_dominance_info (CDI_DOMINATORS);
+ /* Note that the folders should only create gimple expressions.
+ This is a hack until the new folder is ready. */
+ in_gimple_form = (cfun && (cfun->curr_properties & PROP_trees)) != 0;
- /* Finalize layout changes. */
- FOR_EACH_BB (bb)
- if (bb->next_bb != EXIT_BLOCK_PTR)
- bb->rbi->next = bb->next_bb;
- cfg_layout_finalize ();
+ pass_init_dump_file (pass);
- cleanup_cfg (CLEANUP_EXPENSIVE);
- delete_trivially_dead_insns (get_insns (), max_reg_num ());
- reg_scan (get_insns (), max_reg_num (), 0);
- if (dump_file)
- dump_flow_info (dump_file);
- close_dump_file (DFI_loop2, print_rtl_with_bb, get_insns ());
- timevar_pop (TV_LOOP);
- ggc_collect ();
-}
+ /* Run pre-pass verification. */
+ execute_todo (ipa_pass->function_transform_todo_flags_start);
-static void
-rest_of_handle_branch_target_load_optimize (void)
-{
- static int warned = 0;
-
- /* Leave this a warning for now so that it is possible to experiment
- with running this pass twice. In 3.6, we should either make this
- an error, or use separate dump files. */
- if (flag_branch_target_load_optimize
- && flag_branch_target_load_optimize2
- && !warned)
- {
- warning ("branch target register load optimization is not intended "
- "to be run twice");
+ /* If a timevar is present, start it. */
+ if (pass->tv_id)
+ timevar_push (pass->tv_id);
- warned = 1;
- }
+ /* Do it! */
+ todo_after = ipa_pass->function_transform (node);
- open_dump_file (DFI_branch_target_load, current_function_decl);
- branch_target_load_optimize (epilogue_completed);
- close_dump_file (DFI_branch_target_load, print_rtl_with_bb, get_insns ());
- ggc_collect ();
-}
+ /* Stop timevar. */
+ if (pass->tv_id)
+ timevar_pop (pass->tv_id);
-#ifdef OPTIMIZE_MODE_SWITCHING
-static void
-rest_of_handle_mode_switching (void)
-{
- timevar_push (TV_MODE_SWITCH);
+ /* Run post-pass cleanup and verification. */
+ execute_todo (todo_after);
+ verify_interpass_invariants ();
- no_new_pseudos = 0;
- optimize_mode_switching (NULL);
- no_new_pseudos = 1;
+ pass_fini_dump_file (pass);
- timevar_pop (TV_MODE_SWITCH);
+ current_pass = NULL;
}
-#endif
-static void
-rest_of_handle_jump (void)
+static bool
+execute_one_pass (struct opt_pass *pass)
{
- ggc_collect ();
+ bool initializing_dump;
+ unsigned int todo_after = 0;
- timevar_push (TV_JUMP);
- open_dump_file (DFI_sibling, current_function_decl);
-
- /* ??? We may get caled either via tree_rest_of_compilation when the CFG
- is already built or directly (for instance from coverage code).
- The direct callers shall be updated. */
- if (!basic_block_info)
- {
- init_flow ();
- rebuild_jump_labels (get_insns ());
- find_exception_handler_labels ();
- find_basic_blocks (get_insns (), max_reg_num (), dump_file);
- }
-
- /* ??? We may get called either via tree_rest_of_compilation when the CFG
- is already built or directly (for instance from coverage code).
- The direct callers shall be updated. */
- if (!basic_block_info)
- {
- init_flow ();
- rebuild_jump_labels (get_insns ());
- find_exception_handler_labels ();
- find_basic_blocks (get_insns (), max_reg_num (), dump_file);
- }
- delete_unreachable_blocks ();
-#ifdef ENABLE_CHECKING
- verify_flow_info ();
-#endif
- timevar_pop (TV_JUMP);
-}
+ /* IPA passes are executed on whole program, so cfun should be NULL.
+ Other passes need function context set. */
+ if (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS)
+ gcc_assert (!cfun && !current_function_decl);
+ else
+ gcc_assert (cfun && current_function_decl);
-static void
-rest_of_handle_guess_branch_prob (void)
-{
- /* Turn NOTE_INSN_PREDICTIONs into branch predictions. */
- if (flag_guess_branch_prob)
+ if (cfun && cfun->ipa_transforms_to_apply)
{
- timevar_push (TV_BRANCH_PROB);
- note_prediction_to_br_prob ();
- timevar_pop (TV_BRANCH_PROB);
+ unsigned int i;
+ struct cgraph_node *node = cgraph_node (current_function_decl);
+
+ for (i = 0; i < VEC_length (ipa_opt_pass, cfun->ipa_transforms_to_apply);
+ i++)
+ execute_one_ipa_transform_pass (node,
+ VEC_index (ipa_opt_pass,
+ cfun->ipa_transforms_to_apply,
+ i));
+ VEC_free (ipa_opt_pass, heap, cfun->ipa_transforms_to_apply);
+ cfun->ipa_transforms_to_apply = NULL;
}
-}
-static void
-rest_of_handle_eh (void)
-{
- insn_locators_initialize ();
- /* Complete generation of exception handling code. */
- if (doing_eh (0))
- {
- timevar_push (TV_JUMP);
- open_dump_file (DFI_eh, current_function_decl);
-
- finish_eh_generation ();
-
- close_dump_file (DFI_eh, print_rtl, get_insns ());
- timevar_pop (TV_JUMP);
- }
-}
+ current_pass = pass;
+ /* See if we're supposed to run this pass. */
+ if (pass->gate && !pass->gate ())
+ return false;
+ if (!quiet_flag && !cfun)
+ fprintf (stderr, " <%s>", pass->name ? pass->name : "");
-static void
-rest_of_handle_prologue_epilogue (void)
-{
- if (optimize && !flow2_completed)
- cleanup_cfg (CLEANUP_EXPENSIVE);
-
- /* On some machines, the prologue and epilogue code, or parts thereof,
- can be represented as RTL. Doing so lets us schedule insns between
- it and the rest of the code and also allows delayed branch
- scheduling to operate in the epilogue. */
- thread_prologue_and_epilogue_insns (get_insns ());
- epilogue_completed = 1;
-
- if (optimize && flow2_completed)
- life_analysis (dump_file, PROP_POSTRELOAD);
-}
+ if (pass->todo_flags_start & TODO_set_props)
+ cfun->curr_properties = pass->properties_required;
-static void
-rest_of_handle_stack_adjustments (void)
-{
- life_analysis (dump_file, PROP_POSTRELOAD);
- cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_UPDATE_LIFE
- | (flag_crossjumping ? CLEANUP_CROSSJUMP : 0));
-
- /* This is kind of a heuristic. We need to run combine_stack_adjustments
- even for machines with possibly nonzero RETURN_POPS_ARGS
- and ACCUMULATE_OUTGOING_ARGS. We expect that only ports having
- push instructions will have popping returns. */
-#ifndef PUSH_ROUNDING
- if (!ACCUMULATE_OUTGOING_ARGS)
-#endif
- combine_stack_adjustments ();
-}
+ /* Note that the folders should only create gimple expressions.
+ This is a hack until the new folder is ready. */
+ in_gimple_form = (cfun && (cfun->curr_properties & PROP_trees)) != 0;
-static void
-rest_of_handle_flow2 (void)
-{
- timevar_push (TV_FLOW2);
- open_dump_file (DFI_flow2, current_function_decl);
+ /* Run pre-pass verification. */
+ execute_todo (pass->todo_flags_start);
- /* Re-create the death notes which were deleted during reload. */
#ifdef ENABLE_CHECKING
- verify_flow_info ();
-#endif
-
- /* If optimizing, then go ahead and split insns now. */
-#ifndef STACK_REGS
- if (optimize > 0)
-#endif
- split_all_insns (0);
-
- if (flag_branch_target_load_optimize)
- rest_of_handle_branch_target_load_optimize ();
-
- if (!targetm.late_rtl_prologue_epilogue)
- rest_of_handle_prologue_epilogue ();
-
- if (optimize)
- rest_of_handle_stack_adjustments ();
-
- flow2_completed = 1;
-
- close_dump_file (DFI_flow2, print_rtl_with_bb, get_insns ());
- timevar_pop (TV_FLOW2);
-
- ggc_collect ();
-}
-
-
-static void
-rest_of_handle_jump2 (void)
-{
- open_dump_file (DFI_jump, current_function_decl);
-
- /* Always do one jump optimization pass to ensure that JUMP_LABEL fields
- are initialized and to compute whether control can drop off the end
- of the function. */
-
- timevar_push (TV_JUMP);
- /* Turn NOTE_INSN_EXPECTED_VALUE into REG_BR_PROB. Do this
- before jump optimization switches branch directions. */
- if (flag_guess_branch_prob)
- expected_value_to_br_prob ();
-
- delete_trivially_dead_insns (get_insns (), max_reg_num ());
- reg_scan (get_insns (), max_reg_num (), 0);
- if (dump_file)
- dump_flow_info (dump_file);
- cleanup_cfg ((optimize ? CLEANUP_EXPENSIVE : 0) | CLEANUP_PRE_LOOP
- | (flag_thread_jumps ? CLEANUP_THREADING : 0));
-
- create_loop_notes ();
-
- purge_line_number_notes (get_insns ());
-
- if (optimize)
- cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP);
-
- /* Jump optimization, and the removal of NULL pointer checks, may
- have reduced the number of instructions substantially. CSE, and
- future passes, allocate arrays whose dimensions involve the
- maximum instruction UID, so if we can reduce the maximum UID
- we'll save big on memory. */
- renumber_insns (dump_file);
-
- close_dump_file (DFI_jump, print_rtl_with_bb, get_insns ());
- timevar_pop (TV_JUMP);
-
- ggc_collect ();
-}
-
-#ifdef HAVE_peephole2
-static void
-rest_of_handle_peephole2 (void)
-{
- timevar_push (TV_PEEPHOLE2);
- open_dump_file (DFI_peephole2, current_function_decl);
-
- peephole2_optimize (dump_file);
-
- close_dump_file (DFI_peephole2, print_rtl_with_bb, get_insns ());
- timevar_pop (TV_PEEPHOLE2);
-}
-#endif
-
-static void
-rest_of_handle_postreload (void)
-{
- timevar_push (TV_RELOAD_CSE_REGS);
- open_dump_file (DFI_postreload, current_function_decl);
-
- /* Do a very simple CSE pass over just the hard registers. */
- reload_cse_regs (get_insns ());
- /* reload_cse_regs can eliminate potentially-trapping MEMs.
- Remove any EH edges associated with them. */
- if (flag_non_call_exceptions)
- purge_all_dead_edges (0);
-
- close_dump_file (DFI_postreload, print_rtl_with_bb, get_insns ());
- timevar_pop (TV_RELOAD_CSE_REGS);
-}
-
-static void
-rest_of_handle_shorten_branches (void)
-{
- /* Shorten branches. */
- timevar_push (TV_SHORTEN_BRANCH);
- shorten_branches (get_insns ());
- timevar_pop (TV_SHORTEN_BRANCH);
-}
-
-static void
-rest_of_clean_state (void)
-{
- coverage_end_function ();
-
- /* In case the function was not output,
- don't leave any temporary anonymous types
- queued up for sdb output. */
-#ifdef SDB_DEBUGGING_INFO
- if (write_symbols == SDB_DEBUG)
- sdbout_types (NULL_TREE);
+ do_per_function (verify_curr_properties,
+ (void *)(size_t)pass->properties_required);
#endif
- reload_completed = 0;
- epilogue_completed = 0;
- flow2_completed = 0;
- no_new_pseudos = 0;
+ initializing_dump = pass_init_dump_file (pass);
- timevar_push (TV_FINAL);
+ /* If a timevar is present, start it. */
+ if (pass->tv_id)
+ timevar_push (pass->tv_id);
- /* Clear out the insn_length contents now that they are no
- longer valid. */
- init_insn_lengths ();
-
- /* Show no temporary slots allocated. */
- init_temp_slots ();
-
- free_basic_block_vars ();
- free_bb_for_insn ();
-
- timevar_pop (TV_FINAL);
-
- if (targetm.binds_local_p (current_function_decl))
+ /* Do it! */
+ if (pass->execute)
{
- int pref = cfun->preferred_stack_boundary;
- if (cfun->recursive_call_emit
- && cfun->stack_alignment_needed > cfun->preferred_stack_boundary)
- pref = cfun->stack_alignment_needed;
- cgraph_rtl_info (current_function_decl)->preferred_incoming_stack_boundary
- = pref;
+ todo_after = pass->execute ();
+ do_per_function (clear_last_verified, NULL);
}
- /* Make sure volatile mem refs aren't considered valid operands for
- arithmetic insns. We must call this here if this is a nested inline
- function, since the above code leaves us in the init_recog state
- (from final.c), and the function context push/pop code does not
- save/restore volatile_ok.
-
- ??? Maybe it isn't necessary for expand_start_function to call this
- anymore if we do it here? */
-
- init_recog_no_volatile ();
-
- /* We're done with this function. Free up memory if we can. */
- free_after_parsing (cfun);
-}
-\f
-
-/* This is called from finish_function (within langhooks.parse_file)
- after each top-level definition is parsed.
- It is supposed to compile that function or variable
- and output the assembler code for it.
- After we return, the tree storage is freed. */
-
-void
-rest_of_compilation (void)
-{
- /* There's no need to defer outputting this function any more; we
- know we want to output it. */
- DECL_DEFER_OUTPUT (current_function_decl) = 0;
-
- /* Register rtl specific functions for cfg. */
- rtl_register_cfg_hooks ();
+ /* Stop timevar. */
+ if (pass->tv_id)
+ timevar_pop (pass->tv_id);
- /* Now that we're out of the frontend, we shouldn't have any more
- CONCATs anywhere. */
- generating_concat_p = 0;
-
- /* When processing delayed functions, prepare_function_start () won't
- have been run to re-initialize it. */
- cse_not_expected = ! optimize;
-
- finalize_block_changes ();
-
- /* Dump the rtl code if we are dumping rtl. */
- if (open_dump_file (DFI_rtl, current_function_decl))
- close_dump_file (DFI_rtl, print_rtl, get_insns ());
-
- /* Convert from NOTE_INSN_EH_REGION style notes, and do other
- sorts of eh initialization. Delay this until after the
- initial rtl dump so that we can see the original nesting. */
- convert_from_eh_region_ranges ();
-
- /* If we're emitting a nested function, make sure its parent gets
- emitted as well. Doing otherwise confuses debug info. */
- {
- tree parent;
- for (parent = DECL_CONTEXT (current_function_decl);
- parent != NULL_TREE;
- parent = get_containing_scope (parent))
- if (TREE_CODE (parent) == FUNCTION_DECL)
- TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (parent)) = 1;
- }
+ do_per_function (update_properties_after_pass, pass);
- /* We are now committed to emitting code for this function. Do any
- preparation, such as emitting abstract debug info for the inline
- before it gets mangled by optimization. */
- if (cgraph_function_possibly_inlined_p (current_function_decl))
- (*debug_hooks->outlining_inline_function) (current_function_decl);
-
- /* Remove any notes we don't need. That will make iterating
- over the instruction sequence faster, and allow the garbage
- collector to reclaim the memory used by the notes. */
- remove_unnecessary_notes ();
-
- /* Initialize some variables used by the optimizers. */
- init_function_for_compilation ();
-
- TREE_ASM_WRITTEN (current_function_decl) = 1;
-
- /* Now that integrate will no longer see our rtl, we need not
- distinguish between the return value of this function and the
- return value of called functions. Also, we can remove all SETs
- of subregs of hard registers; they are only here because of
- integrate. Also, we can now initialize pseudos intended to
- carry magic hard reg data throughout the function.
-
- FIXME: All this looks thoroughly obsolete... maybe we can
- get rid of both these lines unconditionally? */
- rtx_equal_function_value_matters = 0;
- purge_hard_subreg_sets (get_insns ());
-
- /* Early return if there were errors. We can run afoul of our
- consistency checks, and there's not really much point in fixing them. */
- if (rtl_dump_and_exit || flag_syntax_only || errorcount || sorrycount)
- goto exit_rest_of_compilation;
-
- rest_of_handle_jump ();
- rest_of_handle_guess_branch_prob ();
-
- if (cfun->tail_call_emit)
- fixup_tail_calls ();
-
- rest_of_handle_eh ();
-
- /* Delay emitting hard_reg_initial_value sets until after EH landing pad
- generation, which might create new sets. */
- emit_initial_value_sets ();
-
-#ifdef FINALIZE_PIC
- /* If we are doing position-independent code generation, now
- is the time to output special prologues and epilogues.
- We do not want to do this earlier, because it just clutters
- up inline functions with meaningless insns. */
- if (flag_pic)
- FINALIZE_PIC;
-#endif
-
- /* Copy any shared structure that should not be shared. */
- unshare_all_rtl ();
-
-#ifdef SETJMP_VIA_SAVE_AREA
- /* This must be performed before virtual register instantiation.
- Please be aware that everything in the compiler that can look
- at the RTL up to this point must understand that REG_SAVE_AREA
- is just like a use of the REG contained inside. */
- if (current_function_calls_alloca)
- optimize_save_area_alloca ();
-#endif
-
- /* Instantiate all virtual registers. */
- instantiate_virtual_regs ();
-
- rest_of_handle_jump2 ();
-
- if (optimize > 0)
- rest_of_handle_cse ();
-
- if (optimize > 0)
- {
- if (flag_gcse)
- rest_of_handle_gcse ();
-
- if (flag_loop_optimize)
- rest_of_handle_loop_optimize ();
-
- if (flag_gcse)
- rest_of_handle_jump_bypass ();
- }
-
- timevar_push (TV_FLOW);
- rest_of_handle_cfg ();
-
- if (!flag_tree_based_profiling
- && (optimize > 0 || profile_arc_flag
- || flag_test_coverage || flag_branch_probabilities))
- {
- rtl_register_profile_hooks ();
- rtl_register_value_prof_hooks ();
- rest_of_handle_branch_prob ();
-
- if (flag_branch_probabilities
- && flag_profile_values
- && flag_value_profile_transformations)
- rest_of_handle_value_profile_transformations ();
-
- /* Remove the death notes created for vpt. */
- if (flag_profile_values)
- count_or_remove_death_notes (NULL, 1);
- }
-
- if (optimize > 0)
- rest_of_handle_if_conversion ();
-
- if (optimize > 0 && flag_tracer)
- rest_of_handle_tracer ();
-
- if (optimize > 0
- && flag_loop_optimize2)
- rest_of_handle_loop2 ();
-
- if (optimize > 0 && flag_web)
- rest_of_handle_web ();
-
- if (optimize > 0 && flag_rerun_cse_after_loop)
- rest_of_handle_cse2 ();
-
- cse_not_expected = 1;
-
- rest_of_handle_life ();
- timevar_pop (TV_FLOW);
-
- if (optimize > 0)
- rest_of_handle_combine ();
-
- if (optimize > 0 && flag_if_conversion)
- rest_of_handle_if_after_combine ();
-
- /* The optimization to partition hot/cold basic blocks into separate
- sections of the .o file does not work well with exception handling.
- Don't call it if there are exceptions. */
-
- if (optimize > 0 && flag_reorder_blocks_and_partition && !flag_exceptions)
- rest_of_handle_partition_blocks ();
-
- if (optimize > 0 && (flag_regmove || flag_expensive_optimizations))
- rest_of_handle_regmove ();
-
- /* Do unconditional splitting before register allocation to allow machine
- description to add extra information not needed previously. */
- split_all_insns (1);
-
-#ifdef OPTIMIZE_MODE_SWITCHING
- rest_of_handle_mode_switching ();
-#endif
-
- /* Any of the several passes since flow1 will have munged register
- lifetime data a bit. We need it to be up to date for scheduling
- (see handling of reg_known_equiv in init_alias_analysis). */
- recompute_reg_usage (get_insns (), !optimize_size);
-
-#ifdef INSN_SCHEDULING
- if (optimize > 0 && flag_modulo_sched)
- rest_of_handle_sms ();
-
- if (flag_schedule_insns)
- rest_of_handle_sched ();
-#endif
-
- /* Determine if the current function is a leaf before running reload
- since this can impact optimizations done by the prologue and
- epilogue thus changing register elimination offsets. */
- current_function_is_leaf = leaf_function_p ();
-
- if (flag_new_regalloc)
- {
- if (rest_of_handle_new_regalloc ())
- goto exit_rest_of_compilation;
- }
- else
- {
- if (rest_of_handle_old_regalloc ())
- goto exit_rest_of_compilation;
- }
-
- if (optimize > 0)
- rest_of_handle_postreload ();
-
- if (optimize > 0 && flag_gcse_after_reload)
- rest_of_handle_gcse2 ();
-
- rest_of_handle_flow2 ();
-
-#ifdef HAVE_peephole2
- if (optimize > 0 && flag_peephole2)
- rest_of_handle_peephole2 ();
-#endif
-
- if (optimize > 0)
- rest_of_handle_if_after_reload ();
-
- if (optimize > 0)
+ if (initializing_dump
+ && dump_file
+ && graph_dump_format != no_graph
+ && (cfun->curr_properties & (PROP_cfg | PROP_rtl))
+ == (PROP_cfg | PROP_rtl))
{
- if (flag_rename_registers || flag_cprop_registers)
- rest_of_handle_regrename ();
-
- rest_of_handle_reorder_blocks ();
+ get_dump_file_info (pass->static_pass_number)->flags |= TDF_GRAPH;
+ dump_flags |= TDF_GRAPH;
+ clean_graph_dump_file (dump_file_name);
}
- if (flag_branch_target_load_optimize2)
- rest_of_handle_branch_target_load_optimize ();
-
-#ifdef LEAF_REGISTERS
- current_function_uses_only_leaf_regs
- = optimize > 0 && only_leaf_regs_used () && leaf_function_p ();
-#endif
+ /* Run post-pass cleanup and verification. */
+ execute_todo (todo_after | pass->todo_flags_finish);
+ verify_interpass_invariants ();
+ if (pass->type == IPA_PASS)
+ do_per_function (add_ipa_transform_pass, pass);
- if (targetm.late_rtl_prologue_epilogue)
- rest_of_handle_prologue_epilogue ();
+ if (!current_function_decl)
+ cgraph_process_new_functions ();
-#ifdef INSN_SCHEDULING
- if (optimize > 0 && flag_schedule_insns_after_reload)
- rest_of_handle_sched2 ();
-#endif
-
-#ifdef STACK_REGS
- rest_of_handle_stack_regs ();
-#endif
+ pass_fini_dump_file (pass);
- compute_alignments ();
+ if (pass->type != SIMPLE_IPA_PASS && pass->type != IPA_PASS)
+ gcc_assert (!(cfun->curr_properties & PROP_trees)
+ || pass->type != RTL_PASS);
- if (flag_var_tracking)
- rest_of_handle_variable_tracking ();
+ current_pass = NULL;
- /* CFG is no longer maintained up-to-date. */
- free_bb_for_insn ();
-
- if (targetm.machine_dependent_reorg != 0)
- rest_of_handle_machine_reorg ();
-
- purge_line_number_notes (get_insns ());
- cleanup_barriers ();
-
-#ifdef DELAY_SLOTS
- if (flag_delayed_branch)
- rest_of_handle_delay_slots ();
-#endif
-
-#if defined (HAVE_ATTR_length) && !defined (STACK_REGS)
- timevar_push (TV_SHORTEN_BRANCH);
- split_all_insns_noflow ();
- timevar_pop (TV_SHORTEN_BRANCH);
-#endif
-
- convert_to_eh_region_ranges ();
-
- rest_of_handle_shorten_branches ();
-
- set_nothrow_function_flags ();
-
- rest_of_handle_final ();
-
- exit_rest_of_compilation:
-
- rest_of_clean_state ();
-}
-
-void
-init_optimization_passes (void)
-{
- open_dump_file (DFI_cgraph, NULL);
- cgraph_dump_file = dump_file;
- dump_file = NULL;
+ return true;
}
void
-finish_optimization_passes (void)
+execute_pass_list (struct opt_pass *pass)
{
- timevar_push (TV_DUMP);
- if (profile_arc_flag || flag_test_coverage || flag_branch_probabilities)
+ do
{
- open_dump_file (DFI_bp, NULL);
- end_branch_prob ();
- close_dump_file (DFI_bp, NULL, NULL_RTX);
- }
-
- if (optimize > 0 && open_dump_file (DFI_combine, NULL))
- {
- dump_combine_total_stats (dump_file);
- close_dump_file (DFI_combine, NULL, NULL_RTX);
- }
-
- dump_file = cgraph_dump_file;
- cgraph_dump_file = NULL;
- close_dump_file (DFI_cgraph, NULL, NULL_RTX);
-
- /* Do whatever is necessary to finish printing the graphs. */
- if (graph_dump_format != no_graph)
- {
- int i;
-
- for (i = 0; i < (int) DFI_MAX; ++i)
- if (dump_file_tbl[i].initialized && dump_file_tbl[i].graph_dump_p)
- {
- char seq[16];
- char *suffix;
-
- sprintf (seq, DUMPFILE_FORMAT, i);
- suffix = concat (seq, dump_file_tbl[i].extension, NULL);
- finish_graph_dump_file (dump_base_name, suffix);
- free (suffix);
- }
+ gcc_assert (pass->type == GIMPLE_PASS
+ || pass->type == RTL_PASS);
+ if (execute_one_pass (pass) && pass->sub)
+ execute_pass_list (pass->sub);
+ pass = pass->next;
}
-
- timevar_pop (TV_DUMP);
+ while (pass);
}
-bool
-enable_rtl_dump_file (int letter)
+/* Same as execute_pass_list but assume that subpasses of IPA passes
+ are local passes. */
+void
+execute_ipa_pass_list (struct opt_pass *pass)
{
- bool matched = false;
- int i;
-
- if (letter == 'a')
- {
- for (i = 0; i < (int) DFI_MAX; ++i)
- dump_file_tbl[i].enabled = 1;
- matched = true;
- }
- else
+ bool summaries_generated = false;
+ do
{
- for (i = 0; i < (int) DFI_MAX; ++i)
- if (letter == dump_file_tbl[i].debug_switch)
- {
- dump_file_tbl[i].enabled = 1;
- matched = true;
- }
+ gcc_assert (!current_function_decl);
+ gcc_assert (!cfun);
+ gcc_assert (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS);
+ if (pass->type == IPA_PASS && (!pass->gate || pass->gate ()))
+ {
+ if (!summaries_generated)
+ {
+ if (!quiet_flag && !cfun)
+ fprintf (stderr, " <summary generate>");
+ execute_ipa_summary_passes ((struct ipa_opt_pass *) pass);
+ }
+ summaries_generated = true;
+ }
+ if (execute_one_pass (pass) && pass->sub)
+ {
+ if (pass->sub->type == GIMPLE_PASS)
+ do_per_function_toporder ((void (*)(void *))execute_pass_list,
+ pass->sub);
+ else if (pass->sub->type == SIMPLE_IPA_PASS
+ || pass->sub->type == IPA_PASS)
+ execute_ipa_pass_list (pass->sub);
+ else
+ gcc_unreachable ();
+ }
+ if (!current_function_decl)
+ cgraph_process_new_functions ();
+ pass = pass->next;
}
-
- return matched;
+ while (pass);
}
-struct tree_opt_pass pass_rest_of_compilation =
-{
- "rest of compilation", /* name */
- NULL, /* gate */
- rest_of_compilation, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_REST_OF_COMPILATION, /* tv_id */
- PROP_rtl, /* properties_required */
- 0, /* properties_provided */
- PROP_rtl, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_ggc_collect /* todo_flags_finish */
-};
-
-
+#include "gt-passes.h"