Commit eb6a09a7 by Jan Hubicka Committed by Jan Hubicka

varpool.c (dump_varpool_node): Dump used_by_single_function.


	* varpool.c (dump_varpool_node): Dump used_by_single_function.
	* tree-pass.h (make_pass_ipa_single_use): New pass.
	* cgraph.h (used_by_single_function): New flag.
	* lto-cgraph.c (lto_output_varpool_node, input_varpool_node): Stream
	it.
	* passes.def (pass_ipa_single_use): Scedule.
	* ipa.c (BOTTOM): New macro.
	(meet): New function
	(propagate_single_user): New function.
	(ipa_single_use): New function.
	(pass_data_ipa_single_use): New pass.
	(pass_ipa_single_use): New pass.
	(pass_ipa_single_use::gate): New gate.
	(make_pass_ipa_single_use): New function.

From-SVN: r211925
parent d7dab049
2014-06-23 Jan Hubicka <hubicka@ucw.cz>
* varpool.c (dump_varpool_node): Dump used_by_single_function.
* tree-pass.h (make_pass_ipa_single_use): New pass.
* cgraph.h (used_by_single_function): New flag.
* lto-cgraph.c (lto_output_varpool_node, input_varpool_node): Stream
it.
* passes.def (pass_ipa_single_use): Scedule.
* ipa.c (BOTTOM): New macro.
(meet): New function
(propagate_single_user): New function.
(ipa_single_use): New function.
(pass_data_ipa_single_use): New pass.
(pass_ipa_single_use): New pass.
(pass_ipa_single_use::gate): New gate.
(make_pass_ipa_single_use): New function.
2014-06-23 Kai Tietz <ktietz@redhat.com> 2014-06-23 Kai Tietz <ktietz@redhat.com>
PR target/39284 PR target/39284
......
...@@ -719,6 +719,12 @@ public: ...@@ -719,6 +719,12 @@ public:
unsigned dynamically_initialized : 1; unsigned dynamically_initialized : 1;
ENUM_BITFIELD(tls_model) tls_model : 3; ENUM_BITFIELD(tls_model) tls_model : 3;
/* Set if the variable is known to be used by single function only.
This is computed by ipa_signle_use pass and used by late optimizations
in places where optimization would be valid for local static variable
if we did not do any inter-procedural code movement. */
unsigned used_by_single_function : 1;
}; };
/* Every top level asm statement is put into a asm_node. */ /* Every top level asm statement is put into a asm_node. */
......
...@@ -1096,3 +1096,226 @@ make_pass_ipa_cdtor_merge (gcc::context *ctxt) ...@@ -1096,3 +1096,226 @@ make_pass_ipa_cdtor_merge (gcc::context *ctxt)
{ {
return new pass_ipa_cdtor_merge (ctxt); return new pass_ipa_cdtor_merge (ctxt);
} }
/* Invalid pointer representing BOTTOM for single user dataflow. */
#define BOTTOM ((cgraph_node *)(size_t) 2)
/* Meet operation for single user dataflow.
Here we want to associate variables with sigle function that may access it.
FUNCTION is current single user of a variable, VAR is variable that uses it.
Latttice is stored in SINGLE_USER_MAP.
We represent:
- TOP by no entry in SIGNLE_USER_MAP
- BOTTOM by BOTTOM in AUX pointer (to save lookups)
- known single user by cgraph pointer in SINGLE_USER_MAP. */
cgraph_node *
meet (cgraph_node *function, varpool_node *var,
pointer_map<cgraph_node *> &single_user_map)
{
struct cgraph_node *user, **f;
if (var->aux == BOTTOM)
return BOTTOM;
f = single_user_map.contains (var);
if (!f)
return function;
user = *f;
if (!function)
return user;
else if (function != user)
return BOTTOM;
else
return function;
}
/* Propagation step of single-use dataflow.
Check all uses of VNODE and see if they are used by single function FUNCTION.
SINGLE_USER_MAP represents the dataflow lattice. */
cgraph_node *
propagate_single_user (varpool_node *vnode, cgraph_node *function,
pointer_map<cgraph_node *> &single_user_map)
{
int i;
struct ipa_ref *ref;
gcc_assert (!vnode->externally_visible);
/* If node is an alias, first meet with its target. */
if (vnode->alias)
function = meet (function, varpool_alias_target (vnode), single_user_map);
/* Check all users and see if they correspond to a single function. */
for (i = 0;
ipa_ref_list_referring_iterate (&vnode->ref_list, i, ref)
&& function != BOTTOM; i++)
{
struct cgraph_node *cnode = dyn_cast <cgraph_node *> (ref->referring);
if (cnode)
{
if (cnode->global.inlined_to)
cnode = cnode->global.inlined_to;
if (!function)
function = cnode;
else if (function != cnode)
function = BOTTOM;
}
else
function = meet (function, dyn_cast <varpool_node *> (ref->referring), single_user_map);
}
return function;
}
/* Pass setting used_by_single_function flag.
This flag is set on variable when there is only one function that may possibly
referr to it. */
static unsigned int
ipa_single_use (void)
{
varpool_node *first = (varpool_node *) (void *) 1;
varpool_node *var;
pointer_map<cgraph_node *> single_user_map;
FOR_EACH_DEFINED_VARIABLE (var)
if (!varpool_all_refs_explicit_p (var))
var->aux = BOTTOM;
else
{
/* Enqueue symbol for dataflow. */
var->aux = first;
first = var;
}
/* The actual dataflow. */
while (first != (void *) 1)
{
cgraph_node *user, *orig_user, **f;
var = first;
first = (varpool_node *)first->aux;
f = single_user_map.contains (var);
if (f)
orig_user = *f;
else
orig_user = NULL;
user = propagate_single_user (var, orig_user, single_user_map);
gcc_checking_assert (var->aux != BOTTOM);
/* If user differs, enqueue all references. */
if (user != orig_user)
{
unsigned int i;
ipa_ref *ref;
*single_user_map.insert (var) = user;
/* Enqueue all aliases for re-processing. */
for (i = 0;
ipa_ref_list_referring_iterate (&var->ref_list, i, ref); i++)
if (ref->use == IPA_REF_ALIAS
&& !ref->referring->aux)
{
ref->referring->aux = first;
first = dyn_cast <varpool_node *> (ref->referring);
}
/* Enqueue all users for re-processing. */
for (i = 0;
ipa_ref_list_reference_iterate (&var->ref_list, i, ref); i++)
if (!ref->referred->aux
&& ref->referred->definition
&& is_a <varpool_node *> (ref->referred))
{
ref->referred->aux = first;
first = dyn_cast <varpool_node *> (ref->referred);
}
/* If user is BOTTOM, just punt on this var. */
if (user == BOTTOM)
var->aux = BOTTOM;
else
var->aux = NULL;
}
else
var->aux = NULL;
}
FOR_EACH_DEFINED_VARIABLE (var)
{
if (var->aux != BOTTOM)
{
#ifdef ENABLE_CHECKING
if (!single_user_map.contains (var))
gcc_assert (single_user_map.contains (var));
#endif
if (dump_file)
{
fprintf (dump_file, "Variable %s/%i is used by single function\n",
var->name (), var->order);
}
var->used_by_single_function = true;
}
var->aux = NULL;
}
return 0;
}
namespace {
const pass_data pass_data_ipa_single_use =
{
IPA_PASS, /* type */
"single-use", /* name */
OPTGROUP_NONE, /* optinfo_flags */
true, /* has_execute */
TV_CGRAPHOPT, /* tv_id */
0, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
0, /* todo_flags_finish */
};
class pass_ipa_single_use : public ipa_opt_pass_d
{
public:
pass_ipa_single_use (gcc::context *ctxt)
: ipa_opt_pass_d (pass_data_ipa_single_use, ctxt,
NULL, /* generate_summary */
NULL, /* write_summary */
NULL, /* read_summary */
NULL, /* write_optimization_summary */
NULL, /* read_optimization_summary */
NULL, /* stmt_fixup */
0, /* function_transform_todo_flags_start */
NULL, /* function_transform */
NULL) /* variable_transform */
{}
/* opt_pass methods: */
virtual bool gate (function *);
virtual unsigned int execute (function *) { return ipa_single_use (); }
}; // class pass_ipa_single_use
bool
pass_ipa_single_use::gate (function *)
{
return optimize;
}
} // anon namespace
ipa_opt_pass_d *
make_pass_ipa_single_use (gcc::context *ctxt)
{
return new pass_ipa_single_use (ctxt);
}
...@@ -614,6 +614,7 @@ lto_output_varpool_node (struct lto_simple_output_block *ob, varpool_node *node, ...@@ -614,6 +614,7 @@ lto_output_varpool_node (struct lto_simple_output_block *ob, varpool_node *node,
/* in_other_partition. */ /* in_other_partition. */
} }
bp_pack_value (&bp, node->tls_model, 3); bp_pack_value (&bp, node->tls_model, 3);
bp_pack_value (&bp, node->used_by_single_function, 1);
streamer_write_bitpack (&bp); streamer_write_bitpack (&bp);
group = node->get_comdat_group (); group = node->get_comdat_group ();
...@@ -1275,6 +1276,7 @@ input_varpool_node (struct lto_file_decl_data *file_data, ...@@ -1275,6 +1276,7 @@ input_varpool_node (struct lto_file_decl_data *file_data,
if (node->alias && !node->analyzed && node->weakref) if (node->alias && !node->analyzed && node->weakref)
node->alias_target = get_alias_symbol (node->decl); node->alias_target = get_alias_symbol (node->decl);
node->tls_model = (enum tls_model)bp_unpack_value (&bp, 3); node->tls_model = (enum tls_model)bp_unpack_value (&bp, 3);
node->used_by_single_function = (enum tls_model)bp_unpack_value (&bp, 1);
group = read_identifier (ib); group = read_identifier (ib);
if (group) if (group)
{ {
......
...@@ -109,6 +109,8 @@ along with GCC; see the file COPYING3. If not see ...@@ -109,6 +109,8 @@ along with GCC; see the file COPYING3. If not see
NEXT_PASS (pass_ipa_inline); NEXT_PASS (pass_ipa_inline);
NEXT_PASS (pass_ipa_pure_const); NEXT_PASS (pass_ipa_pure_const);
NEXT_PASS (pass_ipa_reference); NEXT_PASS (pass_ipa_reference);
/* This pass needs to be scheduled after any IP code duplication. */
NEXT_PASS (pass_ipa_single_use);
/* Comdat privatization come last, as direct references to comdat local /* Comdat privatization come last, as direct references to comdat local
symbols are not allowed outside of the comdat group. Privatizing early symbols are not allowed outside of the comdat group. Privatizing early
would result in missed optimizations due to this restriction. */ would result in missed optimizations due to this restriction. */
......
...@@ -472,6 +472,7 @@ extern simple_ipa_opt_pass *make_pass_ipa_tm (gcc::context *ctxt); ...@@ -472,6 +472,7 @@ extern simple_ipa_opt_pass *make_pass_ipa_tm (gcc::context *ctxt);
extern simple_ipa_opt_pass *make_pass_omp_simd_clone (gcc::context *ctxt); extern simple_ipa_opt_pass *make_pass_omp_simd_clone (gcc::context *ctxt);
extern ipa_opt_pass_d *make_pass_ipa_profile (gcc::context *ctxt); extern ipa_opt_pass_d *make_pass_ipa_profile (gcc::context *ctxt);
extern ipa_opt_pass_d *make_pass_ipa_cdtor_merge (gcc::context *ctxt); extern ipa_opt_pass_d *make_pass_ipa_cdtor_merge (gcc::context *ctxt);
extern ipa_opt_pass_d *make_pass_ipa_single_use (gcc::context *ctxt);
extern ipa_opt_pass_d *make_pass_ipa_comdats (gcc::context *ctxt); extern ipa_opt_pass_d *make_pass_ipa_comdats (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_cleanup_cfg_post_optimizing (gcc::context extern gimple_opt_pass *make_pass_cleanup_cfg_post_optimizing (gcc::context
......
...@@ -211,6 +211,8 @@ dump_varpool_node (FILE *f, varpool_node *node) ...@@ -211,6 +211,8 @@ dump_varpool_node (FILE *f, varpool_node *node)
fprintf (f, " initialized"); fprintf (f, " initialized");
if (node->output) if (node->output)
fprintf (f, " output"); fprintf (f, " output");
if (node->used_by_single_function)
fprintf (f, " used-by-single-function");
if (TREE_READONLY (node->decl)) if (TREE_READONLY (node->decl))
fprintf (f, " read-only"); fprintf (f, " read-only");
if (ctor_for_folding (node->decl) != error_mark_node) if (ctor_for_folding (node->decl) != error_mark_node)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment