#include "system.h"
#include "coretypes.h"
#include "tm.h"
-#include "hash-set.h"
-#include "machmode.h"
-#include "vec.h"
-#include "double-int.h"
-#include "input.h"
#include "alias.h"
#include "symtab.h"
-#include "wide-int.h"
-#include "inchash.h"
#include "tree.h"
#include "fold-const.h"
#include "varasm.h"
#include "rtl.h"
#include "predict.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 "diagnostic.h"
#include "params.h"
#include "intl.h"
-#include "hash-map.h"
-#include "plugin-api.h"
-#include "ipa-ref.h"
#include "cgraph.h"
#include "alloc-pool.h"
#include "symbol-summary.h"
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;
}
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:
body. */
if (!gimple_has_body_p (decl))
gimplify_function_tree (decl);
- dump_function (TDI_generic, decl);
/* Lower the function. */
if (!lowered)
(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]);
}
}
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. */
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;
}
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, (void *) 0, ENTRY_BLOCK_PTR_FOR_FN (cfun));
+ 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);
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,
int i;
tree resdecl;
tree restmp = NULL;
+ tree resbnd = NULL;
gcall *call;
greturn *ret;
gsi_insert_after (&bsi, call, GSI_NEW_STMT);
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))
{
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);
+ 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, (void *) 0, then_bb);
+ return_bb = create_basic_block (NULL, then_bb);
return_bb->count = count;
return_bb->frequency = BB_FREQ_MAX;
- else_bb = create_basic_block (NULL, (void *) 0, else_bb);
+ 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);
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);
}
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 ();
}
/* 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 ();
/* Turn alias into thunk and expand it into GIMPLE representation. */
definition = true;
+
+ memset (&thunk, 0, sizeof (cgraph_thunk_info));
thunk.thunk_p = true;
- thunk.this_adjusting = false;
create_edge (target, NULL, count, CGRAPH_FREQ_BASE);
tree arguments = DECL_ARGUMENTS (decl);