Commit e3bfa377 by Bin Cheng Committed by Bin Cheng

tree-outof-ssa.c (tree-ssa.h, tree-dfa.h): Include header files.

	* tree-outof-ssa.c (tree-ssa.h, tree-dfa.h): Include header files.
	(create_default_def, for_all_parms): Moved from tree-ssa-coalesce.c.
	(parm_default_def_partition_arg): Ditto.
	(set_parm_default_def_partition): Ditto.
	(get_parm_default_def_partitions): Ditto and make it static.
	(get_undefined_value_partitions): Ditto and make it static.
	(remove_ssa_form): Refactor call to init_var_map here.
	* tree-ssa-coalesce.c (build_ssa_conflict_graph): Support live range
	computation for loop region.
	(coalesce_partitions, compute_optimized_partition_bases): Ditto.
	(register_default_def): Delete.
	(for_all_parms, create_default_def): Move to tree-outof-ssa.c.
	(parm_default_def_partition_arg): Ditto.
	(set_parm_default_def_partition): Ditto.
	(get_parm_default_def_partitions): Ditto and make it static.
	(get_undefined_value_partitions): Ditto and make it static.
	(coalesce_with_default, coalesce_with_default): Update comment.
	(create_coalesce_list_for_region): New func factored out from
	create_outofssa_var_map.
	(populate_coalesce_list_for_outofssa): New func factored out from
	create_outofssa_var_map and coalesce_ssa_name.
	(create_outofssa_var_map): Delete.
	(coalesce_ssa_name): Refactor to support live range computation.
	* tree-ssa-coalesce.h (coalesce_ssa_name): Change decl.
	(get_parm_default_def_partitions): Delete.
	(get_undefined_value_partitions): Ditto.
	* tree-ssa-live.c (init_var_map, delete_var_map): Support live range
	computation for loop region.
	(new_tree_live_info, loe_visit_block): Ditto.
	(live_worklist, set_var_live_on_entry): Ditto.
	(calculate_live_on_exit, verify_live_on_entry): Ditto.
	* tree-ssa-live.h (struct _var_map): New fields.
	(init_var_map): Change decl.
	(region_contains_p): New.

