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
This commit is contained in:
Jan Hubicka 2014-06-24 05:07:13 +02:00 committed by Jan Hubicka
parent d7dab049c7
commit eb6a09a725
7 changed files with 253 additions and 0 deletions

View File

@ -1,3 +1,20 @@
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>
PR target/39284

View File

@ -719,6 +719,12 @@ public:
unsigned dynamically_initialized : 1;
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. */

223
gcc/ipa.c
View File

@ -1096,3 +1096,226 @@ make_pass_ipa_cdtor_merge (gcc::context *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);
}

View File

@ -614,6 +614,7 @@ lto_output_varpool_node (struct lto_simple_output_block *ob, varpool_node *node,
/* in_other_partition. */
}
bp_pack_value (&bp, node->tls_model, 3);
bp_pack_value (&bp, node->used_by_single_function, 1);
streamer_write_bitpack (&bp);
group = node->get_comdat_group ();
@ -1275,6 +1276,7 @@ input_varpool_node (struct lto_file_decl_data *file_data,
if (node->alias && !node->analyzed && node->weakref)
node->alias_target = get_alias_symbol (node->decl);
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);
if (group)
{

View File

@ -109,6 +109,8 @@ along with GCC; see the file COPYING3. If not see
NEXT_PASS (pass_ipa_inline);
NEXT_PASS (pass_ipa_pure_const);
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
symbols are not allowed outside of the comdat group. Privatizing early
would result in missed optimizations due to this restriction. */

View File

@ -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 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_single_use (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

View File

@ -211,6 +211,8 @@ dump_varpool_node (FILE *f, varpool_node *node)
fprintf (f, " initialized");
if (node->output)
fprintf (f, " output");
if (node->used_by_single_function)
fprintf (f, " used-by-single-function");
if (TREE_READONLY (node->decl))
fprintf (f, " read-only");
if (ctor_for_folding (node->decl) != error_mark_node)