#include "config.h"
#undef FLOAT
#undef FFS
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include <signal.h>
#ifdef HAVE_SYS_RESOURCE_H
# include <sys/resource.h>
#endif
#ifdef HAVE_SYS_TIMES_H
# include <sys/times.h>
#endif
#include "line-map.h"
#include "input.h"
#include "tree.h"
#include "rtl.h"
#include "tm_p.h"
#include "flags.h"
#include "insn-attr.h"
#include "insn-config.h"
#include "insn-flags.h"
#include "hard-reg-set.h"
#include "recog.h"
#include "output.h"
#include "except.h"
#include "function.h"
#include "toplev.h"
#include "expr.h"
#include "basic-block.h"
#include "intl.h"
#include "ggc.h"
#include "graph.h"
#include "regs.h"
#include "timevar.h"
#include "diagnostic.h"
#include "params.h"
#include "reload.h"
#include "dwarf2asm.h"
#include "integrate.h"
#include "real.h"
#include "debug.h"
#include "target.h"
#include "langhooks.h"
#include "cfglayout.h"
#include "cfgloop.h"
#include "hosthooks.h"
#include "cgraph.h"
#include "opts.h"
#include "coverage.h"
#include "value-prof.h"
#include "tree-inline.h"
#include "tree-flow.h"
#include "tree-pass.h"
#include "tree-dump.h"
#ifdef ENABLE_LLVM
#include "llvm.h"
#undef INSN_SCHEDULING
#endif
#if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
#include "dwarf2out.h"
#endif
#if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO)
#include "dbxout.h"
#endif
#ifdef SDB_DEBUGGING_INFO
#include "sdbout.h"
#endif
#ifdef XCOFF_DEBUGGING_INFO
#include "xcoffout.h"
#endif
int dump_flags;
bool in_gimple_form;
void
rest_of_decl_compilation (tree decl,
int top_level,
int at_end)
{
{
tree alias;
alias = lookup_attribute ("alias", DECL_ATTRIBUTES (decl));
if (alias)
{
alias = TREE_VALUE (TREE_VALUE (alias));
alias = get_identifier (TREE_STRING_POINTER (alias));
assemble_alias (decl, alias);
}
}
if (DECL_ASSEMBLER_NAME_SET_P (decl) && DECL_REGISTER (decl))
#ifndef ENABLE_LLVM
make_decl_rtl (decl);
#else
make_decl_llvm (decl);
#endif
if (TREE_STATIC (decl) || DECL_EXTERNAL (decl)
|| TREE_CODE (decl) == FUNCTION_DECL)
{
timevar_push (TV_VARCONST);
if ((at_end
|| !DECL_DEFER_OUTPUT (decl)
|| DECL_INITIAL (decl))
&& !DECL_EXTERNAL (decl))
{
if (TREE_CODE (decl) != FUNCTION_DECL)
cgraph_varpool_finalize_decl (decl);
else
assemble_variable (decl, top_level, at_end, 0);
}
#ifdef ASM_FINISH_DECLARE_OBJECT
if (decl == last_assemble_variable_decl)
{
ASM_FINISH_DECLARE_OBJECT (asm_out_file, decl,
top_level, at_end);
}
#endif
timevar_pop (TV_VARCONST);
}
else if (TREE_CODE (decl) == TYPE_DECL
&& !(sorrycount || errorcount))
{
#ifndef ENABLE_LLVM
timevar_push (TV_SYMOUT);
debug_hooks->type_decl (decl, !top_level);
timevar_pop (TV_SYMOUT);
#else
llvm_emit_typedef (decl);
#endif
}
if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl))
cgraph_varpool_node (decl);
}
void
rest_of_type_compilation (tree type, int toplev)
{
if (errorcount != 0 || sorrycount != 0)
return;
#ifndef ENABLE_LLVM
timevar_push (TV_SYMOUT);
debug_hooks->type_decl (TYPE_STUB_DECL (type), !toplev);
timevar_pop (TV_SYMOUT);
#else
llvm_emit_typedef (TYPE_STUB_DECL (type));
toplev = toplev;
#endif
}
void
finish_optimization_passes (void)
{
#ifdef ENABLE_LLVM
return;
#else
enum tree_dump_index i;
struct dump_file_info *dfi;
char *name;
timevar_push (TV_DUMP);
if (profile_arc_flag || flag_test_coverage || flag_branch_probabilities)
{
dump_file = dump_begin (pass_profile.static_pass_number, NULL);
end_branch_prob ();
if (dump_file)
dump_end (pass_profile.static_pass_number, dump_file);
}
if (optimize > 0)
{
dump_file = dump_begin (pass_combine.static_pass_number, NULL);
if (dump_file)
{
dump_combine_total_stats (dump_file);
dump_end (pass_combine.static_pass_number, dump_file);
}
}
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);
}
timevar_pop (TV_DUMP);
#endif
}
static bool
gate_rest_of_compilation (void)
{
return !(rtl_dump_and_exit || flag_syntax_only || errorcount || sorrycount);
}
struct tree_opt_pass pass_rest_of_compilation =
{
NULL,
gate_rest_of_compilation,
NULL,
NULL,
NULL,
0,
TV_REST_OF_COMPILATION,
PROP_rtl,
0,
0,
0,
TODO_ggc_collect,
0
};
static bool
gate_postreload (void)
{
return reload_completed;
}
struct tree_opt_pass pass_postreload =
{
NULL,
gate_postreload,
NULL,
NULL,
NULL,
0,
0,
PROP_rtl,
0,
0,
0,
TODO_ggc_collect,
0
};
#ifdef ENABLE_LLVM
struct tree_opt_pass *all_lowering_passes, *all_extra_lowering_passes;
#else
struct tree_opt_pass *all_passes, *all_ipa_passes, *all_lowering_passes;
#endif
static void
register_one_dump_file (struct tree_opt_pass *pass, bool ipa, int properties)
{
char *dot_name, *flag_name, *glob_name;
const char *prefix;
char num[10];
int flags;
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 (ipa)
prefix = "ipa-", flags = TDF_IPA;
else if (properties & PROP_trees)
prefix = "tree-", flags = TDF_TREE;
else
prefix = "rtl-", flags = TDF_RTL;
flag_name = concat (prefix, pass->name, num, NULL);
glob_name = concat (prefix, pass->name, NULL);
pass->static_pass_number = dump_register (dot_name, flag_name, glob_name,
flags, pass->letter);
}
static int
register_dump_files_1 (struct tree_opt_pass *pass, bool ipa, int properties)
{
do
{
int new_properties = (properties | pass->properties_provided)
& ~pass->properties_destroyed;
if (pass->name)
register_one_dump_file (pass, ipa, new_properties);
if (pass->sub)
new_properties = register_dump_files_1 (pass->sub, false,
new_properties);
if (pass->gate)
properties &= new_properties;
else
properties = new_properties;
pass = pass->next;
}
while (pass);
return properties;
}
static void
register_dump_files (struct tree_opt_pass *pass, bool ipa, int properties)
{
pass->properties_required |= properties;
pass->todo_flags_start |= TODO_set_props;
register_dump_files_1 (pass, ipa, properties);
}
static struct tree_opt_pass **
next_pass_1 (struct tree_opt_pass **list, struct tree_opt_pass *pass)
{
if (pass->static_pass_number)
{
struct tree_opt_pass *new;
new = xmalloc (sizeof (*new));
memcpy (new, pass, sizeof (*new));
if (pass->name)
{
pass->static_pass_number -= 1;
new->static_pass_number = -pass->static_pass_number;
}
*list = new;
}
else
{
pass->static_pass_number = -1;
*list = pass;
}
return &(*list)->next;
}
void
init_optimization_passes (void)
{
struct tree_opt_pass **p;
#define NEXT_PASS(PASS) (p = next_pass_1 (p, &PASS))
#ifndef ENABLE_LLVM
p = &all_ipa_passes;
NEXT_PASS (pass_early_ipa_inline);
NEXT_PASS (pass_early_local_passes);
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);
*p = NULL;
#endif
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_lower_eh);
NEXT_PASS (pass_build_cfg);
#ifndef ENABLE_LLVM
NEXT_PASS (pass_lower_complex_O0);
NEXT_PASS (pass_lower_vector);
#endif
NEXT_PASS (pass_warn_function_return);
#ifndef ENABLE_LLVM
NEXT_PASS (pass_early_tree_profile);
#endif
*p = NULL;
#ifdef ENABLE_LLVM
p = &all_extra_lowering_passes;
NEXT_PASS (pass_fixup_cfg);
NEXT_PASS (pass_init_datastructures);
NEXT_PASS (pass_expand_omp);
NEXT_PASS (pass_fold_builtins);
NEXT_PASS (pass_free_datastructures);
*p = NULL;
#endif
#ifndef ENABLE_LLVM
p = &pass_early_local_passes.sub;
NEXT_PASS (pass_tree_profile);
NEXT_PASS (pass_cleanup_cfg);
NEXT_PASS (pass_rebuild_cgraph_edges);
*p = NULL;
p = &all_passes;
NEXT_PASS (pass_fixup_cfg);
NEXT_PASS (pass_init_datastructures);
NEXT_PASS (pass_expand_omp);
NEXT_PASS (pass_all_optimizations);
NEXT_PASS (pass_warn_function_noreturn);
NEXT_PASS (pass_mudflap_2);
NEXT_PASS (pass_free_datastructures);
NEXT_PASS (pass_free_cfg_annotations);
NEXT_PASS (pass_expand);
NEXT_PASS (pass_rest_of_compilation);
NEXT_PASS (pass_clean_state);
*p = NULL;
p = &pass_all_optimizations.sub;
NEXT_PASS (pass_referenced_vars);
NEXT_PASS (pass_reset_cc_flags);
NEXT_PASS (pass_create_structure_vars);
NEXT_PASS (pass_build_ssa);
NEXT_PASS (pass_may_alias);
NEXT_PASS (pass_return_slot);
NEXT_PASS (pass_rename_ssa_copies);
NEXT_PASS (pass_early_warn_uninitialized);
NEXT_PASS (pass_ccp);
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_dominator);
NEXT_PASS (pass_phi_only_cprop);
NEXT_PASS (pass_phiopt);
NEXT_PASS (pass_may_alias);
NEXT_PASS (pass_tail_recursion);
NEXT_PASS (pass_profile);
NEXT_PASS (pass_ch);
NEXT_PASS (pass_stdarg);
NEXT_PASS (pass_lower_complex);
NEXT_PASS (pass_sra);
NEXT_PASS (pass_may_alias);
NEXT_PASS (pass_rename_ssa_copies);
NEXT_PASS (pass_dominator);
NEXT_PASS (pass_phi_only_cprop);
NEXT_PASS (pass_reassoc);
NEXT_PASS (pass_dce);
NEXT_PASS (pass_dse);
NEXT_PASS (pass_may_alias);
NEXT_PASS (pass_forwprop);
NEXT_PASS (pass_phiopt);
NEXT_PASS (pass_object_sizes);
NEXT_PASS (pass_store_ccp);
NEXT_PASS (pass_store_copy_prop);
NEXT_PASS (pass_fold_builtins);
NEXT_PASS (pass_may_alias);
NEXT_PASS (pass_split_crit_edges);
NEXT_PASS (pass_pre);
NEXT_PASS (pass_may_alias);
NEXT_PASS (pass_sink_code);
NEXT_PASS (pass_tree_loop);
NEXT_PASS (pass_cse_reciprocals);
NEXT_PASS (pass_reassoc);
NEXT_PASS (pass_vrp);
NEXT_PASS (pass_dominator);
NEXT_PASS (pass_phi_only_cprop);
NEXT_PASS (pass_cd_dce);
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);
*p = NULL;
p = &pass_tree_loop.sub;
NEXT_PASS (pass_tree_loop_init);
NEXT_PASS (pass_copy_prop);
NEXT_PASS (pass_lim);
NEXT_PASS (pass_tree_unswitch);
NEXT_PASS (pass_scev_cprop);
NEXT_PASS (pass_empty_loop);
NEXT_PASS (pass_record_bounds);
NEXT_PASS (pass_linear_transform);
NEXT_PASS (pass_iv_canon);
NEXT_PASS (pass_if_conversion);
NEXT_PASS (pass_vectorize);
NEXT_PASS (pass_complete_unroll);
NEXT_PASS (pass_loop_prefetch);
NEXT_PASS (pass_iv_optimize);
NEXT_PASS (pass_tree_loop_done);
*p = NULL;
p = &pass_vectorize.sub;
NEXT_PASS (pass_lower_vector_ssa);
NEXT_PASS (pass_dce_loop);
*p = NULL;
p = &pass_loop2.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;
p = &pass_rest_of_compilation.sub;
NEXT_PASS (pass_init_function);
NEXT_PASS (pass_jump);
NEXT_PASS (pass_insn_locators_initialize);
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_jump2);
NEXT_PASS (pass_cse);
NEXT_PASS (pass_gcse);
NEXT_PASS (pass_jump_bypass);
NEXT_PASS (pass_rtl_ifcvt);
NEXT_PASS (pass_tracer);
NEXT_PASS (pass_loop2);
NEXT_PASS (pass_web);
NEXT_PASS (pass_cse2);
NEXT_PASS (pass_life);
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_mode_switching);
NEXT_PASS (pass_see);
NEXT_PASS (pass_recompute_reg_usage);
NEXT_PASS (pass_sms);
NEXT_PASS (pass_sched);
NEXT_PASS (pass_local_alloc);
#ifdef TARGET_386
NEXT_PASS (pass_life3);
#endif
NEXT_PASS (pass_global_alloc);
NEXT_PASS (pass_postreload);
*p = NULL;
p = &pass_postreload.sub;
NEXT_PASS (pass_postreload_cse);
NEXT_PASS (pass_gcse2);
NEXT_PASS (pass_flow2);
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_reorder_blocks);
NEXT_PASS (pass_branch_target_load_optimize);
NEXT_PASS (pass_leaf_regs);
NEXT_PASS (pass_sched2);
NEXT_PASS (pass_split_before_regstack);
NEXT_PASS (pass_stack_regs);
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_purge_lineno_notes);
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);
*p = NULL;
#endif
#undef NEXT_PASS
#ifndef ENABLE_LLVM
register_dump_files (all_ipa_passes, true,
PROP_gimple_any | PROP_gimple_lcf | PROP_gimple_leh
| PROP_cfg);
#endif
register_dump_files (all_lowering_passes, false, PROP_gimple_any);
#ifdef ENABLE_LLVM
register_dump_files (all_extra_lowering_passes, false,
PROP_gimple_any | PROP_gimple_lcf | PROP_gimple_leh
| PROP_cfg);
#else
register_dump_files (all_passes, false,
PROP_gimple_any | PROP_gimple_lcf | PROP_gimple_leh
| PROP_cfg);
#endif
}
static unsigned int last_verified;
static unsigned int curr_properties;
static void
execute_todo (unsigned int flags)
{
#if defined ENABLE_CHECKING
if (need_ssa_update_p ())
gcc_assert (flags & TODO_update_ssa_any);
#endif
if (curr_properties & PROP_ssa)
flags |= TODO_verify_ssa;
flags &= ~last_verified;
if (!flags)
return;
if (flags & TODO_update_smt_usage)
recalculate_used_alone ();
if (flags & TODO_cleanup_cfg)
{
updating_used_alone = true;
if (current_loops)
cleanup_tree_cfg_loop ();
else
cleanup_tree_cfg ();
recalculate_used_alone ();
if (!(flags & TODO_update_ssa_any) && need_ssa_update_p ())
flags |= TODO_update_ssa;
}
if (flags & TODO_update_ssa_any)
{
unsigned update_flags = flags & TODO_update_ssa_any;
update_ssa (update_flags);
last_verified &= ~TODO_verify_ssa;
}
if (flags & TODO_remove_unused_locals)
remove_unused_locals ();
if ((flags & TODO_dump_func)
&& dump_file && current_function_decl)
{
if (curr_properties & PROP_trees)
dump_function_to_file (current_function_decl,
dump_file, dump_flags);
else
{
#ifndef ENABLE_LLVM
if (dump_flags & TDF_SLIM)
print_rtl_slim_with_bb (dump_file, get_insns (), dump_flags);
else if ((curr_properties & PROP_cfg) && (dump_flags & TDF_BLOCKS))
print_rtl_with_bb (dump_file, get_insns ());
else
print_rtl (dump_file, get_insns ());
#endif
if (curr_properties & PROP_cfg
&& graph_dump_format != no_graph
&& (dump_flags & TDF_GRAPH))
print_rtl_graph_with_bb (dump_file_name, get_insns ());
}
fflush (dump_file);
}
if ((flags & TODO_dump_cgraph)
&& dump_file && !current_function_decl)
{
dump_cgraph (dump_file);
fflush (dump_file);
}
if (flags & TODO_ggc_collect)
{
ggc_collect ();
}
#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 ();
#endif
last_verified = flags & TODO_verify_all;
}
static void
verify_interpass_invariants (void)
{
#ifdef ENABLE_CHECKING
gcc_assert (!fold_deferring_overflow_warnings_p ());
#endif
}
static bool
execute_one_pass (struct tree_opt_pass *pass)
{
bool initializing_dump;
unsigned int todo_after = 0;
if (pass->gate && !pass->gate ())
return false;
if (pass->todo_flags_start & TODO_set_props)
curr_properties = pass->properties_required;
in_gimple_form = (curr_properties & PROP_trees) != 0;
execute_todo (pass->todo_flags_start);
gcc_assert ((curr_properties & pass->properties_required)
== pass->properties_required);
if (pass->properties_destroyed & PROP_smt_usage)
updating_used_alone = true;
if (pass->static_pass_number != -1)
{
initializing_dump = !dump_initialized_p (pass->static_pass_number);
dump_file_name = get_dump_file_name (pass->static_pass_number);
dump_file = dump_begin (pass->static_pass_number, &dump_flags);
if (dump_file && current_function_decl)
{
const char *dname, *aname;
dname = lang_hooks.decl_printable_name (current_function_decl, 2);
aname = (IDENTIFIER_POINTER
(DECL_ASSEMBLER_NAME (current_function_decl)));
fprintf (dump_file, "\n;; Function %s (%s)%s\n\n", dname, aname,
cfun->function_frequency == FUNCTION_FREQUENCY_HOT
? " (hot)"
: cfun->function_frequency == FUNCTION_FREQUENCY_UNLIKELY_EXECUTED
? " (unlikely executed)"
: "");
}
}
else
initializing_dump = false;
if (pass->tv_id)
timevar_push (pass->tv_id);
if (pass->execute)
{
todo_after = pass->execute ();
last_verified = 0;
}
if (pass->tv_id)
timevar_pop (pass->tv_id);
curr_properties = (curr_properties | pass->properties_provided)
& ~pass->properties_destroyed;
if (initializing_dump
&& dump_file
&& graph_dump_format != no_graph
&& (curr_properties & (PROP_cfg | PROP_rtl)) == (PROP_cfg | PROP_rtl))
{
get_dump_file_info (pass->static_pass_number)->flags |= TDF_GRAPH;
dump_flags |= TDF_GRAPH;
clean_graph_dump_file (dump_file_name);
}
execute_todo (todo_after | pass->todo_flags_finish);
verify_interpass_invariants ();
if (dump_file_name)
{
free ((char *) dump_file_name);
dump_file_name = NULL;
}
if (dump_file)
{
dump_end (pass->static_pass_number, dump_file);
dump_file = NULL;
}
if (pass->properties_destroyed & PROP_smt_usage)
updating_used_alone = false;
in_gimple_form = false;
return true;
}
void
execute_pass_list (struct tree_opt_pass *pass)
{
do
{
if (execute_one_pass (pass) && pass->sub)
execute_pass_list (pass->sub);
pass = pass->next;
}
while (pass);
}
void
execute_ipa_pass_list (struct tree_opt_pass *pass)
{
do
{
if (execute_one_pass (pass) && pass->sub)
{
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;
execute_pass_list (pass->sub);
free_dominance_info (CDI_DOMINATORS);
free_dominance_info (CDI_POST_DOMINATORS);
current_function_decl = NULL;
pop_cfun ();
ggc_collect ();
}
}
pass = pass->next;
}
while (pass);
}