[PATCH] Refactoring FSM bits into their own file
[PATCH] Refactoring FSM bits into their own file * tree-ssa-threadedge.c (fsm_find_thread_path): Moved from here into tree-ssa-threadbackward.c. (fsm_find_control_statement_thread_paths): Likewise. (thread_through_normal_block): Break out FSM bits and move them into a new function in tree-ssa-threadbackward.c. Call new function instead. Minimize header file usage. * tree-ssa-threadbackward.h: New file. * tree-ssa-threadbackward.c: Likewise. * Makefile.in (OBJS): Add tree-ssa-threadbackward.o From-SVN: r228700
This commit is contained in:
parent
f29dc665c7
commit
0732f75fce
|
@ -1,3 +1,16 @@
|
|||
2015-10-11 Jeff Law <law@redhat.com>
|
||||
|
||||
* tree-ssa-threadedge.c (fsm_find_thread_path): Moved from here into
|
||||
tree-ssa-threadbackward.c.
|
||||
(fsm_find_control_statement_thread_paths): Likewise.
|
||||
(thread_through_normal_block): Break out FSM bits and move them
|
||||
into a new function in tree-ssa-threadbackward.c. Call new function
|
||||
instead.
|
||||
Minimize header file usage.
|
||||
* tree-ssa-threadbackward.h: New file.
|
||||
* tree-ssa-threadbackward.c: Likewise.
|
||||
* Makefile.in (OBJS): Add tree-ssa-threadbackward.o
|
||||
|
||||
2015-10-11 Uros Bizjak <ubizjak@gmail.com>
|
||||
|
||||
* config/alpha/alpha.h (ALPHA_ROUND): Implement using ROUND_UP macro.
|
||||
|
|
|
@ -1478,6 +1478,7 @@ OBJS = \
|
|||
tree-ssa-structalias.o \
|
||||
tree-ssa-tail-merge.o \
|
||||
tree-ssa-ter.o \
|
||||
tree-ssa-threadbackward.o \
|
||||
tree-ssa-threadedge.o \
|
||||
tree-ssa-threadupdate.o \
|
||||
tree-ssa-uncprop.o \
|
||||
|
|
|
@ -0,0 +1,325 @@
|
|||
/* SSA Jump Threading
|
||||
Copyright (C) 2005-2015 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GCC; see the file COPYING3. If not see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "config.h"
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "backend.h"
|
||||
#include "predict.h"
|
||||
#include "tree.h"
|
||||
#include "gimple.h"
|
||||
#include "fold-const.h"
|
||||
#include "cfgloop.h"
|
||||
#include "gimple-iterator.h"
|
||||
#include "tree-cfg.h"
|
||||
#include "tree-ssa-threadupdate.h"
|
||||
#include "params.h"
|
||||
#include "tree-ssa-loop.h"
|
||||
#include "cfganal.h"
|
||||
#include "tree-pass.h"
|
||||
|
||||
static int max_threaded_paths;
|
||||
|
||||
/* 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.
|
||||
VISITED_BBS is used to make sure we don't fall into an infinite loop. Bound
|
||||
the recursion to basic blocks belonging to LOOP. */
|
||||
|
||||
static bool
|
||||
fsm_find_thread_path (basic_block start_bb, basic_block end_bb,
|
||||
vec<basic_block, va_gc> *&path,
|
||||
hash_set<basic_block> *visited_bbs, loop_p loop)
|
||||
{
|
||||
if (loop != start_bb->loop_father)
|
||||
return false;
|
||||
|
||||
if (start_bb == end_bb)
|
||||
{
|
||||
vec_safe_push (path, start_bb);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!visited_bbs->add (start_bb))
|
||||
{
|
||||
edge e;
|
||||
edge_iterator ei;
|
||||
FOR_EACH_EDGE (e, ei, start_bb->succs)
|
||||
if (fsm_find_thread_path (e->dest, end_bb, path, visited_bbs, loop))
|
||||
{
|
||||
vec_safe_push (path, start_bb);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* We trace the value of the variable EXPR back through any phi nodes looking
|
||||
for places where it gets a constant value and save the path. Stop after
|
||||
having recorded MAX_PATHS jump threading paths. */
|
||||
|
||||
static void
|
||||
fsm_find_control_statement_thread_paths (tree expr,
|
||||
hash_set<basic_block> *visited_bbs,
|
||||
vec<basic_block, va_gc> *&path,
|
||||
bool seen_loop_phi)
|
||||
{
|
||||
tree var = SSA_NAME_VAR (expr);
|
||||
gimple *def_stmt = SSA_NAME_DEF_STMT (expr);
|
||||
basic_block var_bb = gimple_bb (def_stmt);
|
||||
|
||||
if (var == NULL || var_bb == NULL)
|
||||
return;
|
||||
|
||||
/* For the moment we assume that an SSA chain only contains phi nodes, and
|
||||
eventually one of the phi arguments will be an integer constant. In the
|
||||
future, this could be extended to also handle simple assignments of
|
||||
arithmetic operations. */
|
||||
if (gimple_code (def_stmt) != GIMPLE_PHI)
|
||||
return;
|
||||
|
||||
/* Avoid infinite recursion. */
|
||||
if (visited_bbs->add (var_bb))
|
||||
return;
|
||||
|
||||
gphi *phi = as_a <gphi *> (def_stmt);
|
||||
int next_path_length = 0;
|
||||
basic_block last_bb_in_path = path->last ();
|
||||
|
||||
if (loop_containing_stmt (phi)->header == gimple_bb (phi))
|
||||
{
|
||||
/* Do not walk through more than one loop PHI node. */
|
||||
if (seen_loop_phi)
|
||||
return;
|
||||
seen_loop_phi = true;
|
||||
}
|
||||
|
||||
/* Following the chain of SSA_NAME definitions, we jumped from a definition in
|
||||
LAST_BB_IN_PATH to a definition in VAR_BB. When these basic blocks are
|
||||
different, append to PATH the blocks from LAST_BB_IN_PATH to VAR_BB. */
|
||||
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, n_basic_blocks_for_fn (cfun));
|
||||
|
||||
FOR_EACH_EDGE (e, ei, last_bb_in_path->preds)
|
||||
{
|
||||
hash_set<basic_block> *visited_bbs = new hash_set<basic_block>;
|
||||
|
||||
if (fsm_find_thread_path (var_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;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Iterate over the arguments of PHI. */
|
||||
unsigned int i;
|
||||
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);
|
||||
|
||||
path->pop ();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (TREE_CODE (arg) != INTEGER_CST)
|
||||
continue;
|
||||
|
||||
int path_length = path->length ();
|
||||
/* A path with less than 2 basic blocks should not be jump-threaded. */
|
||||
if (path_length < 2)
|
||||
continue;
|
||||
|
||||
if (path_length > PARAM_VALUE (PARAM_MAX_FSM_THREAD_LENGTH))
|
||||
{
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
fprintf (dump_file, "FSM jump-thread path not considered: "
|
||||
"the number of basic blocks on the path "
|
||||
"exceeds PARAM_MAX_FSM_THREAD_LENGTH.\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (max_threaded_paths <= 0)
|
||||
{
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
fprintf (dump_file, "FSM jump-thread path not considered: "
|
||||
"the number of previously recorded FSM paths to thread "
|
||||
"exceeds PARAM_MAX_FSM_THREAD_PATHS.\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Add BBI to the path. */
|
||||
vec_safe_push (path, bbi);
|
||||
++path_length;
|
||||
|
||||
int n_insns = 0;
|
||||
gimple_stmt_iterator gsi;
|
||||
int j;
|
||||
loop_p loop = (*path)[0]->loop_father;
|
||||
bool path_crosses_loops = false;
|
||||
|
||||
/* Count the number of instructions on the path: as these instructions
|
||||
will have to be duplicated, we will not record the path if there are
|
||||
too many instructions on the path. Also check that all the blocks in
|
||||
the path belong to a single loop. */
|
||||
for (j = 1; j < path_length - 1; j++)
|
||||
{
|
||||
basic_block bb = (*path)[j];
|
||||
|
||||
if (bb->loop_father != loop)
|
||||
{
|
||||
path_crosses_loops = true;
|
||||
break;
|
||||
}
|
||||
|
||||
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
|
||||
{
|
||||
gimple *stmt = gsi_stmt (gsi);
|
||||
/* Do not count empty statements and labels. */
|
||||
if (gimple_code (stmt) != GIMPLE_NOP
|
||||
&& gimple_code (stmt) != GIMPLE_LABEL
|
||||
&& !is_gimple_debug (stmt))
|
||||
++n_insns;
|
||||
}
|
||||
}
|
||||
|
||||
if (path_crosses_loops)
|
||||
{
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
fprintf (dump_file, "FSM jump-thread path not considered: "
|
||||
"the path crosses loops.\n");
|
||||
path->pop ();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (n_insns >= PARAM_VALUE (PARAM_MAX_FSM_THREAD_PATH_INSNS))
|
||||
{
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
fprintf (dump_file, "FSM jump-thread path not considered: "
|
||||
"the number of instructions on the path "
|
||||
"exceeds PARAM_MAX_FSM_THREAD_PATH_INSNS.\n");
|
||||
path->pop ();
|
||||
continue;
|
||||
}
|
||||
|
||||
vec<jump_thread_edge *> *jump_thread_path
|
||||
= new vec<jump_thread_edge *> ();
|
||||
|
||||
/* Record the edges between the blocks in PATH. */
|
||||
for (j = 0; j < path_length - 1; j++)
|
||||
{
|
||||
edge e = find_edge ((*path)[path_length - j - 1],
|
||||
(*path)[path_length - j - 2]);
|
||||
gcc_assert (e);
|
||||
jump_thread_edge *x = new jump_thread_edge (e, EDGE_FSM_THREAD);
|
||||
jump_thread_path->safe_push (x);
|
||||
}
|
||||
|
||||
/* Add the edge taken when the control variable has value ARG. */
|
||||
edge taken_edge = find_taken_edge ((*path)[0], arg);
|
||||
jump_thread_edge *x
|
||||
= new jump_thread_edge (taken_edge, EDGE_NO_COPY_SRC_BLOCK);
|
||||
jump_thread_path->safe_push (x);
|
||||
|
||||
register_jump_thread (jump_thread_path);
|
||||
--max_threaded_paths;
|
||||
|
||||
/* Remove BBI from the path. */
|
||||
path->pop ();
|
||||
}
|
||||
|
||||
/* Remove all the nodes that we added from NEXT_PATH. */
|
||||
if (next_path_length)
|
||||
vec_safe_truncate (path, (path->length () - next_path_length));
|
||||
}
|
||||
|
||||
/* Search backwards from BB looking for paths where NAME (an SSA_NAME)
|
||||
is a constant. Record such paths for jump threading.
|
||||
|
||||
It is assumed that BB ends with a control statement and that by
|
||||
finding a path where NAME is a constant, we can thread the path. */
|
||||
|
||||
void
|
||||
find_jump_threads_backwards (tree name, basic_block bb)
|
||||
{
|
||||
vec<basic_block, va_gc> *bb_path;
|
||||
vec_alloc (bb_path, n_basic_blocks_for_fn (cfun));
|
||||
vec_safe_push (bb_path, bb);
|
||||
hash_set<basic_block> *visited_bbs = new hash_set<basic_block>;
|
||||
|
||||
max_threaded_paths = PARAM_VALUE (PARAM_MAX_FSM_THREAD_PATHS);
|
||||
fsm_find_control_statement_thread_paths (name, visited_bbs, bb_path, false);
|
||||
|
||||
delete visited_bbs;
|
||||
vec_free (bb_path);
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/* Header file for SSA dominator optimizations.
|
||||
Copyright (C) 2013-2015 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 3, or (at your option) any later
|
||||
version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GCC; see the file COPYING3. If not see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef GCC_TREE_SSA_THREADFSM_H
|
||||
#define GCC_TREE_SSA_THREADFSM_H
|
||||
|
||||
extern void find_jump_threads_backwards (tree, basic_block);
|
||||
|
||||
#endif /* GCC_TREE_SSA_THREADFSM_H */
|
|
@ -25,28 +25,18 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "predict.h"
|
||||
#include "tree.h"
|
||||
#include "gimple.h"
|
||||
#include "hard-reg-set.h"
|
||||
#include "ssa.h"
|
||||
#include "alias.h"
|
||||
#include "fold-const.h"
|
||||
#include "flags.h"
|
||||
#include "tm_p.h"
|
||||
#include "cfgloop.h"
|
||||
#include "timevar.h"
|
||||
#include "dumpfile.h"
|
||||
#include "internal-fn.h"
|
||||
#include "gimple-iterator.h"
|
||||
#include "tree-cfg.h"
|
||||
#include "tree-ssa-propagate.h"
|
||||
#include "tree-ssa-threadupdate.h"
|
||||
#include "langhooks.h"
|
||||
#include "params.h"
|
||||
#include "tree-ssa-scopedtables.h"
|
||||
#include "tree-ssa-threadedge.h"
|
||||
#include "tree-ssa-loop.h"
|
||||
#include "tree-ssa-threadbackward.h"
|
||||
#include "tree-ssa-dom.h"
|
||||
#include "builtins.h"
|
||||
#include "cfganal.h"
|
||||
|
||||
/* To avoid code explosion due to jump threading, we limit the
|
||||
number of statements we are going to copy. This variable
|
||||
|
@ -894,275 +884,6 @@ thread_around_empty_blocks (edge taken_edge,
|
|||
return false;
|
||||
}
|
||||
|
||||
/* 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.
|
||||
VISITED_BBS is used to make sure we don't fall into an infinite loop. Bound
|
||||
the recursion to basic blocks belonging to LOOP. */
|
||||
|
||||
static bool
|
||||
fsm_find_thread_path (basic_block start_bb, basic_block end_bb,
|
||||
vec<basic_block, va_gc> *&path,
|
||||
hash_set<basic_block> *visited_bbs, loop_p loop)
|
||||
{
|
||||
if (loop != start_bb->loop_father)
|
||||
return false;
|
||||
|
||||
if (start_bb == end_bb)
|
||||
{
|
||||
vec_safe_push (path, start_bb);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!visited_bbs->add (start_bb))
|
||||
{
|
||||
edge e;
|
||||
edge_iterator ei;
|
||||
FOR_EACH_EDGE (e, ei, start_bb->succs)
|
||||
if (fsm_find_thread_path (e->dest, end_bb, path, visited_bbs, loop))
|
||||
{
|
||||
vec_safe_push (path, start_bb);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int max_threaded_paths;
|
||||
|
||||
/* We trace the value of the variable EXPR back through any phi nodes looking
|
||||
for places where it gets a constant value and save the path. Stop after
|
||||
having recorded MAX_PATHS jump threading paths. */
|
||||
|
||||
static void
|
||||
fsm_find_control_statement_thread_paths (tree expr,
|
||||
hash_set<basic_block> *visited_bbs,
|
||||
vec<basic_block, va_gc> *&path,
|
||||
bool seen_loop_phi)
|
||||
{
|
||||
tree var = SSA_NAME_VAR (expr);
|
||||
gimple *def_stmt = SSA_NAME_DEF_STMT (expr);
|
||||
basic_block var_bb = gimple_bb (def_stmt);
|
||||
|
||||
if (var == NULL || var_bb == NULL)
|
||||
return;
|
||||
|
||||
/* For the moment we assume that an SSA chain only contains phi nodes, and
|
||||
eventually one of the phi arguments will be an integer constant. In the
|
||||
future, this could be extended to also handle simple assignments of
|
||||
arithmetic operations. */
|
||||
if (gimple_code (def_stmt) != GIMPLE_PHI)
|
||||
return;
|
||||
|
||||
/* Avoid infinite recursion. */
|
||||
if (visited_bbs->add (var_bb))
|
||||
return;
|
||||
|
||||
gphi *phi = as_a <gphi *> (def_stmt);
|
||||
int next_path_length = 0;
|
||||
basic_block last_bb_in_path = path->last ();
|
||||
|
||||
if (loop_containing_stmt (phi)->header == gimple_bb (phi))
|
||||
{
|
||||
/* Do not walk through more than one loop PHI node. */
|
||||
if (seen_loop_phi)
|
||||
return;
|
||||
seen_loop_phi = true;
|
||||
}
|
||||
|
||||
/* Following the chain of SSA_NAME definitions, we jumped from a definition in
|
||||
LAST_BB_IN_PATH to a definition in VAR_BB. When these basic blocks are
|
||||
different, append to PATH the blocks from LAST_BB_IN_PATH to VAR_BB. */
|
||||
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, n_basic_blocks_for_fn (cfun));
|
||||
|
||||
FOR_EACH_EDGE (e, ei, last_bb_in_path->preds)
|
||||
{
|
||||
hash_set<basic_block> *visited_bbs = new hash_set<basic_block>;
|
||||
|
||||
if (fsm_find_thread_path (var_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;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Iterate over the arguments of PHI. */
|
||||
unsigned int i;
|
||||
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);
|
||||
|
||||
path->pop ();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (TREE_CODE (arg) != INTEGER_CST)
|
||||
continue;
|
||||
|
||||
int path_length = path->length ();
|
||||
/* A path with less than 2 basic blocks should not be jump-threaded. */
|
||||
if (path_length < 2)
|
||||
continue;
|
||||
|
||||
if (path_length > PARAM_VALUE (PARAM_MAX_FSM_THREAD_LENGTH))
|
||||
{
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
fprintf (dump_file, "FSM jump-thread path not considered: "
|
||||
"the number of basic blocks on the path "
|
||||
"exceeds PARAM_MAX_FSM_THREAD_LENGTH.\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (max_threaded_paths <= 0)
|
||||
{
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
fprintf (dump_file, "FSM jump-thread path not considered: "
|
||||
"the number of previously recorded FSM paths to thread "
|
||||
"exceeds PARAM_MAX_FSM_THREAD_PATHS.\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Add BBI to the path. */
|
||||
vec_safe_push (path, bbi);
|
||||
++path_length;
|
||||
|
||||
int n_insns = 0;
|
||||
gimple_stmt_iterator gsi;
|
||||
int j;
|
||||
loop_p loop = (*path)[0]->loop_father;
|
||||
bool path_crosses_loops = false;
|
||||
|
||||
/* Count the number of instructions on the path: as these instructions
|
||||
will have to be duplicated, we will not record the path if there are
|
||||
too many instructions on the path. Also check that all the blocks in
|
||||
the path belong to a single loop. */
|
||||
for (j = 1; j < path_length - 1; j++)
|
||||
{
|
||||
basic_block bb = (*path)[j];
|
||||
|
||||
if (bb->loop_father != loop)
|
||||
{
|
||||
path_crosses_loops = true;
|
||||
break;
|
||||
}
|
||||
|
||||
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
|
||||
{
|
||||
gimple *stmt = gsi_stmt (gsi);
|
||||
/* Do not count empty statements and labels. */
|
||||
if (gimple_code (stmt) != GIMPLE_NOP
|
||||
&& gimple_code (stmt) != GIMPLE_LABEL
|
||||
&& !is_gimple_debug (stmt))
|
||||
++n_insns;
|
||||
}
|
||||
}
|
||||
|
||||
if (path_crosses_loops)
|
||||
{
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
fprintf (dump_file, "FSM jump-thread path not considered: "
|
||||
"the path crosses loops.\n");
|
||||
path->pop ();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (n_insns >= PARAM_VALUE (PARAM_MAX_FSM_THREAD_PATH_INSNS))
|
||||
{
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
fprintf (dump_file, "FSM jump-thread path not considered: "
|
||||
"the number of instructions on the path "
|
||||
"exceeds PARAM_MAX_FSM_THREAD_PATH_INSNS.\n");
|
||||
path->pop ();
|
||||
continue;
|
||||
}
|
||||
|
||||
vec<jump_thread_edge *> *jump_thread_path
|
||||
= new vec<jump_thread_edge *> ();
|
||||
|
||||
/* Record the edges between the blocks in PATH. */
|
||||
for (j = 0; j < path_length - 1; j++)
|
||||
{
|
||||
edge e = find_edge ((*path)[path_length - j - 1],
|
||||
(*path)[path_length - j - 2]);
|
||||
gcc_assert (e);
|
||||
jump_thread_edge *x = new jump_thread_edge (e, EDGE_FSM_THREAD);
|
||||
jump_thread_path->safe_push (x);
|
||||
}
|
||||
|
||||
/* Add the edge taken when the control variable has value ARG. */
|
||||
edge taken_edge = find_taken_edge ((*path)[0], arg);
|
||||
jump_thread_edge *x
|
||||
= new jump_thread_edge (taken_edge, EDGE_NO_COPY_SRC_BLOCK);
|
||||
jump_thread_path->safe_push (x);
|
||||
|
||||
register_jump_thread (jump_thread_path);
|
||||
--max_threaded_paths;
|
||||
|
||||
/* Remove BBI from the path. */
|
||||
path->pop ();
|
||||
}
|
||||
|
||||
/* Remove all the nodes that we added from NEXT_PATH. */
|
||||
if (next_path_length)
|
||||
vec_safe_truncate (path, (path->length () - next_path_length));
|
||||
}
|
||||
|
||||
/* We are exiting E->src, see if E->dest ends with a conditional
|
||||
jump which has a known value when reached via E.
|
||||
|
||||
|
@ -1333,17 +1054,7 @@ thread_through_normal_block (edge e,
|
|||
/* When COND cannot be simplified, try to find paths from a control
|
||||
statement back through the PHI nodes which would affect that control
|
||||
statement. */
|
||||
vec<basic_block, va_gc> *bb_path;
|
||||
vec_alloc (bb_path, n_basic_blocks_for_fn (cfun));
|
||||
vec_safe_push (bb_path, e->dest);
|
||||
hash_set<basic_block> *visited_bbs = new hash_set<basic_block>;
|
||||
|
||||
max_threaded_paths = PARAM_VALUE (PARAM_MAX_FSM_THREAD_PATHS);
|
||||
fsm_find_control_statement_thread_paths (cond, visited_bbs, bb_path,
|
||||
false);
|
||||
|
||||
delete visited_bbs;
|
||||
vec_free (bb_path);
|
||||
find_jump_threads_backwards (cond, e->dest);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue