/* Driver of optimization process
- Copyright (C) 2003-2014 Free Software Foundation, Inc.
+ Copyright (C) 2003-2015 Free Software Foundation, Inc.
Contributed by Jan Hubicka
This file is part of GCC.
#include "system.h"
#include "coretypes.h"
#include "tm.h"
+#include "alias.h"
+#include "symtab.h"
#include "tree.h"
+#include "fold-const.h"
#include "varasm.h"
#include "stor-layout.h"
#include "stringpool.h"
#include "output.h"
#include "rtl.h"
#include "predict.h"
-#include "vec.h"
-#include "hashtab.h"
-#include "hash-set.h"
-#include "machmode.h"
#include "hard-reg-set.h"
-#include "input.h"
#include "function.h"
#include "basic-block.h"
+#include "dominance.h"
+#include "cfgcleanup.h"
+#include "cfg.h"
#include "tree-ssa-alias.h"
#include "internal-fn.h"
#include "gimple-fold.h"
#include "gimple-expr.h"
-#include "is-a.h"
#include "gimple.h"
#include "gimplify.h"
#include "gimple-iterator.h"
#include "target.h"
#include "diagnostic.h"
#include "params.h"
-#include "fibheap.h"
#include "intl.h"
+#include "cgraph.h"
+#include "alloc-pool.h"
+#include "symbol-summary.h"
#include "ipa-prop.h"
#include "tree-iterator.h"
#include "tree-pass.h"
#include "tree-nested.h"
#include "gimplify.h"
#include "dbgcnt.h"
+#include "tree-chkp.h"
+#include "lto-section-names.h"
+#include "omp-low.h"
+#include "print-tree.h"
/* Queue of cgraph nodes scheduled to be added into cgraph. This is a
secondary queue used during optimization to accommodate passes that
if (forced_by_abi && TREE_PUBLIC (decl))
return true;
- /* Keep constructors, destructors and virtual functions. */
+ /* Keep constructors, destructors and virtual functions. */
if (TREE_CODE (decl) == FUNCTION_DECL
&& (DECL_STATIC_CONSTRUCTOR (decl) || DECL_STATIC_DESTRUCTOR (decl)))
return true;
case IPA:
case IPA_SSA:
+ case IPA_SSA_AFTER_INLINING:
/* When IPA optimization already started, do all essential
transformations that has been already performed on the whole
cgraph but not on this function. */
if (!node->analyzed)
node->analyze ();
push_cfun (DECL_STRUCT_FUNCTION (fndecl));
- if (state == IPA_SSA
+ if ((state == IPA_SSA || state == IPA_SSA_AFTER_INLINING)
&& !gimple_in_ssa_p (DECL_STRUCT_FUNCTION (fndecl)))
g->get_passes ()->execute_early_local_passes ();
- else if (inline_summary_vec != NULL)
+ else if (inline_summaries != NULL)
compute_inline_parameters (node, true);
free_dominance_info (CDI_POST_DOMINATORS);
free_dominance_info (CDI_DOMINATORS);
remove_all_references ();
}
-/* Return true when there are references to the node. */
+/* Return true when there are references to the node. INCLUDE_SELF is
+ true if a self reference counts as a reference. */
bool
-symtab_node::referred_to_p (void)
+symtab_node::referred_to_p (bool include_self)
{
ipa_ref *ref = NULL;
/* For functions check also calls. */
cgraph_node *cn = dyn_cast <cgraph_node *> (this);
if (cn && cn->callers)
- return true;
+ {
+ if (include_self)
+ return true;
+ for (cgraph_edge *e = cn->callers; e; e = e->next_caller)
+ if (e->caller != this)
+ return true;
+ }
return false;
}
node->local.redefined_extern_inline = true;
}
- notice_global_symbol (decl);
+ /* Set definition first before calling notice_global_symbol so that
+ it is available to notice_global_symbol. */
node->definition = true;
+ notice_global_symbol (decl);
node->lowered = DECL_STRUCT_FUNCTION (decl)->cfg != NULL;
/* With -fkeep-inline-functions we are keeping all inline functions except
declared inline and nested functions. These were optimized out
in the original implementation and it is unclear whether we want
to change the behavior here. */
- if ((!optimize
+ if ((!opt_for_fn (decl, optimize)
&& !node->cpp_implicit_alias
&& !DECL_DISREGARD_INLINE_LIMITS (decl)
&& !DECL_DECLARED_INLINE_P (decl)
if (!TREE_ASM_WRITTEN (decl))
(*debug_hooks->deferred_inline_function) (decl);
- /* Possibly warn about unused parameters. */
- if (warn_unused_parameter)
- do_warn_unused_parameter (decl);
-
if (!no_collect)
ggc_collect ();
{
gcc::pass_manager *passes = g->get_passes ();
cgraph_node *node;
+
+ if (dump_file)
+ {
+ struct function *fn = DECL_STRUCT_FUNCTION (fndecl);
+ const char *function_type = ((gimple_has_body_p (fndecl))
+ ? (lowered
+ ? (gimple_in_ssa_p (fn)
+ ? "ssa gimple"
+ : "low gimple")
+ : "high gimple")
+ : "to-be-gimplified");
+ fprintf (dump_file,
+ "Added new %s function %s to callgraph\n",
+ function_type,
+ fndecl_name (fndecl));
+ }
+
switch (symtab->state)
{
case PARSING:
case IPA:
case IPA_SSA:
+ case IPA_SSA_AFTER_INLINING:
case EXPANSION:
/* Bring the function into finalized state and enqueue for later
analyzing and compilation. */
if (thunk.thunk_p)
{
- create_edge (cgraph_node::get (thunk.alias),
- NULL, 0, CGRAPH_FREQ_BASE);
+ cgraph_node *t = cgraph_node::get (thunk.alias);
+
+ create_edge (t, NULL, 0, CGRAPH_FREQ_BASE);
+ /* Target code in expand_thunk may need the thunk's target
+ to be analyzed, so recurse here. */
+ if (!t->analyzed)
+ t->analyze ();
+ if (t->alias)
+ {
+ t = t->get_alias_target ();
+ if (!t->analyzed)
+ t->analyze ();
+ }
if (!expand_thunk (false, false))
{
thunk.alias = NULL;
body. */
if (!gimple_has_body_p (decl))
gimplify_function_tree (decl);
- dump_function (TDI_generic, decl);
/* Lower the function. */
if (!lowered)
if (node->definition)
return;
- notice_global_symbol (decl);
+ /* Set definition first before calling notice_global_symbol so that
+ it is available to notice_global_symbol. */
node->definition = true;
+ notice_global_symbol (decl);
if (TREE_THIS_VOLATILE (decl) || DECL_PRESERVE_P (decl)
/* Traditionally we do not eliminate static variables when not
optimizing and when not doing toplevel reoder. */
|| (!flag_toplevel_reorder
&& symtab->state == EXPANSION))
node->assemble_decl ();
+
+ if (DECL_INITIAL (decl))
+ chkp_register_var_initializer (decl);
}
/* EDGE is an polymorphic call. Mark all possible targets as reachable
(TREE_TYPE (targets[i]->decl))
== METHOD_TYPE
&& !type_in_anonymous_namespace_p
- (method_class_type
- (TREE_TYPE (targets[i]->decl))))
- enqueue_node (targets[i]);
+ (TYPE_METHOD_BASETYPE (TREE_TYPE (targets[i]->decl))))
+ enqueue_node (targets[i]);
}
}
edge->make_direct (target);
edge->redirect_call_stmt_to_callee ();
+
+ /* Call to __builtin_unreachable shouldn't be instrumented. */
+ if (!targets.length ())
+ gimple_call_set_with_bounds (edge->call_stmt, false);
+
if (symtab->dump_file)
{
fprintf (symtab->dump_file,
static cgraph_node *first_analyzed;
static varpool_node *first_analyzed_var;
+/* FIRST_TIME is set to TRUE for the first time we are called for a
+ translation unit from finalize_compilation_unit() or false
+ otherwise. */
+
static void
-analyze_functions (void)
+analyze_functions (bool first_time)
{
/* Keep track of already processed nodes when called multiple times for
intermodule optimization. */
FOR_EACH_SYMBOL (node)
if (node->cpp_implicit_alias)
node->fixup_same_cpp_alias_visibility (node->get_alias_target ());
- if (optimize && flag_devirtualize)
- build_type_inheritance_graph ();
+ build_type_inheritance_graph ();
/* Analysis adds static variables that in turn adds references to new functions.
So we need to iterate the process until it stabilize. */
cnode->analyze ();
for (edge = cnode->callees; edge; edge = edge->next_callee)
- if (edge->callee->definition)
+ if (edge->callee->definition
+ && (!DECL_EXTERNAL (edge->callee->decl)
+ /* When not optimizing, do not try to analyze extern
+ inline functions. Doing so is pointless. */
+ || opt_for_fn (edge->callee->decl, optimize)
+ /* Weakrefs needs to be preserved. */
+ || edge->callee->alias
+ /* always_inline functions are inlined aven at -O0. */
+ || lookup_attribute
+ ("always_inline",
+ DECL_ATTRIBUTES (edge->callee->decl))
+ /* Multiversioned functions needs the dispatcher to
+ be produced locally even for extern functions. */
+ || edge->callee->function_version ()))
enqueue_node (edge->callee);
- if (optimize && flag_devirtualize)
+ if (opt_for_fn (cnode->decl, optimize)
+ && opt_for_fn (cnode->decl, flag_devirtualize))
{
cgraph_edge *next;
for (next = node->same_comdat_group;
next != node;
next = next->same_comdat_group)
- enqueue_node (next);
+ if (!next->comdat_local_p ())
+ enqueue_node (next);
}
for (i = 0; node->iterate_reference (i, ref); i++)
- if (ref->referred->definition)
+ if (ref->referred->definition
+ && (!DECL_EXTERNAL (ref->referred->decl)
+ || ((TREE_CODE (ref->referred->decl) != FUNCTION_DECL
+ && optimize)
+ || (TREE_CODE (ref->referred->decl) == FUNCTION_DECL
+ && opt_for_fn (ref->referred->decl, optimize))
+ || node->alias
+ || ref->referred->alias)))
enqueue_node (ref->referred);
symtab->process_new_functions ();
}
}
- if (optimize && flag_devirtualize)
- update_type_inheritance_graph ();
+ update_type_inheritance_graph ();
/* Collect entry points to the unit. */
if (symtab->dump_file)
symtab_node::dump_table (symtab->dump_file);
}
+ if (first_time)
+ {
+ symtab_node *snode;
+ FOR_EACH_SYMBOL (snode)
+ check_global_declaration (snode->decl);
+ }
+
if (symtab->dump_file)
fprintf (symtab->dump_file, "\nRemoving unused symbols:");
{
if (symtab->dump_file)
fprintf (symtab->dump_file, " %s", node->name ());
+
+ /* See if the debugger can use anything before the DECL
+ passes away. Perhaps it can notice a DECL that is now a
+ constant and can tag the early DIE with an appropriate
+ attribute.
+
+ Otherwise, this is the last chance the debug_hooks have
+ at looking at optimized away DECLs, since
+ late_global_decl will subsequently be called from the
+ contents of the now pruned symbol table. */
+ if (!decl_function_context (node->decl))
+ (*debug_hooks->late_global_decl) (node->decl);
+
node->remove ();
continue;
}
return basic block in the function body. */
basic_block
-init_lowered_empty_function (tree decl, bool in_ssa)
+init_lowered_empty_function (tree decl, bool in_ssa, gcov_type count)
{
basic_block bb;
+ edge e;
current_function_decl = decl;
allocate_struct_function (decl, false);
loops_for_fn (cfun)->state |= LOOPS_MAY_HAVE_MULTIPLE_LATCHES;
/* Create BB for body of the function and connect it properly. */
- bb = create_basic_block (NULL, (void *) 0, ENTRY_BLOCK_PTR_FOR_FN (cfun));
- make_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun), bb, EDGE_FALLTHRU);
- make_edge (bb, EXIT_BLOCK_PTR_FOR_FN (cfun), 0);
+ ENTRY_BLOCK_PTR_FOR_FN (cfun)->count = count;
+ ENTRY_BLOCK_PTR_FOR_FN (cfun)->frequency = REG_BR_PROB_BASE;
+ EXIT_BLOCK_PTR_FOR_FN (cfun)->count = count;
+ EXIT_BLOCK_PTR_FOR_FN (cfun)->frequency = REG_BR_PROB_BASE;
+ bb = create_basic_block (NULL, ENTRY_BLOCK_PTR_FOR_FN (cfun));
+ bb->count = count;
+ bb->frequency = BB_FREQ_MAX;
+ e = make_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun), bb, EDGE_FALLTHRU);
+ e->count = count;
+ e->probability = REG_BR_PROB_BASE;
+ e = make_edge (bb, EXIT_BLOCK_PTR_FOR_FN (cfun), 0);
+ e->count = count;
+ e->probability = REG_BR_PROB_BASE;
add_bb_to_loop (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun)->loop_father);
return bb;
tree ptr, bool this_adjusting,
HOST_WIDE_INT fixed_offset, tree virtual_offset)
{
- gimple stmt;
+ gassign *stmt;
tree ret;
if (this_adjusting
tree thunk_fndecl = decl;
tree a;
+ /* Instrumentation thunk is the same function with
+ a different signature. Never need to expand it. */
+ if (thunk.add_pointer_bounds_args)
+ return false;
if (!force_gimple_thunk && this_adjusting
&& targetm.asm_out.can_output_mi_thunk (thunk_fndecl, fixed_offset,
}
if (in_lto_p)
- get_body ();
+ get_untransformed_body ();
a = DECL_ARGUMENTS (thunk_fndecl);
current_function_decl = thunk_fndecl;
/* Ensure thunks are emitted in their correct sections. */
- resolve_unique_section (thunk_fndecl, 0, flag_function_sections);
+ resolve_unique_section (thunk_fndecl, 0,
+ flag_function_sections);
DECL_RESULT (thunk_fndecl)
= build_decl (DECL_SOURCE_LOCATION (thunk_fndecl),
thunk.thunk_p = false;
analyzed = false;
}
+ else if (stdarg_p (TREE_TYPE (thunk_fndecl)))
+ {
+ error ("generic thunk code fails for method %qD which uses %<...%>",
+ thunk_fndecl);
+ TREE_ASM_WRITTEN (thunk_fndecl) = 1;
+ analyzed = true;
+ return false;
+ }
else
{
tree restype;
int i;
tree resdecl;
tree restmp = NULL;
+ tree resbnd = NULL;
- gimple call;
- gimple ret;
+ gcall *call;
+ greturn *ret;
+ bool alias_is_noreturn = TREE_THIS_VOLATILE (alias);
if (in_lto_p)
- get_body ();
+ get_untransformed_body ();
a = DECL_ARGUMENTS (thunk_fndecl);
current_function_decl = thunk_fndecl;
/* Ensure thunks are emitted in their correct sections. */
- resolve_unique_section (thunk_fndecl, 0, flag_function_sections);
+ resolve_unique_section (thunk_fndecl, 0,
+ flag_function_sections);
DECL_IGNORED_P (thunk_fndecl) = 1;
bitmap_obstack_initialize (NULL);
else
resdecl = DECL_RESULT (thunk_fndecl);
- bb = then_bb = else_bb = return_bb = init_lowered_empty_function (thunk_fndecl, true);
+ bb = then_bb = else_bb = return_bb
+ = init_lowered_empty_function (thunk_fndecl, true, count);
bsi = gsi_start_bb (bb);
/* Build call to the function being thunked. */
- if (!VOID_TYPE_P (restype))
+ if (!VOID_TYPE_P (restype) && !alias_is_noreturn)
{
if (DECL_BY_REFERENCE (resdecl))
- restmp = gimple_fold_indirect_ref (resdecl);
+ {
+ restmp = gimple_fold_indirect_ref (resdecl);
+ if (!restmp)
+ restmp = build2 (MEM_REF,
+ TREE_TYPE (TREE_TYPE (DECL_RESULT (alias))),
+ resdecl,
+ build_int_cst (TREE_TYPE
+ (DECL_RESULT (alias)), 0));
+ }
else if (!is_gimple_reg_type (restype))
{
- restmp = resdecl;
- add_local_decl (cfun, restmp);
- BLOCK_VARS (DECL_INITIAL (current_function_decl)) = restmp;
+ if (aggregate_value_p (resdecl, TREE_TYPE (thunk_fndecl)))
+ {
+ restmp = resdecl;
+
+ if (TREE_CODE (restmp) == VAR_DECL)
+ add_local_decl (cfun, restmp);
+ BLOCK_VARS (DECL_INITIAL (current_function_decl)) = restmp;
+ }
+ else
+ restmp = create_tmp_var (restype, "retval");
}
else
restmp = create_tmp_reg (restype, "retval");
for (arg = a; arg; arg = DECL_CHAIN (arg))
nargs++;
auto_vec<tree> vargs (nargs);
+ i = 0;
+ arg = a;
if (this_adjusting)
- vargs.quick_push (thunk_adjust (&bsi, a, 1, fixed_offset,
- virtual_offset));
- else if (nargs)
- vargs.quick_push (a);
+ {
+ vargs.quick_push (thunk_adjust (&bsi, a, 1, fixed_offset,
+ virtual_offset));
+ arg = DECL_CHAIN (a);
+ i = 1;
+ }
if (nargs)
- for (i = 1, arg = DECL_CHAIN (a); i < nargs; i++, arg = DECL_CHAIN (arg))
+ for (; i < nargs; i++, arg = DECL_CHAIN (arg))
{
tree tmp = arg;
if (!is_gimple_val (arg))
call = gimple_build_call_vec (build_fold_addr_expr_loc (0, alias), vargs);
callees->call_stmt = call;
gimple_call_set_from_thunk (call, true);
- if (restmp)
+ gimple_call_set_with_bounds (call, instrumentation_clone);
+
+ /* Return slot optimization is always possible and in fact requred to
+ return values with DECL_BY_REFERENCE. */
+ if (aggregate_value_p (resdecl, TREE_TYPE (thunk_fndecl))
+ && (!is_gimple_reg_type (TREE_TYPE (resdecl))
+ || DECL_BY_REFERENCE (resdecl)))
+ gimple_call_set_return_slot_opt (call, true);
+
+ if (restmp && !alias_is_noreturn)
{
gimple_call_set_lhs (call, restmp);
gcc_assert (useless_type_conversion_p (TREE_TYPE (restmp),
TREE_TYPE (TREE_TYPE (alias))));
}
gsi_insert_after (&bsi, call, GSI_NEW_STMT);
- if (!(gimple_call_flags (call) & ECF_NORETURN))
+ if (!alias_is_noreturn)
{
+ if (instrumentation_clone
+ && !DECL_BY_REFERENCE (resdecl)
+ && restmp
+ && BOUNDED_P (restmp))
+ {
+ resbnd = chkp_insert_retbnd_call (NULL, restmp, &bsi);
+ create_edge (get_create (gimple_call_fndecl (gsi_stmt (bsi))),
+ as_a <gcall *> (gsi_stmt (bsi)),
+ callees->count, callees->frequency);
+ }
+
if (restmp && !this_adjusting
&& (fixed_offset || virtual_offset))
{
if (TREE_CODE (TREE_TYPE (restmp)) == POINTER_TYPE)
{
gimple stmt;
+ edge e;
/* If the return type is a pointer, we need to
protect against NULL. We know there will be an
adjustment, because that's why we're emitting a
thunk. */
- then_bb = create_basic_block (NULL, (void *) 0, bb);
- return_bb = create_basic_block (NULL, (void *) 0, then_bb);
- else_bb = create_basic_block (NULL, (void *) 0, else_bb);
+ then_bb = create_basic_block (NULL, bb);
+ then_bb->count = count - count / 16;
+ then_bb->frequency = BB_FREQ_MAX - BB_FREQ_MAX / 16;
+ return_bb = create_basic_block (NULL, then_bb);
+ return_bb->count = count;
+ return_bb->frequency = BB_FREQ_MAX;
+ else_bb = create_basic_block (NULL, else_bb);
+ then_bb->count = count / 16;
+ then_bb->frequency = BB_FREQ_MAX / 16;
add_bb_to_loop (then_bb, bb->loop_father);
add_bb_to_loop (return_bb, bb->loop_father);
add_bb_to_loop (else_bb, bb->loop_father);
build_zero_cst (TREE_TYPE (restmp)),
NULL_TREE, NULL_TREE);
gsi_insert_after (&bsi, stmt, GSI_NEW_STMT);
- make_edge (bb, then_bb, EDGE_TRUE_VALUE);
- make_edge (bb, else_bb, EDGE_FALSE_VALUE);
- make_edge (return_bb, EXIT_BLOCK_PTR_FOR_FN (cfun), 0);
- make_edge (then_bb, return_bb, EDGE_FALLTHRU);
- make_edge (else_bb, return_bb, EDGE_FALLTHRU);
+ e = make_edge (bb, then_bb, EDGE_TRUE_VALUE);
+ e->probability = REG_BR_PROB_BASE - REG_BR_PROB_BASE / 16;
+ e->count = count - count / 16;
+ e = make_edge (bb, else_bb, EDGE_FALSE_VALUE);
+ e->probability = REG_BR_PROB_BASE / 16;
+ e->count = count / 16;
+ e = make_edge (return_bb, EXIT_BLOCK_PTR_FOR_FN (cfun), 0);
+ e->probability = REG_BR_PROB_BASE;
+ e->count = count;
+ e = make_edge (then_bb, return_bb, EDGE_FALLTHRU);
+ e->probability = REG_BR_PROB_BASE;
+ e->count = count - count / 16;
+ e = make_edge (else_bb, return_bb, EDGE_FALLTHRU);
+ e->probability = REG_BR_PROB_BASE;
+ e->count = count / 16;
bsi = gsi_last_bb (then_bb);
}
gimple_call_set_tail (call, true);
/* Build return value. */
- ret = gimple_build_return (restmp);
+ if (!DECL_BY_REFERENCE (resdecl))
+ ret = gimple_build_return (restmp);
+ else
+ ret = gimple_build_return (resdecl);
+ gimple_return_set_retbnd (ret, resbnd);
+
gsi_insert_after (&bsi, ret, GSI_NEW_STMT);
}
else
}
cfun->gimple_df->in_ssa_p = true;
+ profile_status_for_fn (cfun)
+ = count ? PROFILE_READ : PROFILE_GUESSED;
/* FIXME: C++ FE should stop setting TREE_ASM_WRITTEN on thunks. */
TREE_ASM_WRITTEN (thunk_fndecl) = false;
delete_unreachable_blocks ();
ipa_ref *ref;
for (e = callers; e;)
- if (e->caller->thunk.thunk_p)
+ if (e->caller->thunk.thunk_p
+ && !e->caller->thunk.add_pointer_bounds_args)
{
cgraph_node *thunk = e->caller;
announce_function (decl);
process = 0;
gcc_assert (lowered);
- get_body ();
+ get_untransformed_body ();
/* Generate RTL for the body of DECL. */
if (node->process)
{
- expanded_func_count++;
- if(node->tp_first_run)
- profiled_func_count++;
-
- if (symtab->dump_file)
- fprintf (symtab->dump_file,
- "Time profile order in expand_all_functions:%s:%d\n",
- node->asm_name (), node->tp_first_run);
+ expanded_func_count++;
+ if(node->tp_first_run)
+ profiled_func_count++;
+
+ if (symtab->dump_file)
+ fprintf (symtab->dump_file,
+ "Time profile order in expand_all_functions:%s:%d\n",
+ node->asm_name (), node->tp_first_run);
node->process = 0;
node->expand ();
}
/* This extra symtab_remove_unreachable_nodes pass tends to catch some
devirtualization and other changes where removal iterate. */
- symtab->remove_unreachable_nodes (true, symtab->dump_file);
+ symtab->remove_unreachable_nodes (symtab->dump_file);
/* If pass_all_early_optimizations was not scheduled, the state of
the cgraph will not be properly updated. Update it now. */
}
/* Some targets need to handle LTO assembler output specially. */
- if (flag_generate_lto)
+ if (flag_generate_lto || flag_generate_offload)
targetm.asm_out.lto_start ();
if (!in_lto_p)
- ipa_write_summaries ();
+ {
+ if (g->have_offload)
+ {
+ section_name_prefix = OFFLOAD_SECTION_NAME_PREFIX;
+ lto_stream_offload_p = true;
+ ipa_write_summaries ();
+ lto_stream_offload_p = false;
+ }
+ if (flag_lto)
+ {
+ section_name_prefix = LTO_SECTION_NAME_PREFIX;
+ lto_stream_offload_p = false;
+ ipa_write_summaries ();
+ }
+ }
- if (flag_generate_lto)
+ if (flag_generate_lto || flag_generate_offload)
targetm.asm_out.lto_end ();
if (!flag_ltrans && (in_lto_p || !flag_lto || flag_fat_lto_objects))
symbol_table::output_weakrefs (void)
{
symtab_node *node;
+ cgraph_node *cnode;
FOR_EACH_SYMBOL (node)
if (node->alias
&& !TREE_ASM_WRITTEN (node->decl)
+ && (!(cnode = dyn_cast <cgraph_node *> (node))
+ || !cnode->instrumented_version
+ || !TREE_ASM_WRITTEN (cnode->instrumented_version->decl))
&& node->weakref)
{
tree target;
fprintf (stderr, "Performing interprocedural optimizations\n");
state = IPA;
+ /* Offloading requires LTO infrastructure. */
+ if (!in_lto_p && g->have_offload)
+ flag_generate_offload = 1;
+
/* If LTO is enabled, initialize the streamer hooks needed by GIMPLE. */
- if (flag_lto)
+ if (flag_generate_lto || flag_generate_offload)
lto_streamer_hooks_init ();
/* Don't run the IPA passes if there was any error or sorry messages. */
return;
}
- /* This pass remove bodies of extern inline functions we never inlined.
- Do this later so other IPA passes see what is really going on.
- FIXME: This should be run just after inlining by pasmanager. */
- remove_unreachable_nodes (false, dump_file);
global_info_ready = true;
if (dump_file)
{
/* Gimplify and lower all functions, compute reachability and
remove unreachable nodes. */
- analyze_functions ();
+ analyze_functions (/*first_time=*/true);
/* Mark alias targets necessary and emit diagnostics. */
handle_alias_pairs ();
/* Gimplify and lower thunks. */
- analyze_functions ();
+ analyze_functions (/*first_time=*/false);
+
+ /* Emit early debug for reachable functions, and by consequence,
+ locally scoped symbols. */
+ struct cgraph_node *cnode;
+ FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (cnode)
+ (*debug_hooks->early_global_decl) (cnode->decl);
+
+ /* Clean up anything that needs cleaning up after initial debug
+ generation. */
+ (*debug_hooks->early_finish) ();
/* Finally drive the pass manager. */
compile ();
void
cgraph_node::create_wrapper (cgraph_node *target)
{
- /* Preserve DECL_RESULT so we get right by reference flag. */
- tree decl_result = DECL_RESULT (decl);
+ /* Preserve DECL_RESULT so we get right by reference flag. */
+ tree decl_result = DECL_RESULT (decl);
+
+ /* Remove the function's body but keep arguments to be reused
+ for thunk. */
+ release_body (true);
+ reset ();
- /* Remove the function's body but keep arguments to be reused
- for thunk. */
- release_body (true);
- reset ();
+ DECL_UNINLINABLE (decl) = false;
+ DECL_RESULT (decl) = decl_result;
+ DECL_INITIAL (decl) = NULL;
+ allocate_struct_function (decl, false);
+ set_cfun (NULL);
- DECL_RESULT (decl) = decl_result;
- DECL_INITIAL (decl) = NULL;
- allocate_struct_function (decl, false);
- set_cfun (NULL);
+ /* Turn alias into thunk and expand it into GIMPLE representation. */
+ definition = true;
- /* Turn alias into thunk and expand it into GIMPLE representation. */
- definition = true;
- thunk.thunk_p = true;
- thunk.this_adjusting = false;
+ memset (&thunk, 0, sizeof (cgraph_thunk_info));
+ thunk.thunk_p = true;
+ create_edge (target, NULL, count, CGRAPH_FREQ_BASE);
- cgraph_edge *e = create_edge (target, NULL, 0, CGRAPH_FREQ_BASE);
+ tree arguments = DECL_ARGUMENTS (decl);
+
+ while (arguments)
+ {
+ TREE_ADDRESSABLE (arguments) = false;
+ arguments = TREE_CHAIN (arguments);
+ }
- expand_thunk (false, true);
- e->call_stmt_cannot_inline_p = true;
+ expand_thunk (false, true);
- /* Inline summary set-up. */
- analyze ();
- inline_analyze_function (this);
+ /* Inline summary set-up. */
+ analyze ();
+ inline_analyze_function (this);
}
#include "gt-cgraphunit.h"