mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-18 23:31:22 +08:00
cgraphbuild.c (build_cgraph_edges, [...]): Build indrect edges too.
* cgraphbuild.c (build_cgraph_edges, rebuild_cgraph_edges): Build indrect edges too. * cgraph.c (cgraph_create_indirect_edge): Take ecf_flags argument. (cgraph_clone_edge): Update. (cgraph_node_remove_callees): Remove indirect calls too. * cgraph.h (cgraph_indirect_call_info): Add ecf_flags. (cgraph_create_indirect_edge): Update prototype. * ipa-reference.c (has_proper_scope_for_analysis): Rename to is_proper_for_analysis. (add_new_function, visited_nodes, function_insertion_hook_holder, get_local_reference_vars_info, mark_address_taken, mark_address, mark_load, mark_store, check_asm_memory_clobber, check_call, scan_stmt_for_static_refs, scan_initializer_for_static_refs): Remove. (ipa_init): Do not initialize visited_nodes; function_insertion_hook_holder. (analyze_variable): Rewrite. (analyze_function): Rewrite. (copy_local_bitmap): Remove. (duplicate_node_dat): Do not duplicate local info. (generate_summary): Simplify to only walk cgraph. (write_node_summary_p, ipa_reference_write_summary, ipa_reference_read_summary): Remove. (propagate): Do not remove function insertion; generate summary. (pass_ipa_reference): NULLify summary handling fields. * lto-cgraph.c (lto_output_edge): Output ecf_flags. (input_edge): Input ecf_flags. * ipa-prop.c (ipa_note_parm_call): Expect edge to be around. (update_indirect_edges_after_inlining): Ignore edges with unknown param. From-SVN: r159343
This commit is contained in:
parent
87a0ebfd20
commit
5f902d766c
@ -1,3 +1,36 @@
|
||||
2010-05-12 Jan Hubicka <jh@suse.cz>
|
||||
|
||||
* cgraphbuild.c (build_cgraph_edges, rebuild_cgraph_edges): Build
|
||||
indrect edges too.
|
||||
* cgraph.c (cgraph_create_indirect_edge): Take ecf_flags argument.
|
||||
(cgraph_clone_edge): Update.
|
||||
(cgraph_node_remove_callees): Remove indirect calls too.
|
||||
* cgraph.h (cgraph_indirect_call_info): Add ecf_flags.
|
||||
(cgraph_create_indirect_edge): Update prototype.
|
||||
* ipa-reference.c (has_proper_scope_for_analysis): Rename to
|
||||
is_proper_for_analysis.
|
||||
(add_new_function, visited_nodes, function_insertion_hook_holder,
|
||||
get_local_reference_vars_info, mark_address_taken, mark_address,
|
||||
mark_load, mark_store, check_asm_memory_clobber, check_call,
|
||||
scan_stmt_for_static_refs, scan_initializer_for_static_refs): Remove.
|
||||
(ipa_init): Do not initialize visited_nodes;
|
||||
function_insertion_hook_holder.
|
||||
(analyze_variable): Rewrite.
|
||||
(analyze_function): Rewrite.
|
||||
(copy_local_bitmap): Remove.
|
||||
(duplicate_node_dat): Do not duplicate local info.
|
||||
(generate_summary): Simplify to only walk cgraph.
|
||||
(write_node_summary_p, ipa_reference_write_summary,
|
||||
ipa_reference_read_summary): Remove.
|
||||
(propagate): Do not remove function insertion;
|
||||
generate summary.
|
||||
(pass_ipa_reference): NULLify summary handling fields.
|
||||
* lto-cgraph.c (lto_output_edge): Output ecf_flags.
|
||||
(input_edge): Input ecf_flags.
|
||||
* ipa-prop.c (ipa_note_parm_call): Expect edge to be around.
|
||||
(update_indirect_edges_after_inlining): Ignore edges with unknown
|
||||
param.
|
||||
|
||||
2010-05-12 Sriraman Tallam <tmsriram@google.com>
|
||||
|
||||
* implicit-zee.c: New file.
|
||||
|
15
gcc/cgraph.c
15
gcc/cgraph.c
@ -1036,6 +1036,7 @@ cgraph_create_edge (struct cgraph_node *caller, struct cgraph_node *callee,
|
||||
|
||||
struct cgraph_edge *
|
||||
cgraph_create_indirect_edge (struct cgraph_node *caller, gimple call_stmt,
|
||||
int ecf_flags,
|
||||
gcov_type count, int freq, int nest)
|
||||
{
|
||||
struct cgraph_edge *edge = cgraph_create_edge_1 (caller, NULL, call_stmt,
|
||||
@ -1046,6 +1047,7 @@ cgraph_create_indirect_edge (struct cgraph_node *caller, gimple call_stmt,
|
||||
|
||||
edge->indirect_info = GGC_NEW (struct cgraph_indirect_call_info);
|
||||
edge->indirect_info->param_index = -1;
|
||||
edge->indirect_info->ecf_flags = ecf_flags;
|
||||
|
||||
edge->next_callee = caller->indirect_calls;
|
||||
if (caller->indirect_calls)
|
||||
@ -1292,6 +1294,15 @@ cgraph_node_remove_callees (struct cgraph_node *node)
|
||||
cgraph_edge_remove_callee (e);
|
||||
cgraph_free_edge (e);
|
||||
}
|
||||
for (e = node->indirect_calls; e; e = f)
|
||||
{
|
||||
f = e->next_callee;
|
||||
cgraph_call_edge_removal_hooks (e);
|
||||
if (!e->indirect_unknown_callee)
|
||||
cgraph_edge_remove_callee (e);
|
||||
cgraph_free_edge (e);
|
||||
}
|
||||
node->indirect_calls = NULL;
|
||||
node->callees = NULL;
|
||||
if (node->call_site_hash)
|
||||
{
|
||||
@ -2009,7 +2020,9 @@ cgraph_clone_edge (struct cgraph_edge *e, struct cgraph_node *n,
|
||||
}
|
||||
else
|
||||
{
|
||||
new_edge = cgraph_create_indirect_edge (n, call_stmt, count, freq,
|
||||
new_edge = cgraph_create_indirect_edge (n, call_stmt,
|
||||
e->indirect_info->ecf_flags,
|
||||
count, freq,
|
||||
e->loop_nest + loop_nest);
|
||||
new_edge->indirect_info->param_index = e->indirect_info->param_index;
|
||||
}
|
||||
|
@ -376,6 +376,8 @@ struct GTY(()) cgraph_indirect_call_info
|
||||
{
|
||||
/* Index of the parameter that is called. */
|
||||
int param_index;
|
||||
/* ECF flags determined from the caller. */
|
||||
int ecf_flags;
|
||||
};
|
||||
|
||||
struct GTY((chain_next ("%h.next_caller"), chain_prev ("%h.prev_caller"))) cgraph_edge {
|
||||
@ -519,7 +521,7 @@ void cgraph_node_remove_callees (struct cgraph_node *node);
|
||||
struct cgraph_edge *cgraph_create_edge (struct cgraph_node *,
|
||||
struct cgraph_node *,
|
||||
gimple, gcov_type, int, int);
|
||||
struct cgraph_edge *cgraph_create_indirect_edge (struct cgraph_node *, gimple,
|
||||
struct cgraph_edge *cgraph_create_indirect_edge (struct cgraph_node *, gimple, int,
|
||||
gcov_type, int, int);
|
||||
struct cgraph_node * cgraph_get_node (tree);
|
||||
struct cgraph_node *cgraph_node (tree);
|
||||
|
@ -339,12 +339,21 @@ build_cgraph_edges (void)
|
||||
gimple stmt = gsi_stmt (gsi);
|
||||
tree decl;
|
||||
|
||||
if (is_gimple_call (stmt) && (decl = gimple_call_fndecl (stmt)))
|
||||
cgraph_create_edge (node, cgraph_node (decl), stmt,
|
||||
bb->count,
|
||||
compute_call_stmt_bb_frequency
|
||||
(current_function_decl, bb),
|
||||
bb->loop_depth);
|
||||
if (is_gimple_call (stmt))
|
||||
{
|
||||
int freq = compute_call_stmt_bb_frequency (current_function_decl,
|
||||
bb);
|
||||
decl = gimple_call_fndecl (stmt);
|
||||
if (decl)
|
||||
cgraph_create_edge (node, cgraph_node (decl), stmt,
|
||||
bb->count, freq,
|
||||
bb->loop_depth);
|
||||
else
|
||||
cgraph_create_indirect_edge (node, stmt,
|
||||
gimple_call_flags (stmt),
|
||||
bb->count, freq,
|
||||
bb->loop_depth);
|
||||
}
|
||||
walk_stmt_load_store_addr_ops (stmt, node, mark_load,
|
||||
mark_store, mark_address);
|
||||
if (gimple_code (stmt) == GIMPLE_OMP_PARALLEL
|
||||
@ -443,12 +452,21 @@ rebuild_cgraph_edges (void)
|
||||
gimple stmt = gsi_stmt (gsi);
|
||||
tree decl;
|
||||
|
||||
if (is_gimple_call (stmt) && (decl = gimple_call_fndecl (stmt)))
|
||||
cgraph_create_edge (node, cgraph_node (decl), stmt,
|
||||
bb->count,
|
||||
compute_call_stmt_bb_frequency
|
||||
(current_function_decl, bb),
|
||||
bb->loop_depth);
|
||||
if (is_gimple_call (stmt))
|
||||
{
|
||||
int freq = compute_call_stmt_bb_frequency (current_function_decl,
|
||||
bb);
|
||||
decl = gimple_call_fndecl (stmt);
|
||||
if (decl)
|
||||
cgraph_create_edge (node, cgraph_node (decl), stmt,
|
||||
bb->count, freq,
|
||||
bb->loop_depth);
|
||||
else
|
||||
cgraph_create_indirect_edge (node, stmt,
|
||||
gimple_call_flags (stmt),
|
||||
bb->count, freq,
|
||||
bb->loop_depth);
|
||||
}
|
||||
walk_stmt_load_store_addr_ops (stmt, node, mark_load,
|
||||
mark_store, mark_address);
|
||||
|
||||
|
@ -757,12 +757,8 @@ static void
|
||||
ipa_note_param_call (struct cgraph_node *node, int formal_id, gimple stmt)
|
||||
{
|
||||
struct cgraph_edge *cs;
|
||||
basic_block bb = gimple_bb (stmt);
|
||||
int freq;
|
||||
|
||||
freq = compute_call_stmt_bb_frequency (current_function_decl, bb);
|
||||
cs = cgraph_create_indirect_edge (node, stmt, bb->count, freq,
|
||||
bb->loop_depth);
|
||||
cs = cgraph_edge (node, stmt);
|
||||
cs->indirect_info->param_index = formal_id;
|
||||
}
|
||||
|
||||
@ -1071,7 +1067,8 @@ update_indirect_edges_after_inlining (struct cgraph_edge *cs,
|
||||
|
||||
/* If we ever use indirect edges for anything other than indirect
|
||||
inlining, we will need to skip those with negative param_indices. */
|
||||
gcc_assert (ici->param_index >= 0);
|
||||
if (ici->param_index == -1)
|
||||
continue;
|
||||
|
||||
/* We must check range due to calls with variable number of arguments: */
|
||||
if (ici->param_index >= ipa_get_cs_argument_count (top))
|
||||
|
@ -71,8 +71,6 @@ along with GCC; see the file COPYING3. If not see
|
||||
#include "langhooks.h"
|
||||
#include "lto-streamer.h"
|
||||
|
||||
static void add_new_function (struct cgraph_node *node,
|
||||
void *data ATTRIBUTE_UNUSED);
|
||||
static void remove_node_data (struct cgraph_node *node,
|
||||
void *data ATTRIBUTE_UNUSED);
|
||||
static void duplicate_node_data (struct cgraph_node *src,
|
||||
@ -147,8 +145,6 @@ static bitmap module_statics_written;
|
||||
memory. */
|
||||
static bitmap all_module_statics;
|
||||
|
||||
static struct pointer_set_t *visited_nodes;
|
||||
|
||||
/* Obstack holding bitmaps of local analysis (live from analysis to
|
||||
propagation) */
|
||||
static bitmap_obstack local_info_obstack;
|
||||
@ -156,7 +152,6 @@ static bitmap_obstack local_info_obstack;
|
||||
static bitmap_obstack global_info_obstack;
|
||||
|
||||
/* Holders of ipa cgraph hooks: */
|
||||
static struct cgraph_node_hook_list *function_insertion_hook_holder;
|
||||
static struct cgraph_2node_hook_list *node_duplication_hook_holder;
|
||||
static struct cgraph_node_hook_list *node_removal_hook_holder;
|
||||
|
||||
@ -194,20 +189,6 @@ set_reference_vars_info (struct cgraph_node *node, ipa_reference_vars_info_t inf
|
||||
VEC_replace (ipa_reference_vars_info_t, ipa_reference_vars_vector, node->uid, info);
|
||||
}
|
||||
|
||||
/* Get a bitmap that contains all of the locally referenced static
|
||||
variables for function FN. */
|
||||
static ipa_reference_local_vars_info_t
|
||||
get_local_reference_vars_info (struct cgraph_node *fn)
|
||||
{
|
||||
ipa_reference_vars_info_t info = get_reference_vars_info (fn);
|
||||
|
||||
if (info)
|
||||
return info->local;
|
||||
else
|
||||
/* This phase was not run. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get a bitmap that contains all of the globally referenced static
|
||||
variables for function FN. */
|
||||
|
||||
@ -303,7 +284,7 @@ add_static_var (tree var)
|
||||
perform compilation unit scope escape analysis. */
|
||||
|
||||
static inline bool
|
||||
has_proper_scope_for_analysis (tree t)
|
||||
is_proper_for_analysis (tree t)
|
||||
{
|
||||
/* If the variable has the "used" attribute, treat it as if it had a
|
||||
been touched by the devil. */
|
||||
@ -315,15 +296,6 @@ has_proper_scope_for_analysis (tree t)
|
||||
if (TREE_THIS_VOLATILE (t))
|
||||
return false;
|
||||
|
||||
/* Do not care about a local automatic that is not static. */
|
||||
if (!TREE_STATIC (t) && !DECL_EXTERNAL (t))
|
||||
return false;
|
||||
|
||||
/* FIXME: for LTO we should include PUBLIC vars too. This is bit difficult
|
||||
as summarie would need unsharing. */
|
||||
if (DECL_EXTERNAL (t) || TREE_PUBLIC (t))
|
||||
return false;
|
||||
|
||||
/* We cannot touch decls where the type needs constructing. */
|
||||
if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (t)))
|
||||
return false;
|
||||
@ -336,160 +308,6 @@ has_proper_scope_for_analysis (tree t)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Mark tree T as having address taken. */
|
||||
|
||||
static void
|
||||
mark_address_taken (tree x)
|
||||
{
|
||||
if (TREE_CODE (x) == VAR_DECL
|
||||
&& module_statics_escape && has_proper_scope_for_analysis (x))
|
||||
bitmap_set_bit (module_statics_escape, DECL_UID (x));
|
||||
}
|
||||
|
||||
/* Wrapper around mark_address_taken for the stmt walker. */
|
||||
|
||||
static bool
|
||||
mark_address (gimple stmt ATTRIBUTE_UNUSED, tree addr,
|
||||
void *data ATTRIBUTE_UNUSED)
|
||||
{
|
||||
addr = get_base_address (addr);
|
||||
if (addr)
|
||||
mark_address_taken (addr);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Mark load of T. */
|
||||
|
||||
static bool
|
||||
mark_load (gimple stmt ATTRIBUTE_UNUSED, tree t, void *data)
|
||||
{
|
||||
ipa_reference_local_vars_info_t local = (ipa_reference_local_vars_info_t)data;
|
||||
t = get_base_address (t);
|
||||
if (t && TREE_CODE (t) == VAR_DECL
|
||||
&& has_proper_scope_for_analysis (t))
|
||||
bitmap_set_bit (local->statics_read, DECL_UID (t));
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Mark store of T. */
|
||||
|
||||
static bool
|
||||
mark_store (gimple stmt ATTRIBUTE_UNUSED, tree t, void *data)
|
||||
{
|
||||
ipa_reference_local_vars_info_t local = (ipa_reference_local_vars_info_t)data;
|
||||
t = get_base_address (t);
|
||||
if (t && TREE_CODE (t) == VAR_DECL
|
||||
&& has_proper_scope_for_analysis (t))
|
||||
{
|
||||
if (local)
|
||||
bitmap_set_bit (local->statics_written, DECL_UID (t));
|
||||
/* Mark the write so we can tell which statics are
|
||||
readonly. */
|
||||
if (module_statics_written)
|
||||
bitmap_set_bit (module_statics_written, DECL_UID (t));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Look for memory clobber and set read_all/write_all if present. */
|
||||
|
||||
static void
|
||||
check_asm_memory_clobber (ipa_reference_local_vars_info_t local, gimple stmt)
|
||||
{
|
||||
size_t i;
|
||||
tree op;
|
||||
|
||||
for (i = 0; i < gimple_asm_nclobbers (stmt); i++)
|
||||
{
|
||||
op = gimple_asm_clobber_op (stmt, i);
|
||||
if (simple_cst_equal(TREE_VALUE (op), memory_identifier_string) == 1)
|
||||
{
|
||||
/* Abandon all hope, ye who enter here. */
|
||||
local->calls_read_all = true;
|
||||
local->calls_write_all = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Look for external calls and set read_all/write_all correspondingly. */
|
||||
|
||||
static void
|
||||
check_call (ipa_reference_local_vars_info_t local, gimple stmt)
|
||||
{
|
||||
int flags = gimple_call_flags (stmt);
|
||||
tree callee_t = gimple_call_fndecl (stmt);
|
||||
|
||||
/* Process indirect calls. All direct calles are handled at propagation
|
||||
time. */
|
||||
if (!callee_t)
|
||||
{
|
||||
if (flags & ECF_CONST)
|
||||
;
|
||||
else if (flags & ECF_PURE)
|
||||
local->calls_read_all = true;
|
||||
else
|
||||
{
|
||||
local->calls_read_all = true;
|
||||
/* When function does not reutrn, it is safe to ignore anythign it writes
|
||||
to, because the effect will never happen. */
|
||||
if ((flags & (ECF_NOTHROW | ECF_NORETURN))
|
||||
!= (ECF_NOTHROW | ECF_NORETURN))
|
||||
local->calls_write_all = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* TP is the part of the tree currently under the microscope.
|
||||
WALK_SUBTREES is part of the walk_tree api but is unused here.
|
||||
DATA is cgraph_node of the function being walked. */
|
||||
|
||||
static tree
|
||||
scan_stmt_for_static_refs (gimple_stmt_iterator *gsip,
|
||||
struct cgraph_node *fn)
|
||||
{
|
||||
gimple stmt = gsi_stmt (*gsip);
|
||||
ipa_reference_local_vars_info_t local = NULL;
|
||||
|
||||
if (is_gimple_debug (stmt))
|
||||
return NULL;
|
||||
|
||||
if (fn)
|
||||
local = get_reference_vars_info (fn)->local;
|
||||
|
||||
/* Look for direct loads and stores. */
|
||||
walk_stmt_load_store_addr_ops (stmt, local, mark_load, mark_store,
|
||||
mark_address);
|
||||
|
||||
if (is_gimple_call (stmt))
|
||||
check_call (local, stmt);
|
||||
else if (gimple_code (stmt) == GIMPLE_ASM)
|
||||
check_asm_memory_clobber (local, stmt);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Call-back to scan variable initializers for static references.
|
||||
Called using walk_tree. */
|
||||
|
||||
static tree
|
||||
scan_initializer_for_static_refs (tree *tp, int *walk_subtrees,
|
||||
void *data ATTRIBUTE_UNUSED)
|
||||
{
|
||||
tree t = *tp;
|
||||
|
||||
if (TREE_CODE (t) == ADDR_EXPR)
|
||||
{
|
||||
mark_address_taken (get_base_var (t));
|
||||
*walk_subtrees = 0;
|
||||
}
|
||||
/* Save some cycles by not walking types and declaration as we
|
||||
won't find anything useful there anyway. */
|
||||
else if (IS_TYPE_OR_DECL_P (*tp))
|
||||
*walk_subtrees = 0;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Lookup the tree node for the static variable that has UID. */
|
||||
static tree
|
||||
get_static_decl (int index)
|
||||
@ -604,14 +422,6 @@ ipa_init (void)
|
||||
module_statics_written = BITMAP_ALLOC (&local_info_obstack);
|
||||
all_module_statics = BITMAP_ALLOC (&global_info_obstack);
|
||||
|
||||
/* There are some shared nodes, in particular the initializers on
|
||||
static declarations. We do not need to scan them more than once
|
||||
since all we would be interested in are the addressof
|
||||
operations. */
|
||||
visited_nodes = pointer_set_create ();
|
||||
|
||||
function_insertion_hook_holder =
|
||||
cgraph_add_function_insertion_hook (&add_new_function, NULL);
|
||||
node_removal_hook_holder =
|
||||
cgraph_add_node_removal_hook (&remove_node_data, NULL);
|
||||
node_duplication_hook_holder =
|
||||
@ -627,13 +437,29 @@ ipa_init (void)
|
||||
static void
|
||||
analyze_variable (struct varpool_node *vnode)
|
||||
{
|
||||
struct walk_stmt_info wi;
|
||||
tree global = vnode->decl;
|
||||
|
||||
memset (&wi, 0, sizeof (wi));
|
||||
wi.pset = visited_nodes;
|
||||
walk_tree (&DECL_INITIAL (global), scan_initializer_for_static_refs,
|
||||
&wi, wi.pset);
|
||||
int i;
|
||||
struct ipa_ref *ref;
|
||||
for (i = 0; ipa_ref_list_reference_iterate (&vnode->ref_list, i, ref); i++)
|
||||
{
|
||||
tree var;
|
||||
if (ref->refered_type != IPA_REF_VARPOOL)
|
||||
continue;
|
||||
var = ipa_ref_varpool_node (ref)->decl;
|
||||
if (ipa_ref_varpool_node (ref)->externally_visible
|
||||
|| !ipa_ref_varpool_node (ref)->analyzed
|
||||
|| !is_proper_for_analysis (var))
|
||||
continue;
|
||||
switch (ref->use)
|
||||
{
|
||||
case IPA_REF_LOAD:
|
||||
case IPA_REF_STORE:
|
||||
gcc_unreachable ();
|
||||
break;
|
||||
case IPA_REF_ADDR:
|
||||
bitmap_set_bit (module_statics_escape, DECL_UID (var));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -664,49 +490,49 @@ init_function_info (struct cgraph_node *fn)
|
||||
static void
|
||||
analyze_function (struct cgraph_node *fn)
|
||||
{
|
||||
tree decl = fn->decl;
|
||||
struct function *this_cfun = DECL_STRUCT_FUNCTION (decl);
|
||||
basic_block this_block;
|
||||
#ifdef ENABLE_CHECKING
|
||||
tree step;
|
||||
#endif
|
||||
ipa_reference_local_vars_info_t local;
|
||||
struct ipa_ref *ref;
|
||||
int i;
|
||||
tree var;
|
||||
struct cgraph_edge *ie;
|
||||
|
||||
if (dump_file)
|
||||
fprintf (dump_file, "\n local analysis of %s\n", cgraph_node_name (fn));
|
||||
|
||||
push_cfun (DECL_STRUCT_FUNCTION (decl));
|
||||
current_function_decl = decl;
|
||||
|
||||
init_function_info (fn);
|
||||
FOR_EACH_BB_FN (this_block, this_cfun)
|
||||
local = init_function_info (fn);
|
||||
/* Process indirect calls. All direct calles are handled at propagation
|
||||
time. */
|
||||
for (ie = fn->indirect_calls; ie; ie = ie->next_callee)
|
||||
if (!(ie->indirect_info->ecf_flags & ECF_CONST))
|
||||
{
|
||||
local->calls_read_all = true;
|
||||
if (!(ie->indirect_info->ecf_flags & ECF_PURE)
|
||||
&& ((ie->indirect_info->ecf_flags & (ECF_NOTHROW | ECF_NORETURN))
|
||||
!= (ECF_NOTHROW | ECF_NORETURN)))
|
||||
local->calls_write_all = true;
|
||||
}
|
||||
for (i = 0; ipa_ref_list_reference_iterate (&fn->ref_list, i, ref); i++)
|
||||
{
|
||||
gimple_stmt_iterator gsi;
|
||||
gimple phi;
|
||||
tree op;
|
||||
use_operand_p use;
|
||||
ssa_op_iter iter;
|
||||
|
||||
/* Find the addresses taken in phi node arguments. */
|
||||
for (gsi = gsi_start_phis (this_block);
|
||||
!gsi_end_p (gsi);
|
||||
gsi_next (&gsi))
|
||||
if (ref->refered_type != IPA_REF_VARPOOL)
|
||||
continue;
|
||||
var = ipa_ref_varpool_node (ref)->decl;
|
||||
if (ipa_ref_varpool_node (ref)->externally_visible
|
||||
|| !ipa_ref_varpool_node (ref)->analyzed
|
||||
|| !is_proper_for_analysis (var))
|
||||
continue;
|
||||
switch (ref->use)
|
||||
{
|
||||
phi = gsi_stmt (gsi);
|
||||
FOR_EACH_PHI_ARG (use, phi, iter, SSA_OP_USE)
|
||||
{
|
||||
op = USE_FROM_PTR (use);
|
||||
if (TREE_CODE (op) == ADDR_EXPR)
|
||||
mark_address_taken (get_base_var (op));
|
||||
}
|
||||
case IPA_REF_LOAD:
|
||||
bitmap_set_bit (local->statics_read, DECL_UID (var));
|
||||
break;
|
||||
case IPA_REF_STORE:
|
||||
bitmap_set_bit (local->statics_written, DECL_UID (var));
|
||||
bitmap_set_bit (module_statics_written, DECL_UID (var));
|
||||
break;
|
||||
case IPA_REF_ADDR:
|
||||
bitmap_set_bit (module_statics_escape, DECL_UID (var));
|
||||
break;
|
||||
}
|
||||
|
||||
for (gsi = gsi_start_bb (this_block); !gsi_end_p (gsi); gsi_next (&gsi))
|
||||
scan_stmt_for_static_refs (&gsi, fn);
|
||||
}
|
||||
|
||||
local = get_reference_vars_info (fn)->local;
|
||||
if ((flags_from_decl_or_type (decl) & (ECF_NOTHROW | ECF_NORETURN))
|
||||
if ((flags_from_decl_or_type (fn->decl) & (ECF_NOTHROW | ECF_NORETURN))
|
||||
== (ECF_NOTHROW | ECF_NORETURN))
|
||||
{
|
||||
local->calls_write_all = false;
|
||||
@ -718,23 +544,6 @@ analyze_function (struct cgraph_node *fn)
|
||||
BITMAP_FREE (local->statics_written);
|
||||
if (local->calls_read_all)
|
||||
BITMAP_FREE (local->statics_read);
|
||||
|
||||
|
||||
#ifdef ENABLE_CHECKING
|
||||
/* Verify that all local initializers was expanded by gimplifier. */
|
||||
for (step = DECL_STRUCT_FUNCTION (decl)->local_decls;
|
||||
step;
|
||||
step = TREE_CHAIN (step))
|
||||
{
|
||||
tree var = TREE_VALUE (step);
|
||||
if (TREE_CODE (var) == VAR_DECL
|
||||
&& DECL_INITIAL (var)
|
||||
&& !TREE_STATIC (var))
|
||||
gcc_unreachable ();
|
||||
}
|
||||
#endif
|
||||
pop_cfun ();
|
||||
current_function_decl = NULL;
|
||||
}
|
||||
|
||||
/* Remove local data associated with function FN. */
|
||||
@ -790,31 +599,6 @@ clean_function (struct cgraph_node *fn)
|
||||
set_reference_vars_info (fn, NULL);
|
||||
}
|
||||
|
||||
/* Called when new function is inserted to callgraph late. */
|
||||
static void
|
||||
add_new_function (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
|
||||
{
|
||||
/* There are some shared nodes, in particular the initializers on
|
||||
static declarations. We do not need to scan them more than once
|
||||
since all we would be interested in are the addressof
|
||||
operations. */
|
||||
analyze_function (node);
|
||||
visited_nodes = NULL;
|
||||
}
|
||||
|
||||
static bitmap
|
||||
copy_local_bitmap (bitmap src)
|
||||
{
|
||||
bitmap dst;
|
||||
if (!src)
|
||||
return NULL;
|
||||
if (src == all_module_statics)
|
||||
return all_module_statics;
|
||||
dst = BITMAP_ALLOC (&local_info_obstack);
|
||||
bitmap_copy (dst, src);
|
||||
return dst;
|
||||
}
|
||||
|
||||
static bitmap
|
||||
copy_global_bitmap (bitmap src)
|
||||
{
|
||||
@ -828,6 +612,7 @@ copy_global_bitmap (bitmap src)
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
||||
/* Called when new clone is inserted to callgraph late. */
|
||||
|
||||
static void
|
||||
@ -835,23 +620,12 @@ duplicate_node_data (struct cgraph_node *src, struct cgraph_node *dst,
|
||||
void *data ATTRIBUTE_UNUSED)
|
||||
{
|
||||
ipa_reference_global_vars_info_t ginfo;
|
||||
ipa_reference_local_vars_info_t linfo;
|
||||
ipa_reference_global_vars_info_t dst_ginfo;
|
||||
ipa_reference_local_vars_info_t dst_linfo;
|
||||
|
||||
ginfo = get_global_reference_vars_info (src);
|
||||
linfo = get_local_reference_vars_info (src);
|
||||
if (!linfo && !ginfo)
|
||||
if (!ginfo)
|
||||
return;
|
||||
init_function_info (dst);
|
||||
if (linfo)
|
||||
{
|
||||
dst_linfo = get_local_reference_vars_info (dst);
|
||||
dst_linfo->statics_read = copy_local_bitmap (linfo->statics_read);
|
||||
dst_linfo->statics_written = copy_local_bitmap (linfo->statics_written);
|
||||
dst_linfo->calls_read_all = linfo->calls_read_all;
|
||||
dst_linfo->calls_write_all = linfo->calls_write_all;
|
||||
}
|
||||
if (ginfo)
|
||||
{
|
||||
get_reference_vars_info (dst)->global = XCNEW (struct ipa_reference_global_vars_info_d);
|
||||
@ -893,24 +667,11 @@ generate_summary (void)
|
||||
FOR_EACH_STATIC_INITIALIZER (vnode)
|
||||
analyze_variable (vnode);
|
||||
|
||||
/* Process all of the functions next.
|
||||
|
||||
We do not want to process any of the clones so we check that this
|
||||
is a master clone. However, we do need to process any
|
||||
AVAIL_OVERWRITABLE functions (these are never clones) because
|
||||
they may cause a static variable to escape. The code that can
|
||||
overwrite such a function cannot access the statics because it
|
||||
would not be in the same compilation unit. When the analysis is
|
||||
finished, the computed information of these AVAIL_OVERWRITABLE is
|
||||
replaced with worst case info.
|
||||
*/
|
||||
/* Process all of the functions next. */
|
||||
for (node = cgraph_nodes; node; node = node->next)
|
||||
if (cgraph_function_body_availability (node) >= AVAIL_OVERWRITABLE)
|
||||
if (node->analyzed)
|
||||
analyze_function (node);
|
||||
|
||||
pointer_set_destroy (visited_nodes);
|
||||
visited_nodes = NULL;
|
||||
|
||||
/* Prune out the variables that were found to behave badly
|
||||
(i.e. have their address taken). */
|
||||
EXECUTE_IF_SET_IN_BITMAP (module_statics_escape, 0, index, bi)
|
||||
@ -1024,158 +785,6 @@ generate_summary (void)
|
||||
fprintf (dump_file, "\n calls read all: ");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Return true if we need to write summary of NODE. */
|
||||
|
||||
static bool
|
||||
write_node_summary_p (struct cgraph_node *node)
|
||||
{
|
||||
gcc_assert (node->global.inlined_to == NULL);
|
||||
return (node->analyzed
|
||||
&& cgraph_function_body_availability (node) >= AVAIL_OVERWRITABLE
|
||||
&& get_reference_vars_info (node) != NULL);
|
||||
}
|
||||
|
||||
/* Serialize the ipa info for lto. */
|
||||
|
||||
static void
|
||||
ipa_reference_write_summary (cgraph_node_set set,
|
||||
varpool_node_set vset ATTRIBUTE_UNUSED)
|
||||
{
|
||||
struct cgraph_node *node;
|
||||
struct lto_simple_output_block *ob
|
||||
= lto_create_simple_output_block (LTO_section_ipa_reference);
|
||||
unsigned int count = 0;
|
||||
cgraph_node_set_iterator csi;
|
||||
|
||||
for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi))
|
||||
if (write_node_summary_p (csi_node (csi)))
|
||||
count++;
|
||||
|
||||
lto_output_uleb128_stream (ob->main_stream, count);
|
||||
|
||||
/* Process all of the functions. */
|
||||
for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi))
|
||||
{
|
||||
node = csi_node (csi);
|
||||
if (write_node_summary_p (node))
|
||||
{
|
||||
ipa_reference_local_vars_info_t l
|
||||
= get_reference_vars_info (node)->local;
|
||||
unsigned int index;
|
||||
bitmap_iterator bi;
|
||||
lto_cgraph_encoder_t encoder;
|
||||
int node_ref;
|
||||
|
||||
encoder = ob->decl_state->cgraph_node_encoder;
|
||||
node_ref = lto_cgraph_encoder_encode (encoder, node);
|
||||
lto_output_uleb128_stream (ob->main_stream, node_ref);
|
||||
|
||||
/* Stream out the statics read. */
|
||||
if (l->calls_read_all)
|
||||
lto_output_sleb128_stream (ob->main_stream, -1);
|
||||
else
|
||||
{
|
||||
lto_output_sleb128_stream (ob->main_stream,
|
||||
bitmap_count_bits (l->statics_read));
|
||||
EXECUTE_IF_SET_IN_BITMAP (l->statics_read, 0, index, bi)
|
||||
lto_output_var_decl_index(ob->decl_state, ob->main_stream,
|
||||
get_static_decl (index));
|
||||
}
|
||||
|
||||
/* Stream out the statics written. */
|
||||
if (l->calls_write_all)
|
||||
lto_output_sleb128_stream (ob->main_stream, -1);
|
||||
else
|
||||
{
|
||||
lto_output_sleb128_stream (ob->main_stream,
|
||||
bitmap_count_bits (l->statics_written));
|
||||
EXECUTE_IF_SET_IN_BITMAP (l->statics_written, 0, index, bi)
|
||||
lto_output_var_decl_index(ob->decl_state, ob->main_stream,
|
||||
get_static_decl (index));
|
||||
}
|
||||
}
|
||||
}
|
||||
lto_destroy_simple_output_block (ob);
|
||||
}
|
||||
|
||||
|
||||
/* Deserialize the ipa info for lto. */
|
||||
|
||||
static void
|
||||
ipa_reference_read_summary (void)
|
||||
{
|
||||
struct lto_file_decl_data ** file_data_vec
|
||||
= lto_get_file_decl_data ();
|
||||
struct lto_file_decl_data * file_data;
|
||||
unsigned int j = 0;
|
||||
|
||||
ipa_init ();
|
||||
|
||||
while ((file_data = file_data_vec[j++]))
|
||||
{
|
||||
const char *data;
|
||||
size_t len;
|
||||
struct lto_input_block *ib
|
||||
= lto_create_simple_input_block (file_data,
|
||||
LTO_section_ipa_reference,
|
||||
&data, &len);
|
||||
if (ib)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int f_count = lto_input_uleb128 (ib);
|
||||
|
||||
for (i = 0; i < f_count; i++)
|
||||
{
|
||||
unsigned int j, index;
|
||||
struct cgraph_node *node;
|
||||
ipa_reference_local_vars_info_t l;
|
||||
int v_count;
|
||||
lto_cgraph_encoder_t encoder;
|
||||
|
||||
index = lto_input_uleb128 (ib);
|
||||
encoder = file_data->cgraph_node_encoder;
|
||||
node = lto_cgraph_encoder_deref (encoder, index);
|
||||
l = init_function_info (node);
|
||||
|
||||
/* Set the statics read. */
|
||||
v_count = lto_input_sleb128 (ib);
|
||||
if (v_count == -1)
|
||||
l->calls_read_all = true;
|
||||
else
|
||||
for (j = 0; j < (unsigned int)v_count; j++)
|
||||
{
|
||||
unsigned int var_index = lto_input_uleb128 (ib);
|
||||
tree v_decl = lto_file_decl_data_get_var_decl (file_data,
|
||||
var_index);
|
||||
add_static_var (v_decl);
|
||||
bitmap_set_bit (l->statics_read, DECL_UID (v_decl));
|
||||
}
|
||||
|
||||
/* Set the statics written. */
|
||||
v_count = lto_input_sleb128 (ib);
|
||||
if (v_count == -1)
|
||||
l->calls_write_all = true;
|
||||
else
|
||||
for (j = 0; j < (unsigned int)v_count; j++)
|
||||
{
|
||||
unsigned int var_index = lto_input_uleb128 (ib);
|
||||
tree v_decl = lto_file_decl_data_get_var_decl (file_data,
|
||||
var_index);
|
||||
add_static_var (v_decl);
|
||||
bitmap_set_bit (l->statics_written, DECL_UID (v_decl));
|
||||
}
|
||||
}
|
||||
|
||||
lto_destroy_simple_input_block (file_data,
|
||||
LTO_section_ipa_reference,
|
||||
ib, data, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Set READ_ALL/WRITE_ALL based on DECL flags. */
|
||||
static void
|
||||
@ -1215,10 +824,11 @@ propagate (void)
|
||||
int order_pos = ipa_utils_reduced_inorder (order, false, true, NULL);
|
||||
int i;
|
||||
|
||||
cgraph_remove_function_insertion_hook (function_insertion_hook_holder);
|
||||
if (dump_file)
|
||||
dump_cgraph (dump_file);
|
||||
|
||||
generate_summary ();
|
||||
|
||||
/* Propagate the local information thru the call graph to produce
|
||||
the global information. All the nodes within a cycle will have
|
||||
the same info so we collapse cycles first. Then we can do the
|
||||
@ -1512,9 +1122,9 @@ struct ipa_opt_pass_d pass_ipa_reference =
|
||||
0, /* todo_flags_start */
|
||||
0 /* todo_flags_finish */
|
||||
},
|
||||
generate_summary, /* generate_summary */
|
||||
ipa_reference_write_summary, /* write_summary */
|
||||
ipa_reference_read_summary, /* read_summary */
|
||||
NULL, /* generate_summary */
|
||||
NULL, /* write_summary */
|
||||
NULL, /* read_summary */
|
||||
NULL, /* write_optimization_summary */
|
||||
NULL, /* read_optimization_summary */
|
||||
NULL, /* stmt_fixup */
|
||||
|
@ -282,6 +282,21 @@ lto_output_edge (struct lto_simple_output_block *ob, struct cgraph_edge *edge,
|
||||
bp_pack_value (bp, edge->indirect_inlining_edge, 1);
|
||||
bp_pack_value (bp, edge->call_stmt_cannot_inline_p, 1);
|
||||
bp_pack_value (bp, edge->can_throw_external, 1);
|
||||
if (edge->indirect_unknown_callee)
|
||||
{
|
||||
int flags = edge->indirect_info->ecf_flags;
|
||||
bp_pack_value (bp, (flags & ECF_CONST) != 0, 1);
|
||||
bp_pack_value (bp, (flags & ECF_PURE) != 0, 1);
|
||||
bp_pack_value (bp, (flags & ECF_NORETURN) != 0, 1);
|
||||
bp_pack_value (bp, (flags & ECF_MALLOC) != 0, 1);
|
||||
bp_pack_value (bp, (flags & ECF_NOTHROW) != 0, 1);
|
||||
bp_pack_value (bp, (flags & ECF_RETURNS_TWICE) != 0, 1);
|
||||
/* Flags that should not appear on indirect calls. */
|
||||
gcc_assert (!(flags & (ECF_LOOPING_CONST_OR_PURE
|
||||
| ECF_MAY_BE_ALLOCA
|
||||
| ECF_SIBCALL
|
||||
| ECF_NOVOPS)));
|
||||
}
|
||||
lto_output_bitpack (ob->main_stream, bp);
|
||||
bitpack_delete (bp);
|
||||
}
|
||||
@ -1060,6 +1075,7 @@ input_edge (struct lto_input_block *ib, VEC(cgraph_node_ptr, heap) *nodes,
|
||||
cgraph_inline_failed_t inline_failed;
|
||||
struct bitpack_d *bp;
|
||||
enum ld_plugin_symbol_resolution caller_resolution;
|
||||
int ecf_flags = 0;
|
||||
|
||||
caller = VEC_index (cgraph_node_ptr, nodes, lto_input_sleb128 (ib));
|
||||
if (caller == NULL || caller->decl == NULL_TREE)
|
||||
@ -1091,7 +1107,7 @@ input_edge (struct lto_input_block *ib, VEC(cgraph_node_ptr, heap) *nodes,
|
||||
return;
|
||||
|
||||
if (indirect)
|
||||
edge = cgraph_create_indirect_edge (caller, NULL, count, freq, nest);
|
||||
edge = cgraph_create_indirect_edge (caller, NULL, 0, count, freq, nest);
|
||||
else
|
||||
edge = cgraph_create_edge (caller, callee, NULL, count, freq, nest);
|
||||
|
||||
@ -1100,6 +1116,22 @@ input_edge (struct lto_input_block *ib, VEC(cgraph_node_ptr, heap) *nodes,
|
||||
edge->inline_failed = inline_failed;
|
||||
edge->call_stmt_cannot_inline_p = bp_unpack_value (bp, 1);
|
||||
edge->can_throw_external = bp_unpack_value (bp, 1);
|
||||
if (indirect)
|
||||
{
|
||||
if (bp_unpack_value (bp, 1))
|
||||
ecf_flags |= ECF_CONST;
|
||||
if (bp_unpack_value (bp, 1))
|
||||
ecf_flags |= ECF_PURE;
|
||||
if (bp_unpack_value (bp, 1))
|
||||
ecf_flags |= ECF_NORETURN;
|
||||
if (bp_unpack_value (bp, 1))
|
||||
ecf_flags |= ECF_MALLOC;
|
||||
if (bp_unpack_value (bp, 1))
|
||||
ecf_flags |= ECF_NOTHROW;
|
||||
if (bp_unpack_value (bp, 1))
|
||||
ecf_flags |= ECF_RETURNS_TWICE;
|
||||
edge->indirect_info->ecf_flags = ecf_flags;
|
||||
}
|
||||
bitpack_delete (bp);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user