Commit 435fd407 by Jeff Law Committed by Jeff Law

tree-ssa-threadbackward.c (fsm_find_thread_path): Remove unneeded parameter.

	* tree-ssa-threadbackward.c (fsm_find_thread_path): Remove unneeded
	parameter.  Callers changed.
	(check-subpath_and_update_thread_path): Extracted from
	fsm_find_control_statement_thread_paths.
	(handle_phi, handle_assignment, handle_assignment_p): Likewise.
	(handle_phi, handle_assignment): Allow any constant node, not
	just INTEGER_CST.

From-SVN: r242431
parent 5a0e7889
2016-11-15 Jeff Law <law@redhat.com>
* tree-ssa-threadbackward.c (fsm_find_thread_path): Remove unneeded
parameter. Callers changed.
(check-subpath_and_update_thread_path): Extracted from
fsm_find_control_statement_thread_paths.
(handle_phi, handle_assignment, handle_assignment_p): Likewise.
(handle_phi, handle_assignment): Allow any constant node, not
just INTEGER_CST.
2016-11-15 Claudiu Zissulescu <claziss@synopsys.com> 2016-11-15 Claudiu Zissulescu <claziss@synopsys.com>
* config/arc/arc-arch.h: New file. * config/arc/arc-arch.h: New file.
...@@ -62,14 +62,12 @@ get_gimple_control_stmt (basic_block bb) ...@@ -62,14 +62,12 @@ get_gimple_control_stmt (basic_block bb)
/* Return true if the CFG contains at least one path from START_BB to END_BB. /* Return true if the CFG contains at least one path from START_BB to END_BB.
When a path is found, record in PATH the blocks from END_BB to START_BB. When a path is found, record in PATH the blocks from END_BB to START_BB.
VISITED_BBS is used to make sure we don't fall into an infinite loop. Bound VISITED_BBS is used to make sure we don't fall into an infinite loop. Bound
the recursion to basic blocks belonging to LOOP. the recursion to basic blocks belonging to LOOP. */
SPEED_P indicate that we could increase code size to improve the code path */
static bool static bool
fsm_find_thread_path (basic_block start_bb, basic_block end_bb, fsm_find_thread_path (basic_block start_bb, basic_block end_bb,
vec<basic_block, va_gc> *&path, vec<basic_block, va_gc> *&path,
hash_set<basic_block> *visited_bbs, loop_p loop, hash_set<basic_block> *visited_bbs, loop_p loop)
bool speed_p)
{ {
if (loop != start_bb->loop_father) if (loop != start_bb->loop_father)
return false; return false;
...@@ -85,8 +83,7 @@ fsm_find_thread_path (basic_block start_bb, basic_block end_bb, ...@@ -85,8 +83,7 @@ fsm_find_thread_path (basic_block start_bb, basic_block end_bb,
edge e; edge e;
edge_iterator ei; edge_iterator ei;
FOR_EACH_EDGE (e, ei, start_bb->succs) FOR_EACH_EDGE (e, ei, start_bb->succs)
if (fsm_find_thread_path (e->dest, end_bb, path, visited_bbs, loop, if (fsm_find_thread_path (e->dest, end_bb, path, visited_bbs, loop))
speed_p))
{ {
vec_safe_push (path, start_bb); vec_safe_push (path, start_bb);
return true; return true;
...@@ -427,6 +424,222 @@ convert_and_register_jump_thread_path (vec<basic_block, va_gc> *path, ...@@ -427,6 +424,222 @@ convert_and_register_jump_thread_path (vec<basic_block, va_gc> *path,
--max_threaded_paths; --max_threaded_paths;
} }
/* While following a chain of SSA_NAME definitions, we jumped from a definition
in LAST_BB to a definition in VAR_BB (walking backwards).
Verify there is a single path between the blocks and none of the blocks
in the path is already in VISITED_BBS. If so, then update VISISTED_BBS,
add the new blocks to PATH and return TRUE. Otherwise return FALSE.
Store the length of the subpath in NEXT_PATH_LENGTH. */
static bool
check_subpath_and_update_thread_path (basic_block last_bb, basic_block new_bb,
hash_set<basic_block> *visited_bbs,
vec<basic_block, va_gc> *&path,
int *next_path_length)
{
edge e;
int e_count = 0;
edge_iterator ei;
vec<basic_block, va_gc> *next_path;
vec_alloc (next_path, 10);
FOR_EACH_EDGE (e, ei, last_bb->preds)
{
hash_set<basic_block> *visited_bbs = new hash_set<basic_block>;
if (fsm_find_thread_path (new_bb, e->src, next_path, visited_bbs,
e->src->loop_father))
++e_count;
delete visited_bbs;
/* If there is more than one path, stop. */
if (e_count > 1)
{
vec_free (next_path);
return false;
}
}
/* Stop if we have not found a path: this could occur when the recursion
is stopped by one of the bounds. */
if (e_count == 0)
{
vec_free (next_path);
return false;
}
/* Make sure we haven't already visited any of the nodes in
NEXT_PATH. Don't add them here to avoid pollution. */
for (unsigned int i = 0; i < next_path->length () - 1; i++)
{
if (visited_bbs->contains ((*next_path)[i]))
{
vec_free (next_path);
return false;
}
}
/* Now add the nodes to VISISTED_BBS. */
for (unsigned int i = 0; i < next_path->length () - 1; i++)
visited_bbs->add ((*next_path)[i]);
/* Append all the nodes from NEXT_PATH to PATH. */
vec_safe_splice (path, next_path);
*next_path_length = next_path->length ();
vec_free (next_path);
return true;
}
static void fsm_find_control_statement_thread_paths (tree,
hash_set<basic_block> *,
vec<basic_block, va_gc> *&,
bool, bool);
/* Given PHI which defines NAME in block VAR_BB, recurse through the
PHI's arguments searching for paths where NAME will ultimately have
a constant value.
VISITED_BBS tracks the blocks that have been encountered.
PATH contains the series of blocks to traverse that will result in
NAME having a constant value.
SEEN_LOOP_PHI tracks if we have recursed through a loop PHI node.
SPEED_P indicates if we are optimizing for speed over space. */
static void
handle_phi (gphi *phi, tree name, basic_block var_bb,
hash_set<basic_block> *visited_bbs,
vec<basic_block, va_gc> *&path,
bool seen_loop_phi, bool speed_p)
{
/* Iterate over the arguments of PHI. */
for (unsigned int i = 0; i < gimple_phi_num_args (phi); i++)
{
tree arg = gimple_phi_arg_def (phi, i);
basic_block bbi = gimple_phi_arg_edge (phi, i)->src;
/* Skip edges pointing outside the current loop. */
if (!arg || var_bb->loop_father != bbi->loop_father)
continue;
if (TREE_CODE (arg) == SSA_NAME)
{
vec_safe_push (path, bbi);
/* Recursively follow SSA_NAMEs looking for a constant
definition. */
fsm_find_control_statement_thread_paths (arg, visited_bbs, path,
seen_loop_phi, speed_p);
path->pop ();
continue;
}
if (TREE_CODE_CLASS (TREE_CODE (arg)) != tcc_constant)
continue;
/* If this is a profitable jump thread path, then convert it
into the canonical form and register it. */
bool irreducible = false;
edge taken_edge = profitable_jump_thread_path (path, bbi, name, arg,
speed_p, &irreducible);
if (taken_edge)
{
convert_and_register_jump_thread_path (path, taken_edge);
path->pop ();
if (irreducible)
vect_free_loop_info_assumptions ((*path)[0]->loop_father);
}
}
}
/* Return TRUE if STMT is a gimple assignment we want to either directly
handle or recurse through. Return FALSE otherwise.
Note that adding more cases here requires adding cases to handle_assignment
below. */
static bool
handle_assignment_p (gimple *stmt)
{
if (is_gimple_assign (stmt))
{
enum tree_code def_code = gimple_assign_rhs_code (stmt);
/* If the RHS is an SSA_NAME, then we will recurse through it.
Go ahead and filter out cases where the SSA_NAME is a default
definition. There's little to be gained by trying to handle that. */
if (def_code == SSA_NAME
&& !SSA_NAME_IS_DEFAULT_DEF (gimple_assign_rhs1 (stmt)))
return true;
/* If the RHS is a constant, then it's a terminal that we'll want
to handle as well. */
if (TREE_CODE_CLASS (def_code) == tcc_constant)
return true;
}
/* Anything not explicitly allowed is not handled. */
return false;
}
/* Given STMT which defines NAME in block VAR_BB, recurse through the
PHI's arguments searching for paths where NAME will ultimately have
a constant value.
VISITED_BBS tracks the blocks that have been encountered.
PATH contains the series of blocks to traverse that will result in
NAME having a constant value.
SEEN_LOOP_PHI tracks if we have recursed through a loop PHI node.
SPEED_P indicates if we are optimizing for speed over space. */
static void
handle_assignment (gimple *stmt, tree name, basic_block var_bb,
hash_set<basic_block> *visited_bbs,
vec<basic_block, va_gc> *&path,
bool seen_loop_phi, bool speed_p)
{
tree arg = gimple_assign_rhs1 (stmt);
if (TREE_CODE (arg) == SSA_NAME)
fsm_find_control_statement_thread_paths (arg, visited_bbs,
path, seen_loop_phi, speed_p);
else
{
/* profitable_jump_thread_path is going to push the current
block onto the path. But the path will always have the current
block at this point. So we can just pop it. */
path->pop ();
bool irreducible = false;
edge taken_edge = profitable_jump_thread_path (path, var_bb,
name, arg, speed_p,
&irreducible);
if (taken_edge)
{
convert_and_register_jump_thread_path (path, taken_edge);
path->pop ();
if (irreducible)
vect_free_loop_info_assumptions ((*path)[0]->loop_father);
}
/* And put the current block back onto the path so that the
state of the stack is unchanged when we leave. */
vec_safe_push (path, var_bb);
}
}
/* We trace the value of the SSA_NAME NAME back through any phi nodes looking /* We trace the value of the SSA_NAME NAME back through any phi nodes looking
for places where it gets a constant value and save the path. Stop after for places where it gets a constant value and save the path. Stop after
having recorded MAX_PATHS jump threading paths. having recorded MAX_PATHS jump threading paths.
...@@ -461,9 +674,8 @@ fsm_find_control_statement_thread_paths (tree name, ...@@ -461,9 +674,8 @@ fsm_find_control_statement_thread_paths (tree name,
>= (unsigned) PARAM_VALUE (PARAM_FSM_MAXIMUM_PHI_ARGUMENTS))) >= (unsigned) PARAM_VALUE (PARAM_FSM_MAXIMUM_PHI_ARGUMENTS)))
return; return;
if (gimple_code (def_stmt) == GIMPLE_ASSIGN if (is_gimple_assign (def_stmt)
&& gimple_assign_rhs_code (def_stmt) != INTEGER_CST && ! handle_assignment_p (def_stmt))
&& gimple_assign_rhs_code (def_stmt) != SSA_NAME)
return; return;
/* Avoid infinite recursion. */ /* Avoid infinite recursion. */
...@@ -486,143 +698,25 @@ fsm_find_control_statement_thread_paths (tree name, ...@@ -486,143 +698,25 @@ fsm_find_control_statement_thread_paths (tree name,
different, append to PATH the blocks from LAST_BB_IN_PATH to VAR_BB. */ different, append to PATH the blocks from LAST_BB_IN_PATH to VAR_BB. */
if (var_bb != last_bb_in_path) if (var_bb != last_bb_in_path)
{ {
edge e;
int e_count = 0;
edge_iterator ei;
vec<basic_block, va_gc> *next_path;
vec_alloc (next_path, 10);
/* When VAR_BB == LAST_BB_IN_PATH, then the first block in the path /* When VAR_BB == LAST_BB_IN_PATH, then the first block in the path
will already be in VISITED_BBS. When they are not equal, then we will already be in VISITED_BBS. When they are not equal, then we
must ensure that first block is accounted for to ensure we do not must ensure that first block is accounted for to ensure we do not
create bogus jump threading paths. */ create bogus jump threading paths. */
visited_bbs->add ((*path)[0]); visited_bbs->add ((*path)[0]);
FOR_EACH_EDGE (e, ei, last_bb_in_path->preds) if (!check_subpath_and_update_thread_path (last_bb_in_path, var_bb,
{ visited_bbs, path,
hash_set<basic_block> *visited_bbs = new hash_set<basic_block>; &next_path_length))
return;
if (fsm_find_thread_path (var_bb, e->src, next_path, visited_bbs,
e->src->loop_father, speed_p))
++e_count;
delete visited_bbs;
/* If there is more than one path, stop. */
if (e_count > 1)
{
vec_free (next_path);
return;
}
}
/* Stop if we have not found a path: this could occur when the recursion
is stopped by one of the bounds. */
if (e_count == 0)
{
vec_free (next_path);
return;
}
/* Make sure we haven't already visited any of the nodes in
NEXT_PATH. Don't add them here to avoid pollution. */
for (unsigned int i = 0; i < next_path->length () - 1; i++)
{
if (visited_bbs->contains ((*next_path)[i]))
{
vec_free (next_path);
return;
}
}
/* Now add the nodes to VISISTED_BBS. */
for (unsigned int i = 0; i < next_path->length () - 1; i++)
visited_bbs->add ((*next_path)[i]);
/* Append all the nodes from NEXT_PATH to PATH. */
vec_safe_splice (path, next_path);
next_path_length = next_path->length ();
vec_free (next_path);
} }
gcc_assert (path->last () == var_bb); gcc_assert (path->last () == var_bb);
/* Iterate over the arguments of PHI. */
unsigned int i;
if (gimple_code (def_stmt) == GIMPLE_PHI) if (gimple_code (def_stmt) == GIMPLE_PHI)
{ handle_phi (as_a <gphi *> (def_stmt), name, var_bb,
gphi *phi = as_a <gphi *> (def_stmt); visited_bbs, path, seen_loop_phi, speed_p);
for (i = 0; i < gimple_phi_num_args (phi); i++)
{
tree arg = gimple_phi_arg_def (phi, i);
basic_block bbi = gimple_phi_arg_edge (phi, i)->src;
/* Skip edges pointing outside the current loop. */
if (!arg || var_bb->loop_father != bbi->loop_father)
continue;
if (TREE_CODE (arg) == SSA_NAME)
{
vec_safe_push (path, bbi);
/* Recursively follow SSA_NAMEs looking for a constant
definition. */
fsm_find_control_statement_thread_paths (arg, visited_bbs, path,
seen_loop_phi, speed_p);
path->pop ();
continue;
}
if (TREE_CODE (arg) != INTEGER_CST)
continue;
/* If this is a profitable jump thread path, then convert it
into the canonical form and register it. */
bool irreducible = false;
edge taken_edge = profitable_jump_thread_path (path, bbi, name, arg,
speed_p, &irreducible);
if (taken_edge)
{
convert_and_register_jump_thread_path (path, taken_edge);
path->pop ();
if (irreducible)
vect_free_loop_info_assumptions ((*path)[0]->loop_father);
}
}
}
else if (gimple_code (def_stmt) == GIMPLE_ASSIGN) else if (gimple_code (def_stmt) == GIMPLE_ASSIGN)
{ handle_assignment (def_stmt, name, var_bb,
tree arg = gimple_assign_rhs1 (def_stmt); visited_bbs, path, seen_loop_phi, speed_p);
if (TREE_CODE (arg) == SSA_NAME)
fsm_find_control_statement_thread_paths (arg, visited_bbs,
path, seen_loop_phi, speed_p);
else
{
/* profitable_jump_thread_path is going to push the current
block onto the path. But the path will always have the current
block at this point. So we can just pop it. */
path->pop ();
bool irreducible = false;
edge taken_edge = profitable_jump_thread_path (path, var_bb,
name, arg, speed_p,
&irreducible);
if (taken_edge)
{
convert_and_register_jump_thread_path (path, taken_edge);
path->pop ();
if (irreducible)
vect_free_loop_info_assumptions ((*path)[0]->loop_father);
}
/* And put the current block back onto the path so that the
state of the stack is unchanged when we leave. */
vec_safe_push (path, var_bb);
}
}
/* Remove all the nodes that we added from NEXT_PATH. */ /* Remove all the nodes that we added from NEXT_PATH. */
if (next_path_length) if (next_path_length)
...@@ -652,7 +746,7 @@ find_jump_threads_backwards (basic_block bb, bool speed_p) ...@@ -652,7 +746,7 @@ find_jump_threads_backwards (basic_block bb, bool speed_p)
else if (code == GIMPLE_COND) else if (code == GIMPLE_COND)
{ {
if (TREE_CODE (gimple_cond_lhs (stmt)) == SSA_NAME if (TREE_CODE (gimple_cond_lhs (stmt)) == SSA_NAME
&& TREE_CODE (gimple_cond_rhs (stmt)) == INTEGER_CST && TREE_CODE_CLASS (TREE_CODE (gimple_cond_rhs (stmt))) == tcc_constant
&& (INTEGRAL_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt))) && (INTEGRAL_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt)))
|| POINTER_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt))))) || POINTER_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt)))))
name = gimple_cond_lhs (stmt); name = gimple_cond_lhs (stmt);
......
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