summaryrefslogtreecommitdiff
path: root/gcc/tree-ssa-sink.c
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@baserock.org>2015-04-22 10:21:45 +0000
committer <>2015-04-25 21:44:09 +0000
commitf80b5ea1605c9f9408c5aa386ba71c16d918ebbf (patch)
treebb7eafaa81fc4b8c5c215bc08d517fd158db234a /gcc/tree-ssa-sink.c
parentc27a97d04853380f1e80525391b3f0d156ed4c84 (diff)
downloadgcc-tarball-f80b5ea1605c9f9408c5aa386ba71c16d918ebbf.tar.gz
Imported from /home/lorry/working-area/delta_gcc-tarball/gcc-5.1.0.tar.bz2.gcc-5.1.0
Diffstat (limited to 'gcc/tree-ssa-sink.c')
-rw-r--r--gcc/tree-ssa-sink.c215
1 files changed, 122 insertions, 93 deletions
diff --git a/gcc/tree-ssa-sink.c b/gcc/tree-ssa-sink.c
index 6d02975c4d..1ed8a0e367 100644
--- a/gcc/tree-ssa-sink.c
+++ b/gcc/tree-ssa-sink.c
@@ -1,5 +1,5 @@
/* Code sinking for trees
- Copyright (C) 2001-2014 Free Software Foundation, Inc.
+ Copyright (C) 2001-2015 Free Software Foundation, Inc.
Contributed by Daniel Berlin <dan@dberlin.org>
This file is part of GCC.
@@ -22,8 +22,25 @@ along with GCC; see the file COPYING3. If not see
#include "system.h"
#include "coretypes.h"
#include "tm.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "vec.h"
+#include "double-int.h"
+#include "input.h"
+#include "alias.h"
+#include "symtab.h"
+#include "wide-int.h"
+#include "inchash.h"
#include "tree.h"
+#include "fold-const.h"
#include "stor-layout.h"
+#include "predict.h"
+#include "hard-reg-set.h"
+#include "input.h"
+#include "function.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfganal.h"
#include "basic-block.h"
#include "gimple-pretty-print.h"
#include "tree-inline.h"
@@ -37,7 +54,6 @@ along with GCC; see the file COPYING3. If not see
#include "tree-cfg.h"
#include "tree-phinodes.h"
#include "ssa-iterators.h"
-#include "hashtab.h"
#include "tree-iterator.h"
#include "alloc-pool.h"
#include "tree-pass.h"
@@ -85,7 +101,7 @@ static struct
we return NULL. */
static basic_block
-find_bb_for_arg (gimple phi, tree def)
+find_bb_for_arg (gphi *phi, tree def)
{
size_t i;
bool foundone = false;
@@ -110,26 +126,22 @@ find_bb_for_arg (gimple phi, tree def)
used in, so that you only have one place you can sink it to. */
static bool
-all_immediate_uses_same_place (gimple stmt)
+all_immediate_uses_same_place (def_operand_p def_p)
{
- gimple firstuse = NULL;
- ssa_op_iter op_iter;
+ tree var = DEF_FROM_PTR (def_p);
imm_use_iterator imm_iter;
use_operand_p use_p;
- tree var;
- FOR_EACH_SSA_TREE_OPERAND (var, stmt, op_iter, SSA_OP_ALL_DEFS)
+ gimple firstuse = NULL;
+ FOR_EACH_IMM_USE_FAST (use_p, imm_iter, var)
{
- FOR_EACH_IMM_USE_FAST (use_p, imm_iter, var)
- {
- if (is_gimple_debug (USE_STMT (use_p)))
- continue;
- if (firstuse == NULL)
- firstuse = USE_STMT (use_p);
- else
- if (firstuse != USE_STMT (use_p))
- return false;
- }
+ if (is_gimple_debug (USE_STMT (use_p)))
+ continue;
+ if (firstuse == NULL)
+ firstuse = USE_STMT (use_p);
+ else
+ if (firstuse != USE_STMT (use_p))
+ return false;
}
return true;
@@ -138,49 +150,44 @@ all_immediate_uses_same_place (gimple stmt)
/* Find the nearest common dominator of all of the immediate uses in IMM. */
static basic_block
-nearest_common_dominator_of_uses (gimple stmt, bool *debug_stmts)
+nearest_common_dominator_of_uses (def_operand_p def_p, bool *debug_stmts)
{
+ tree var = DEF_FROM_PTR (def_p);
bitmap blocks = BITMAP_ALLOC (NULL);
basic_block commondom;
unsigned int j;
bitmap_iterator bi;
- ssa_op_iter op_iter;
imm_use_iterator imm_iter;
use_operand_p use_p;
- tree var;
- bitmap_clear (blocks);
- FOR_EACH_SSA_TREE_OPERAND (var, stmt, op_iter, SSA_OP_ALL_DEFS)
+ FOR_EACH_IMM_USE_FAST (use_p, imm_iter, var)
{
- FOR_EACH_IMM_USE_FAST (use_p, imm_iter, var)
- {
- gimple usestmt = USE_STMT (use_p);
- basic_block useblock;
+ gimple usestmt = USE_STMT (use_p);
+ basic_block useblock;
- if (gimple_code (usestmt) == GIMPLE_PHI)
- {
- int idx = PHI_ARG_INDEX_FROM_USE (use_p);
+ if (gphi *phi = dyn_cast <gphi *> (usestmt))
+ {
+ int idx = PHI_ARG_INDEX_FROM_USE (use_p);
- useblock = gimple_phi_arg_edge (usestmt, idx)->src;
- }
- else if (is_gimple_debug (usestmt))
- {
- *debug_stmts = true;
- continue;
- }
- else
- {
- useblock = gimple_bb (usestmt);
- }
+ useblock = gimple_phi_arg_edge (phi, idx)->src;
+ }
+ else if (is_gimple_debug (usestmt))
+ {
+ *debug_stmts = true;
+ continue;
+ }
+ else
+ {
+ useblock = gimple_bb (usestmt);
+ }
- /* Short circuit. Nothing dominates the entry block. */
- if (useblock == ENTRY_BLOCK_PTR_FOR_FN (cfun))
- {
- BITMAP_FREE (blocks);
- return NULL;
- }
- bitmap_set_bit (blocks, useblock->index);
+ /* Short circuit. Nothing dominates the entry block. */
+ if (useblock == ENTRY_BLOCK_PTR_FOR_FN (cfun))
+ {
+ BITMAP_FREE (blocks);
+ return NULL;
}
+ bitmap_set_bit (blocks, useblock->index);
}
commondom = BASIC_BLOCK_FOR_FN (cfun, bitmap_first_set_bit (blocks));
EXECUTE_IF_SET_IN_BITMAP (blocks, 0, j, bi)
@@ -294,8 +301,6 @@ statement_sink_location (gimple stmt, basic_block frombb,
be seen by an external routine that needs it depending on where it gets
moved to.
- We don't want to sink loads from memory.
-
We can't sink statements that end basic blocks without splitting the
incoming edge for the sink location to place it there.
@@ -313,7 +318,6 @@ statement_sink_location (gimple stmt, basic_block frombb,
if (stmt_ends_bb_p (stmt)
|| gimple_has_side_effects (stmt)
|| gimple_has_volatile_ops (stmt)
- || (gimple_vuse (stmt) && !gimple_vdef (stmt))
|| (cfun->has_local_explicit_reg_vars
&& TYPE_MODE (TREE_TYPE (gimple_assign_lhs (stmt))) == BLKmode))
return false;
@@ -332,7 +336,7 @@ statement_sink_location (gimple stmt, basic_block frombb,
/* If stmt is a store the one and only use needs to be the VOP
merging PHI node. */
- if (gimple_vdef (stmt))
+ if (virtual_operand_p (DEF_FROM_PTR (def_p)))
{
FOR_EACH_IMM_USE_FAST (use_p, imm_iter, DEF_FROM_PTR (def_p))
{
@@ -369,15 +373,56 @@ statement_sink_location (gimple stmt, basic_block frombb,
common dominator of all the immediate uses. For PHI nodes, we have to
find the nearest common dominator of all of the predecessor blocks, since
that is where insertion would have to take place. */
- else if (!all_immediate_uses_same_place (stmt))
+ else if (gimple_vuse (stmt)
+ || !all_immediate_uses_same_place (def_p))
{
bool debug_stmts = false;
- basic_block commondom = nearest_common_dominator_of_uses (stmt,
+ basic_block commondom = nearest_common_dominator_of_uses (def_p,
&debug_stmts);
if (commondom == frombb)
return false;
+ /* If this is a load then do not sink past any stores.
+ ??? This is overly simple but cheap. We basically look
+ for an existing load with the same VUSE in the path to one
+ of the sink candidate blocks and we adjust commondom to the
+ nearest to commondom. */
+ if (gimple_vuse (stmt))
+ {
+ /* Do not sink loads from hard registers. */
+ if (gimple_assign_single_p (stmt)
+ && TREE_CODE (gimple_assign_rhs1 (stmt)) == VAR_DECL
+ && DECL_HARD_REGISTER (gimple_assign_rhs1 (stmt)))
+ return false;
+
+ imm_use_iterator imm_iter;
+ use_operand_p use_p;
+ basic_block found = NULL;
+ FOR_EACH_IMM_USE_FAST (use_p, imm_iter, gimple_vuse (stmt))
+ {
+ gimple use_stmt = USE_STMT (use_p);
+ basic_block bb = gimple_bb (use_stmt);
+ /* For PHI nodes the block we know sth about
+ is the incoming block with the use. */
+ if (gimple_code (use_stmt) == GIMPLE_PHI)
+ bb = EDGE_PRED (bb, PHI_ARG_INDEX_FROM_USE (use_p))->src;
+ /* Any dominator of commondom would be ok with
+ adjusting commondom to that block. */
+ bb = nearest_common_dominator (CDI_DOMINATORS, bb, commondom);
+ if (!found)
+ found = bb;
+ else if (dominated_by_p (CDI_DOMINATORS, bb, found))
+ found = bb;
+ /* If we can't improve, stop. */
+ if (found == commondom)
+ break;
+ }
+ commondom = found;
+ if (commondom == frombb)
+ return false;
+ }
+
/* Our common dominator has to be dominated by frombb in order to be a
trivially safe place to put this statement, since it has multiple
uses. */
@@ -417,7 +462,7 @@ statement_sink_location (gimple stmt, basic_block frombb,
}
}
- sinkbb = find_bb_for_arg (use, DEF_FROM_PTR (def_p));
+ sinkbb = find_bb_for_arg (as_a <gphi *> (use), DEF_FROM_PTR (def_p));
/* This can happen if there are multiple uses in a PHI. */
if (!sinkbb)
@@ -563,37 +608,6 @@ sink_code_in_bb (basic_block bb)
Note that this reduces the number of computations of a = b + c to 1
when we take the else edge, instead of 2.
*/
-static void
-execute_sink_code (void)
-{
- loop_optimizer_init (LOOPS_NORMAL);
- split_critical_edges ();
- connect_infinite_loops_to_exit ();
- memset (&sink_stats, 0, sizeof (sink_stats));
- calculate_dominance_info (CDI_DOMINATORS);
- calculate_dominance_info (CDI_POST_DOMINATORS);
- sink_code_in_bb (EXIT_BLOCK_PTR_FOR_FN (cfun));
- statistics_counter_event (cfun, "Sunk statements", sink_stats.sunk);
- free_dominance_info (CDI_POST_DOMINATORS);
- remove_fake_exit_edges ();
- loop_optimizer_finalize ();
-}
-
-/* Gate and execute functions for PRE. */
-
-static unsigned int
-do_sink (void)
-{
- execute_sink_code ();
- return 0;
-}
-
-static bool
-gate_sink (void)
-{
- return flag_tree_sink != 0;
-}
-
namespace {
const pass_data pass_data_sink_code =
@@ -601,17 +615,14 @@ const pass_data pass_data_sink_code =
GIMPLE_PASS, /* type */
"sink", /* name */
OPTGROUP_NONE, /* optinfo_flags */
- true, /* has_gate */
- true, /* has_execute */
TV_TREE_SINK, /* tv_id */
/* PROP_no_crit_edges is ensured by running split_critical_edges in
- execute_sink_code. */
+ pass_data_sink_code::execute (). */
( PROP_cfg | PROP_ssa ), /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- ( TODO_update_ssa | TODO_verify_ssa
- | TODO_verify_flow ), /* todo_flags_finish */
+ TODO_update_ssa, /* todo_flags_finish */
};
class pass_sink_code : public gimple_opt_pass
@@ -622,11 +633,29 @@ public:
{}
/* opt_pass methods: */
- bool gate () { return gate_sink (); }
- unsigned int execute () { return do_sink (); }
+ virtual bool gate (function *) { return flag_tree_sink != 0; }
+ virtual unsigned int execute (function *);
}; // class pass_sink_code
+unsigned int
+pass_sink_code::execute (function *fun)
+{
+ loop_optimizer_init (LOOPS_NORMAL);
+ split_critical_edges ();
+ connect_infinite_loops_to_exit ();
+ memset (&sink_stats, 0, sizeof (sink_stats));
+ calculate_dominance_info (CDI_DOMINATORS);
+ calculate_dominance_info (CDI_POST_DOMINATORS);
+ sink_code_in_bb (EXIT_BLOCK_PTR_FOR_FN (fun));
+ statistics_counter_event (fun, "Sunk statements", sink_stats.sunk);
+ free_dominance_info (CDI_POST_DOMINATORS);
+ remove_fake_exit_edges ();
+ loop_optimizer_finalize ();
+
+ return 0;
+}
+
} // anon namespace
gimple_opt_pass *