From-SVN: r260747
parent 34f7080e
2018-05-25 Bin Cheng <bin.cheng@arm.com> 2018-05-25 Bin Cheng <bin.cheng@arm.com>
* tree-outof-ssa.c (tree-ssa.h, tree-dfa.h): Include header files.
(create_default_def, for_all_parms): Moved from tree-ssa-coalesce.c.
(parm_default_def_partition_arg): Ditto.
(set_parm_default_def_partition): Ditto.
(get_parm_default_def_partitions): Ditto and make it static.
(get_undefined_value_partitions): Ditto and make it static.
(remove_ssa_form): Refactor call to init_var_map here.
* tree-ssa-coalesce.c (build_ssa_conflict_graph): Support live range
computation for loop region.
(coalesce_partitions, compute_optimized_partition_bases): Ditto.
(register_default_def): Delete.
(for_all_parms, create_default_def): Move to tree-outof-ssa.c.
(parm_default_def_partition_arg): Ditto.
(set_parm_default_def_partition): Ditto.
(get_parm_default_def_partitions): Ditto and make it static.
(get_undefined_value_partitions): Ditto and make it static.
(coalesce_with_default, coalesce_with_default): Update comment.
(create_coalesce_list_for_region): New func factored out from
create_outofssa_var_map.
(populate_coalesce_list_for_outofssa): New func factored out from
create_outofssa_var_map and coalesce_ssa_name.
(create_outofssa_var_map): Delete.
(coalesce_ssa_name): Refactor to support live range computation.
* tree-ssa-coalesce.h (coalesce_ssa_name): Change decl.
(get_parm_default_def_partitions): Delete.
(get_undefined_value_partitions): Ditto.
* tree-ssa-live.c (init_var_map, delete_var_map): Support live range
computation for loop region.
(new_tree_live_info, loe_visit_block): Ditto.
(live_worklist, set_var_live_on_entry): Ditto.
(calculate_live_on_exit, verify_live_on_entry): Ditto.
* tree-ssa-live.h (struct _var_map): New fields.
(init_var_map): Change decl.
(region_contains_p): New.
2018-05-25 Bin Cheng <bin.cheng@arm.com>
* tree-ssa-live.h (live_merge_and_clear): Delete. * tree-ssa-live.h (live_merge_and_clear): Delete.
2018-05-25 Richard Biener <rguenther@suse.de> 2018-05-25 Richard Biener <rguenther@suse.de>
......
...@@ -27,10 +27,12 @@ along with GCC; see the file COPYING3. If not see ...@@ -27,10 +27,12 @@ along with GCC; see the file COPYING3. If not see
#include "gimple.h" #include "gimple.h"
#include "cfghooks.h" #include "cfghooks.h"
#include "ssa.h" #include "ssa.h"
#include "tree-ssa.h"
#include "memmodel.h" #include "memmodel.h"
#include "emit-rtl.h" #include "emit-rtl.h"
#include "gimple-pretty-print.h" #include "gimple-pretty-print.h"
#include "diagnostic-core.h" #include "diagnostic-core.h"
#include "tree-dfa.h"
#include "stor-layout.h" #include "stor-layout.h"
#include "cfgrtl.h" #include "cfgrtl.h"
#include "cfganal.h" #include "cfganal.h"
...@@ -888,6 +890,102 @@ rewrite_trees (var_map map) ...@@ -888,6 +890,102 @@ rewrite_trees (var_map map)
} }
} }
/* Create a default def for VAR. */
static void
create_default_def (tree var, void *arg ATTRIBUTE_UNUSED)
{
if (!is_gimple_reg (var))
return;
tree ssa = get_or_create_ssa_default_def (cfun, var);
gcc_assert (ssa);
}
/* Call CALLBACK for all PARM_DECLs and RESULT_DECLs for which
assign_parms may ask for a default partition. */
static void
for_all_parms (void (*callback)(tree var, void *arg), void *arg)
{
for (tree var = DECL_ARGUMENTS (current_function_decl); var;
var = DECL_CHAIN (var))
callback (var, arg);
if (!VOID_TYPE_P (TREE_TYPE (DECL_RESULT (current_function_decl))))
callback (DECL_RESULT (current_function_decl), arg);
if (cfun->static_chain_decl)
callback (cfun->static_chain_decl, arg);
}
/* We need to pass two arguments to set_parm_default_def_partition,
but for_all_parms only supports one. Use a pair. */
typedef std::pair<var_map, bitmap> parm_default_def_partition_arg;
/* Set in ARG's PARTS bitmap the bit corresponding to the partition in
ARG's MAP containing VAR's default def. */
static void
set_parm_default_def_partition (tree var, void *arg_)
{
parm_default_def_partition_arg *arg = (parm_default_def_partition_arg *)arg_;
var_map map = arg->first;
bitmap parts = arg->second;
if (!is_gimple_reg (var))
return;
tree ssa = ssa_default_def (cfun, var);
gcc_assert (ssa);
int version = var_to_partition (map, ssa);
gcc_assert (version != NO_PARTITION);
bool changed = bitmap_set_bit (parts, version);
gcc_assert (changed);
}
/* Allocate and return a bitmap that has a bit set for each partition
that contains a default def for a parameter. */
static bitmap
get_parm_default_def_partitions (var_map map)
{
bitmap parm_default_def_parts = BITMAP_ALLOC (NULL);
parm_default_def_partition_arg
arg = std::make_pair (map, parm_default_def_parts);
for_all_parms (set_parm_default_def_partition, &arg);
return parm_default_def_parts;
}
/* Allocate and return a bitmap that has a bit set for each partition
that contains an undefined value. */
static bitmap
get_undefined_value_partitions (var_map map)
{
bitmap undefined_value_parts = BITMAP_ALLOC (NULL);
for (unsigned int i = 1; i < num_ssa_names; i++)
{
tree var = ssa_name (i);
if (var
&& !virtual_operand_p (var)
&& !has_zero_uses (var)
&& ssa_undefined_value_p (var))
{
const int p = var_to_partition (map, var);
if (p != NO_PARTITION)
bitmap_set_bit (undefined_value_parts, p);
}
}
return undefined_value_parts;
}
/* Given the out-of-ssa info object SA (with prepared partitions) /* Given the out-of-ssa info object SA (with prepared partitions)
eliminate all phi nodes in all basic blocks. Afterwards no eliminate all phi nodes in all basic blocks. Afterwards no
basic block will have phi nodes anymore and there are possibly basic block will have phi nodes anymore and there are possibly
...@@ -945,7 +1043,9 @@ remove_ssa_form (bool perform_ter, struct ssaexpand *sa) ...@@ -945,7 +1043,9 @@ remove_ssa_form (bool perform_ter, struct ssaexpand *sa)
bitmap values = NULL; bitmap values = NULL;
var_map map; var_map map;
map = coalesce_ssa_name (); for_all_parms (create_default_def, NULL);
map = init_var_map (num_ssa_names);
coalesce_ssa_name (map);
/* Return to viewing the variable list as just all reference variables after /* Return to viewing the variable list as just all reference variables after
coalescing has been performed. */ coalescing has been performed. */
......
...@@ -879,7 +879,7 @@ build_ssa_conflict_graph (tree_live_info_p liveinfo) ...@@ -879,7 +879,7 @@ build_ssa_conflict_graph (tree_live_info_p liveinfo)
live = new_live_track (map); live = new_live_track (map);
FOR_EACH_BB_FN (bb, cfun) for (unsigned i = 0; liveinfo->map->vec_bbs.iterate (i, &bb); ++i)
{ {
/* Start with live on exit temporaries. */ /* Start with live on exit temporaries. */
live_track_init (live, live_on_exit (liveinfo, bb)); live_track_init (live, live_on_exit (liveinfo, bb));
...@@ -944,6 +944,8 @@ build_ssa_conflict_graph (tree_live_info_p liveinfo) ...@@ -944,6 +944,8 @@ build_ssa_conflict_graph (tree_live_info_p liveinfo)
{ {
gphi *phi = gsi.phi (); gphi *phi = gsi.phi ();
tree result = PHI_RESULT (phi); tree result = PHI_RESULT (phi);
if (virtual_operand_p (result))
continue;
if (live_track_live_p (live, result)) if (live_track_live_p (live, result))
live_track_process_def (live, result, graph); live_track_process_def (live, result, graph);
} }
...@@ -1012,48 +1014,9 @@ fail_abnormal_edge_coalesce (int x, int y) ...@@ -1012,48 +1014,9 @@ fail_abnormal_edge_coalesce (int x, int y)
internal_error ("SSA corruption"); internal_error ("SSA corruption");
} }
/* Call CALLBACK for all PARM_DECLs and RESULT_DECLs for which
assign_parms may ask for a default partition. */
static void
for_all_parms (void (*callback)(tree var, void *arg), void *arg)
{
for (tree var = DECL_ARGUMENTS (current_function_decl); var;
var = DECL_CHAIN (var))
callback (var, arg);
if (!VOID_TYPE_P (TREE_TYPE (DECL_RESULT (current_function_decl))))
callback (DECL_RESULT (current_function_decl), arg);
if (cfun->static_chain_decl)
callback (cfun->static_chain_decl, arg);
}
/* Create a default def for VAR. */
static void
create_default_def (tree var, void *arg ATTRIBUTE_UNUSED)
{
if (!is_gimple_reg (var))
return;
tree ssa = get_or_create_ssa_default_def (cfun, var);
gcc_assert (ssa);
}
/* Register VAR's default def in MAP. */
static void
register_default_def (tree var, void *arg ATTRIBUTE_UNUSED)
{
if (!is_gimple_reg (var))
return;
tree ssa = ssa_default_def (cfun, var);
gcc_assert (ssa);
}
/* If VAR is an SSA_NAME associated with a PARM_DECL or a RESULT_DECL, /* If VAR is an SSA_NAME associated with a PARM_DECL or a RESULT_DECL,
and the DECL's default def is unused (i.e., it was introduced by and the DECL's default def is unused (i.e., it was introduced by
create_default_def), mark VAR and the default def for create_default_def for out-of-ssa), mark VAR and the default def for
coalescing. */ coalescing. */
static void static void
...@@ -1070,32 +1033,25 @@ coalesce_with_default (tree var, coalesce_list *cl, bitmap used_in_copy) ...@@ -1070,32 +1033,25 @@ coalesce_with_default (tree var, coalesce_list *cl, bitmap used_in_copy)
add_cost_one_coalesce (cl, SSA_NAME_VERSION (ssa), SSA_NAME_VERSION (var)); add_cost_one_coalesce (cl, SSA_NAME_VERSION (ssa), SSA_NAME_VERSION (var));
bitmap_set_bit (used_in_copy, SSA_NAME_VERSION (var)); bitmap_set_bit (used_in_copy, SSA_NAME_VERSION (var));
/* Default defs will have their used_in_copy bits set at the end of /* Default defs will have their used_in_copy bits set at the beginning of
create_outofssa_var_map. */ populate_coalesce_list_for_outofssa. */
} }
/* This function creates a var_map for the current function as well as creating
a coalesce list for use later in the out of ssa process. */
static var_map /* Given var_map MAP for a region, this function creates and returns a coalesce
create_outofssa_var_map (coalesce_list *cl, bitmap used_in_copy) list as well as recording related ssa names in USED_IN_COPIES for use later
in the out-of-ssa or live range computation process. */
static coalesce_list *
create_coalesce_list_for_region (var_map map, bitmap used_in_copy)
{ {
gimple_stmt_iterator gsi; gimple_stmt_iterator gsi;
basic_block bb; basic_block bb;
tree var; coalesce_list *cl = create_coalesce_list ();
gimple *stmt; gimple *stmt;
tree first;
var_map map;
int v1, v2, cost; int v1, v2, cost;
unsigned i;
for_all_parms (create_default_def, NULL);
map = init_var_map (num_ssa_names);
for_all_parms (register_default_def, NULL);
FOR_EACH_BB_FN (bb, cfun) for (unsigned j = 0; map->vec_bbs.iterate (j, &bb); ++j)
{ {
tree arg; tree arg;
...@@ -1110,6 +1066,8 @@ create_outofssa_var_map (coalesce_list *cl, bitmap used_in_copy) ...@@ -1110,6 +1066,8 @@ create_outofssa_var_map (coalesce_list *cl, bitmap used_in_copy)
bool saw_copy = false; bool saw_copy = false;
res = gimple_phi_result (phi); res = gimple_phi_result (phi);
if (virtual_operand_p (res))
continue;
ver = SSA_NAME_VERSION (res); ver = SSA_NAME_VERSION (res);
/* Register ssa_names and coalesces between the args and the result /* Register ssa_names and coalesces between the args and the result
...@@ -1249,8 +1207,44 @@ create_outofssa_var_map (coalesce_list *cl, bitmap used_in_copy) ...@@ -1249,8 +1207,44 @@ create_outofssa_var_map (coalesce_list *cl, bitmap used_in_copy)
} }
} }
/* Now process result decls and live on entry variables for entry into return cl;
the coalesce list. */ }
/* Hashtable support for storing SSA names hashed by their SSA_NAME_VAR. */
struct ssa_name_var_hash : nofree_ptr_hash <tree_node>
{
static inline hashval_t hash (const tree_node *);
static inline int equal (const tree_node *, const tree_node *);
};
inline hashval_t
ssa_name_var_hash::hash (const_tree n)
{
return DECL_UID (SSA_NAME_VAR (n));
}
inline int
ssa_name_var_hash::equal (const tree_node *n1, const tree_node *n2)
{
return SSA_NAME_VAR (n1) == SSA_NAME_VAR (n2);
}
/* This function populates coalesce list CL as well as recording related ssa
names in USED_IN_COPIES for use later in the out-of-ssa process. */
static void
populate_coalesce_list_for_outofssa (coalesce_list *cl, bitmap used_in_copy)
{
tree var;
tree first;
int v1, v2, cost;
unsigned i;
/* Process result decls and live on entry variables for entry into the
coalesce list. */
first = NULL_TREE; first = NULL_TREE;
FOR_EACH_SSA_NAME (i, var, cfun) FOR_EACH_SSA_NAME (i, var, cfun)
{ {
...@@ -1285,7 +1279,46 @@ create_outofssa_var_map (coalesce_list *cl, bitmap used_in_copy) ...@@ -1285,7 +1279,46 @@ create_outofssa_var_map (coalesce_list *cl, bitmap used_in_copy)
} }
} }
return map; /* If this optimization is disabled, we need to coalesce all the
names originating from the same SSA_NAME_VAR so debug info
remains undisturbed. */
if (!flag_tree_coalesce_vars)
{
tree a;
hash_table<ssa_name_var_hash> ssa_name_hash (10);
FOR_EACH_SSA_NAME (i, a, cfun)
{
if (SSA_NAME_VAR (a)
&& !DECL_IGNORED_P (SSA_NAME_VAR (a))
&& (!has_zero_uses (a) || !SSA_NAME_IS_DEFAULT_DEF (a)
|| !VAR_P (SSA_NAME_VAR (a))))
{
tree *slot = ssa_name_hash.find_slot (a, INSERT);
if (!*slot)
*slot = a;
else
{
/* If the variable is a PARM_DECL or a RESULT_DECL, we
_require_ that all the names originating from it be
coalesced, because there must be a single partition
containing all the names so that it can be assigned
the canonical RTL location of the DECL safely.
If in_lto_p, a function could have been compiled
originally with optimizations and only the link
performed at -O0, so we can't actually require it. */
const int cost
= (TREE_CODE (SSA_NAME_VAR (a)) == VAR_DECL || in_lto_p)
? MUST_COALESCE_COST - 1 : MUST_COALESCE_COST;
add_coalesce (cl, SSA_NAME_VERSION (a),
SSA_NAME_VERSION (*slot), cost);
bitmap_set_bit (used_in_copy, SSA_NAME_VERSION (a));
bitmap_set_bit (used_in_copy, SSA_NAME_VERSION (*slot));
}
}
}
}
} }
...@@ -1384,13 +1417,15 @@ coalesce_partitions (var_map map, ssa_conflicts *graph, coalesce_list *cl, ...@@ -1384,13 +1417,15 @@ coalesce_partitions (var_map map, ssa_conflicts *graph, coalesce_list *cl,
gsi_next (&gsi)) gsi_next (&gsi))
{ {
gphi *phi = gsi.phi (); gphi *phi = gsi.phi ();
tree res = PHI_RESULT (phi);
if (virtual_operand_p (res))
continue;
tree arg = PHI_ARG_DEF (phi, e->dest_idx); tree arg = PHI_ARG_DEF (phi, e->dest_idx);
if (SSA_NAME_IS_DEFAULT_DEF (arg) if (SSA_NAME_IS_DEFAULT_DEF (arg)
&& (!SSA_NAME_VAR (arg) && (!SSA_NAME_VAR (arg)
|| TREE_CODE (SSA_NAME_VAR (arg)) != PARM_DECL)) || TREE_CODE (SSA_NAME_VAR (arg)) != PARM_DECL))
continue; continue;
tree res = PHI_RESULT (phi);
int v1 = SSA_NAME_VERSION (res); int v1 = SSA_NAME_VERSION (res);
int v2 = SSA_NAME_VERSION (arg); int v2 = SSA_NAME_VERSION (arg);
...@@ -1420,27 +1455,6 @@ coalesce_partitions (var_map map, ssa_conflicts *graph, coalesce_list *cl, ...@@ -1420,27 +1455,6 @@ coalesce_partitions (var_map map, ssa_conflicts *graph, coalesce_list *cl,
} }
/* Hashtable support for storing SSA names hashed by their SSA_NAME_VAR. */
struct ssa_name_var_hash : nofree_ptr_hash <tree_node>
{
static inline hashval_t hash (const tree_node *);
static inline int equal (const tree_node *, const tree_node *);
};
inline hashval_t
ssa_name_var_hash::hash (const_tree n)
{
return DECL_UID (SSA_NAME_VAR (n));
}
inline int
ssa_name_var_hash::equal (const tree_node *n1, const tree_node *n2)
{
return SSA_NAME_VAR (n1) == SSA_NAME_VAR (n2);
}
/* Output partition map MAP with coalescing plan PART to file F. */ /* Output partition map MAP with coalescing plan PART to file F. */
void void
...@@ -1629,8 +1643,9 @@ compute_optimized_partition_bases (var_map map, bitmap used_in_copies, ...@@ -1629,8 +1643,9 @@ compute_optimized_partition_bases (var_map map, bitmap used_in_copies,
/* And also with abnormal edges. */ /* And also with abnormal edges. */
basic_block bb; basic_block bb;
edge e; edge e;
unsigned i;
edge_iterator ei; edge_iterator ei;
FOR_EACH_BB_FN (bb, cfun) for (i = 0; map->vec_bbs.iterate (i, &bb); ++i)
{ {
FOR_EACH_EDGE (e, ei, bb->preds) FOR_EACH_EDGE (e, ei, bb->preds)
if (e->flags & EDGE_ABNORMAL) if (e->flags & EDGE_ABNORMAL)
...@@ -1640,14 +1655,15 @@ compute_optimized_partition_bases (var_map map, bitmap used_in_copies, ...@@ -1640,14 +1655,15 @@ compute_optimized_partition_bases (var_map map, bitmap used_in_copies,
gsi_next (&gsi)) gsi_next (&gsi))
{ {
gphi *phi = gsi.phi (); gphi *phi = gsi.phi ();
tree res = PHI_RESULT (phi);
if (virtual_operand_p (res))
continue;
tree arg = PHI_ARG_DEF (phi, e->dest_idx); tree arg = PHI_ARG_DEF (phi, e->dest_idx);
if (SSA_NAME_IS_DEFAULT_DEF (arg) if (SSA_NAME_IS_DEFAULT_DEF (arg)
&& (!SSA_NAME_VAR (arg) && (!SSA_NAME_VAR (arg)
|| TREE_CODE (SSA_NAME_VAR (arg)) != PARM_DECL)) || TREE_CODE (SSA_NAME_VAR (arg)) != PARM_DECL))
continue; continue;
tree res = PHI_RESULT (phi);
int p1 = partition_find (tentative, var_to_partition (map, res)); int p1 = partition_find (tentative, var_to_partition (map, res));
int p2 = partition_find (tentative, var_to_partition (map, arg)); int p2 = partition_find (tentative, var_to_partition (map, arg));
...@@ -1675,7 +1691,6 @@ compute_optimized_partition_bases (var_map map, bitmap used_in_copies, ...@@ -1675,7 +1691,6 @@ compute_optimized_partition_bases (var_map map, bitmap used_in_copies,
between all SSA versions that ended up in the same potential between all SSA versions that ended up in the same potential
coalesce partition. */ coalesce partition. */
bitmap_iterator bi; bitmap_iterator bi;
unsigned i;
EXECUTE_IF_SET_IN_BITMAP (used_in_copies, 0, i, bi) EXECUTE_IF_SET_IN_BITMAP (used_in_copies, 0, i, bi)
{ {
int pidx = var_to_partition (map, ssa_name (i)); int pidx = var_to_partition (map, ssa_name (i));
...@@ -1784,62 +1799,22 @@ compute_samebase_partition_bases (var_map map) ...@@ -1784,62 +1799,22 @@ compute_samebase_partition_bases (var_map map)
free (mapstorage); free (mapstorage);
} }
/* Reduce the number of copies by coalescing variables in the function. Return /* Given an initial var_map MAP, coalesce variables and return a partition map
a partition map with the resulting coalesces. */ with the resulting coalesce. Note that this function is called in either
live range computation context or out-of-ssa context, indicated by MAP. */
extern var_map extern void
coalesce_ssa_name (void) coalesce_ssa_name (var_map map)
{ {
tree_live_info_p liveinfo; tree_live_info_p liveinfo;
ssa_conflicts *graph; ssa_conflicts *graph;
coalesce_list *cl; coalesce_list *cl;
auto_bitmap used_in_copies; auto_bitmap used_in_copies;
var_map map;
unsigned int i;
tree a;
cl = create_coalesce_list (); cl = create_coalesce_list_for_region (map, used_in_copies);
map = create_outofssa_var_map (cl, used_in_copies); if (map->outofssa_p)
populate_coalesce_list_for_outofssa (cl, used_in_copies);
/* If this optimization is disabled, we need to coalesce all the
names originating from the same SSA_NAME_VAR so debug info
remains undisturbed. */
if (!flag_tree_coalesce_vars)
{
hash_table<ssa_name_var_hash> ssa_name_hash (10);
FOR_EACH_SSA_NAME (i, a, cfun)
{
if (SSA_NAME_VAR (a)
&& !DECL_IGNORED_P (SSA_NAME_VAR (a))
&& (!has_zero_uses (a) || !SSA_NAME_IS_DEFAULT_DEF (a)
|| !VAR_P (SSA_NAME_VAR (a))))
{
tree *slot = ssa_name_hash.find_slot (a, INSERT);
if (!*slot)
*slot = a;
else
{
/* If the variable is a PARM_DECL or a RESULT_DECL, we
_require_ that all the names originating from it be
coalesced, because there must be a single partition
containing all the names so that it can be assigned
the canonical RTL location of the DECL safely.
If in_lto_p, a function could have been compiled
originally with optimizations and only the link
performed at -O0, so we can't actually require it. */
const int cost
= (TREE_CODE (SSA_NAME_VAR (a)) == VAR_DECL || in_lto_p)
? MUST_COALESCE_COST - 1 : MUST_COALESCE_COST;
add_coalesce (cl, SSA_NAME_VERSION (a),
SSA_NAME_VERSION (*slot), cost);
bitmap_set_bit (used_in_copies, SSA_NAME_VERSION (a));
bitmap_set_bit (used_in_copies, SSA_NAME_VERSION (*slot));
}
}
}
}
if (dump_file && (dump_flags & TDF_DETAILS)) if (dump_file && (dump_flags & TDF_DETAILS))
dump_var_map (dump_file, map); dump_var_map (dump_file, map);
...@@ -1853,7 +1828,7 @@ coalesce_ssa_name (void) ...@@ -1853,7 +1828,7 @@ coalesce_ssa_name (void)
if (num_var_partitions (map) < 1) if (num_var_partitions (map) < 1)
{ {
delete_coalesce_list (cl); delete_coalesce_list (cl);
return map; return;
} }
if (dump_file && (dump_flags & TDF_DETAILS)) if (dump_file && (dump_flags & TDF_DETAILS))
...@@ -1890,75 +1865,5 @@ coalesce_ssa_name (void) ...@@ -1890,75 +1865,5 @@ coalesce_ssa_name (void)
delete_coalesce_list (cl); delete_coalesce_list (cl);
ssa_conflicts_delete (graph); ssa_conflicts_delete (graph);
return map;
} }
/* We need to pass two arguments to set_parm_default_def_partition,
but for_all_parms only supports one. Use a pair. */
typedef std::pair<var_map, bitmap> parm_default_def_partition_arg;
/* Set in ARG's PARTS bitmap the bit corresponding to the partition in
ARG's MAP containing VAR's default def. */
static void
set_parm_default_def_partition (tree var, void *arg_)
{
parm_default_def_partition_arg *arg = (parm_default_def_partition_arg *)arg_;
var_map map = arg->first;
bitmap parts = arg->second;
if (!is_gimple_reg (var))
return;
tree ssa = ssa_default_def (cfun, var);
gcc_assert (ssa);
int version = var_to_partition (map, ssa);
gcc_assert (version != NO_PARTITION);
bool changed = bitmap_set_bit (parts, version);
gcc_assert (changed);
}
/* Allocate and return a bitmap that has a bit set for each partition
that contains a default def for a parameter. */
bitmap
get_parm_default_def_partitions (var_map map)
{
bitmap parm_default_def_parts = BITMAP_ALLOC (NULL);
parm_default_def_partition_arg
arg = std::make_pair (map, parm_default_def_parts);
for_all_parms (set_parm_default_def_partition, &arg);
return parm_default_def_parts;
}
/* Allocate and return a bitmap that has a bit set for each partition
that contains an undefined value. */
bitmap
get_undefined_value_partitions (var_map map)
{
bitmap undefined_value_parts = BITMAP_ALLOC (NULL);
for (unsigned int i = 1; i < num_ssa_names; i++)
{
tree var = ssa_name (i);
if (var
&& !virtual_operand_p (var)
&& !has_zero_uses (var)
&& ssa_undefined_value_p (var))
{
const int p = var_to_partition (map, var);
if (p != NO_PARTITION)
bitmap_set_bit (undefined_value_parts, p);
}
}
return undefined_value_parts;
}
...@@ -20,9 +20,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -20,9 +20,7 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_TREE_SSA_COALESCE_H #ifndef GCC_TREE_SSA_COALESCE_H
#define GCC_TREE_SSA_COALESCE_H #define GCC_TREE_SSA_COALESCE_H
extern var_map coalesce_ssa_name (void); extern void coalesce_ssa_name (var_map);
extern bool gimple_can_coalesce_p (tree, tree); extern bool gimple_can_coalesce_p (tree, tree);
extern bitmap get_parm_default_def_partitions (var_map);
extern bitmap get_undefined_value_partitions (var_map);
#endif /* GCC_TREE_SSA_COALESCE_H */ #endif /* GCC_TREE_SSA_COALESCE_H */
...@@ -71,10 +71,12 @@ var_map_base_fini (var_map map) ...@@ -71,10 +71,12 @@ var_map_base_fini (var_map map)
map->num_basevars = 0; map->num_basevars = 0;
} }
} }
/* Create a variable partition map of SIZE, initialize and return it. */ /* Create a variable partition map of SIZE for region, initialize and return
it. Region is a loop if LOOP is non-NULL, otherwise is the current
function. */
var_map var_map
init_var_map (int size) init_var_map (int size, struct loop *loop)
{ {
var_map map; var_map map;
...@@ -87,6 +89,27 @@ init_var_map (int size) ...@@ -87,6 +89,27 @@ init_var_map (int size)
map->partition_size = size; map->partition_size = size;
map->num_basevars = 0; map->num_basevars = 0;
map->partition_to_base_index = NULL; map->partition_to_base_index = NULL;
map->vec_bbs = vNULL;
if (loop)
{
map->bmp_bbs = BITMAP_ALLOC (NULL);
map->outofssa_p = false;
basic_block *bbs = get_loop_body_in_dom_order (loop);
for (unsigned i = 0; i < loop->num_nodes; ++i)
{
bitmap_set_bit (map->bmp_bbs, bbs[i]->index);
map->vec_bbs.safe_push (bbs[i]);
}
free (bbs);
}
else
{
map->bmp_bbs = NULL;
map->outofssa_p = true;
basic_block bb;
FOR_EACH_BB_FN (bb, cfun)
map->vec_bbs.safe_push (bb);
}
return map; return map;
} }
...@@ -100,6 +123,9 @@ delete_var_map (var_map map) ...@@ -100,6 +123,9 @@ delete_var_map (var_map map)
partition_delete (map->var_partition); partition_delete (map->var_partition);
free (map->partition_to_view); free (map->partition_to_view);
free (map->view_to_partition); free (map->view_to_partition);
if (map->bmp_bbs)
BITMAP_FREE (map->bmp_bbs);
map->vec_bbs.release ();
free (map); free (map);
} }
...@@ -901,13 +927,14 @@ new_tree_live_info (var_map map) ...@@ -901,13 +927,14 @@ new_tree_live_info (var_map map)
bitmap_obstack_initialize (&live->livein_obstack); bitmap_obstack_initialize (&live->livein_obstack);
bitmap_obstack_initialize (&live->liveout_obstack); bitmap_obstack_initialize (&live->liveout_obstack);
live->livein = XNEWVEC (bitmap_head, last_basic_block_for_fn (cfun));
FOR_EACH_BB_FN (bb, cfun)
bitmap_initialize (&live->livein[bb->index], &live->livein_obstack);
live->liveout = XNEWVEC (bitmap_head, last_basic_block_for_fn (cfun)); live->livein = XCNEWVEC (bitmap_head, last_basic_block_for_fn (cfun));
FOR_EACH_BB_FN (bb, cfun) live->liveout = XCNEWVEC (bitmap_head, last_basic_block_for_fn (cfun));
bitmap_initialize (&live->liveout[bb->index], &live->liveout_obstack); for (unsigned i = 0; map->vec_bbs.iterate (i, &bb); ++i)
{
bitmap_initialize (&live->livein[bb->index], &live->livein_obstack);
bitmap_initialize (&live->liveout[bb->index], &live->liveout_obstack);
}
live->work_stack = XNEWVEC (int, last_basic_block_for_fn (cfun)); live->work_stack = XNEWVEC (int, last_basic_block_for_fn (cfun));
live->stack_top = live->work_stack; live->stack_top = live->work_stack;
...@@ -960,7 +987,7 @@ loe_visit_block (tree_live_info_p live, basic_block bb, sbitmap visited) ...@@ -960,7 +987,7 @@ loe_visit_block (tree_live_info_p live, basic_block bb, sbitmap visited)
FOR_EACH_EDGE (e, ei, bb->preds) FOR_EACH_EDGE (e, ei, bb->preds)
{ {
pred_bb = e->src; pred_bb = e->src;
if (pred_bb == ENTRY_BLOCK_PTR_FOR_FN (cfun)) if (!region_contains_p (live->map, pred_bb))
continue; continue;
/* Variables live-on-entry from BB that aren't defined in the /* Variables live-on-entry from BB that aren't defined in the
predecessor block. This should be the live on entry vars to pred. predecessor block. This should be the live on entry vars to pred.
...@@ -993,9 +1020,10 @@ live_worklist (tree_live_info_p live) ...@@ -993,9 +1020,10 @@ live_worklist (tree_live_info_p live)
bitmap_clear (visited); bitmap_clear (visited);
/* Visit all the blocks in reverse order and propagate live on entry values /* Visit region's blocks in reverse order and propagate live on entry values
into the predecessors blocks. */ into the predecessors blocks. */
FOR_EACH_BB_REVERSE_FN (bb, cfun) for (unsigned i = live->map->vec_bbs.length () - 1;
live->map->vec_bbs.iterate (i, &bb); --i)
loe_visit_block (live, bb, visited); loe_visit_block (live, bb, visited);
/* Process any blocks which require further iteration. */ /* Process any blocks which require further iteration. */
...@@ -1030,7 +1058,7 @@ set_var_live_on_entry (tree ssa_name, tree_live_info_p live) ...@@ -1030,7 +1058,7 @@ set_var_live_on_entry (tree ssa_name, tree_live_info_p live)
{ {
def_bb = gimple_bb (stmt); def_bb = gimple_bb (stmt);
/* Mark defs in liveout bitmap temporarily. */ /* Mark defs in liveout bitmap temporarily. */
if (def_bb) if (def_bb && region_contains_p (live->map, def_bb))
bitmap_set_bit (&live->liveout[def_bb->index], p); bitmap_set_bit (&live->liveout[def_bb->index], p);
} }
else else
...@@ -1054,11 +1082,8 @@ set_var_live_on_entry (tree ssa_name, tree_live_info_p live) ...@@ -1054,11 +1082,8 @@ set_var_live_on_entry (tree ssa_name, tree_live_info_p live)
defined in that block, or whether its live on entry. */ defined in that block, or whether its live on entry. */
int index = PHI_ARG_INDEX_FROM_USE (use); int index = PHI_ARG_INDEX_FROM_USE (use);
edge e = gimple_phi_arg_edge (as_a <gphi *> (use_stmt), index); edge e = gimple_phi_arg_edge (as_a <gphi *> (use_stmt), index);
if (e->src != ENTRY_BLOCK_PTR_FOR_FN (cfun)) if (e->src != def_bb && region_contains_p (live->map, e->src))
{ add_block = e->src;
if (e->src != def_bb)
add_block = e->src;
}
} }
else if (is_gimple_debug (use_stmt)) else if (is_gimple_debug (use_stmt))
continue; continue;
...@@ -1066,7 +1091,7 @@ set_var_live_on_entry (tree ssa_name, tree_live_info_p live) ...@@ -1066,7 +1091,7 @@ set_var_live_on_entry (tree ssa_name, tree_live_info_p live)
{ {
/* If its not defined in this block, its live on entry. */ /* If its not defined in this block, its live on entry. */
basic_block use_bb = gimple_bb (use_stmt); basic_block use_bb = gimple_bb (use_stmt);
if (use_bb != def_bb) if (use_bb != def_bb && region_contains_p (live->map, use_bb))
add_block = use_bb; add_block = use_bb;
} }
...@@ -1095,7 +1120,7 @@ calculate_live_on_exit (tree_live_info_p liveinfo) ...@@ -1095,7 +1120,7 @@ calculate_live_on_exit (tree_live_info_p liveinfo)
edge_iterator ei; edge_iterator ei;
/* live on entry calculations used liveout vectors for defs, clear them. */ /* live on entry calculations used liveout vectors for defs, clear them. */
FOR_EACH_BB_FN (bb, cfun) for (unsigned i = 0; liveinfo->map->vec_bbs.iterate (i, &bb); ++i)
bitmap_clear (&liveinfo->liveout[bb->index]); bitmap_clear (&liveinfo->liveout[bb->index]);
/* Set all the live-on-exit bits for uses in PHIs. */ /* Set all the live-on-exit bits for uses in PHIs. */
...@@ -1108,6 +1133,8 @@ calculate_live_on_exit (tree_live_info_p liveinfo) ...@@ -1108,6 +1133,8 @@ calculate_live_on_exit (tree_live_info_p liveinfo)
for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi)) for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
{ {
gphi *phi = gsi.phi (); gphi *phi = gsi.phi ();
if (virtual_operand_p (gimple_phi_result (phi)))
continue;
for (i = 0; i < gimple_phi_num_args (phi); i++) for (i = 0; i < gimple_phi_num_args (phi); i++)
{ {
tree t = PHI_ARG_DEF (phi, i); tree t = PHI_ARG_DEF (phi, i);
...@@ -1120,14 +1147,17 @@ calculate_live_on_exit (tree_live_info_p liveinfo) ...@@ -1120,14 +1147,17 @@ calculate_live_on_exit (tree_live_info_p liveinfo)
if (p == NO_PARTITION) if (p == NO_PARTITION)
continue; continue;
e = gimple_phi_arg_edge (phi, i); e = gimple_phi_arg_edge (phi, i);
if (e->src != ENTRY_BLOCK_PTR_FOR_FN (cfun)) if (region_contains_p (liveinfo->map, e->src))
bitmap_set_bit (&liveinfo->liveout[e->src->index], p); bitmap_set_bit (&liveinfo->liveout[e->src->index], p);
} }
} }
if (!region_contains_p (liveinfo->map, bb))
continue;
/* Add each successors live on entry to this bock live on exit. */ /* Add each successors live on entry to this bock live on exit. */
FOR_EACH_EDGE (e, ei, bb->succs) FOR_EACH_EDGE (e, ei, bb->succs)
if (e->dest != EXIT_BLOCK_PTR_FOR_FN (cfun)) if (region_contains_p (liveinfo->map, e->dest))
bitmap_ior_into (&liveinfo->liveout[bb->index], bitmap_ior_into (&liveinfo->liveout[bb->index],
live_on_entry (liveinfo, e->dest)); live_on_entry (liveinfo, e->dest));
} }
...@@ -1314,7 +1344,7 @@ verify_live_on_entry (tree_live_info_p live) ...@@ -1314,7 +1344,7 @@ verify_live_on_entry (tree_live_info_p live)
FOR_EACH_EDGE (e, ei, bb->succs) FOR_EACH_EDGE (e, ei, bb->succs)
{ {
int entry_block = e->dest->index; int entry_block = e->dest->index;
if (e->dest == EXIT_BLOCK_PTR_FOR_FN (cfun)) if (!region_contains_p (live->map, e->dest))
continue; continue;
for (i = 0; i < (unsigned)num_var_partitions (map); i++) for (i = 0; i < (unsigned)num_var_partitions (map); i++)
{ {
...@@ -1380,6 +1410,8 @@ verify_live_on_entry (tree_live_info_p live) ...@@ -1380,6 +1410,8 @@ verify_live_on_entry (tree_live_info_p live)
gsi_next (&gsi)) gsi_next (&gsi))
{ {
gphi *phi = gsi.phi (); gphi *phi = gsi.phi ();
if (virtual_operand_p (gimple_phi_result (phi)))
continue;
for (z = 0; z < gimple_phi_num_args (phi); z++) for (z = 0; z < gimple_phi_num_args (phi); z++)
if (var == gimple_phi_arg_def (phi, z)) if (var == gimple_phi_arg_def (phi, z))
{ {
......
...@@ -62,13 +62,25 @@ typedef struct _var_map ...@@ -62,13 +62,25 @@ typedef struct _var_map
/* Map of partitions numbers to base variable table indexes. */ /* Map of partitions numbers to base variable table indexes. */
int *partition_to_base_index; int *partition_to_base_index;
/* Bitmap of basic block. It describes the region within which the analysis
is done. Using pointer avoids allocating memory in out-of-ssa case. */
bitmap bmp_bbs;
/* Vector of basic block in the region. */
vec<basic_block> vec_bbs;
/* True if this map is for out-of-ssa, otherwise for live range
computation. When for out-of-ssa, it also means the var map is computed
for whole current function. */
bool outofssa_p;
} *var_map; } *var_map;
/* Value used to represent no partition number. */ /* Value used to represent no partition number. */
#define NO_PARTITION -1 #define NO_PARTITION -1
extern var_map init_var_map (int); extern var_map init_var_map (int, struct loop* = NULL);
extern void delete_var_map (var_map); extern void delete_var_map (var_map);
extern int var_union (var_map, tree, tree); extern int var_union (var_map, tree, tree);
extern void partition_view_normal (var_map); extern void partition_view_normal (var_map);
...@@ -82,6 +94,19 @@ extern void debug (_var_map &ref); ...@@ -82,6 +94,19 @@ extern void debug (_var_map &ref);
extern void debug (_var_map *ptr); extern void debug (_var_map *ptr);
/* Return TRUE if region of the MAP contains basic block BB. */
inline bool
region_contains_p (var_map map, basic_block bb)
{
/* It's possible that the function is called with ENTRY_BLOCK/EXIT_BLOCK. */
if (map->outofssa_p)
return (bb->index != ENTRY_BLOCK && bb->index != EXIT_BLOCK);
return bitmap_bit_p (map->bmp_bbs, bb->index);
}
/* Return number of partitions in MAP. */ /* Return number of partitions in MAP. */
static inline unsigned static inline unsigned
......
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