aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.8.1/gcc/tree-ssa-sink.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.8.1/gcc/tree-ssa-sink.c')
-rw-r--r--gcc-4.8.1/gcc/tree-ssa-sink.c611
1 files changed, 0 insertions, 611 deletions
diff --git a/gcc-4.8.1/gcc/tree-ssa-sink.c b/gcc-4.8.1/gcc/tree-ssa-sink.c
deleted file mode 100644
index 9f091748e..000000000
--- a/gcc-4.8.1/gcc/tree-ssa-sink.c
+++ /dev/null
@@ -1,611 +0,0 @@
-/* Code sinking for trees
- Copyright (C) 2001-2013 Free Software Foundation, Inc.
- Contributed by Daniel Berlin <dan@dberlin.org>
-
-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 "tm.h"
-#include "tree.h"
-#include "basic-block.h"
-#include "gimple-pretty-print.h"
-#include "tree-inline.h"
-#include "tree-flow.h"
-#include "gimple.h"
-#include "hashtab.h"
-#include "tree-iterator.h"
-#include "alloc-pool.h"
-#include "tree-pass.h"
-#include "flags.h"
-#include "bitmap.h"
-#include "cfgloop.h"
-#include "params.h"
-
-/* TODO:
- 1. Sinking store only using scalar promotion (IE without moving the RHS):
-
- *q = p;
- p = p + 1;
- if (something)
- *q = <not p>;
- else
- y = *q;
-
-
- should become
- sinktemp = p;
- p = p + 1;
- if (something)
- *q = <not p>;
- else
- {
- *q = sinktemp;
- y = *q
- }
- Store copy propagation will take care of the store elimination above.
-
-
- 2. Sinking using Partial Dead Code Elimination. */
-
-
-static struct
-{
- /* The number of statements sunk down the flowgraph by code sinking. */
- int sunk;
-
-} sink_stats;
-
-
-/* Given a PHI, and one of its arguments (DEF), find the edge for
- that argument and return it. If the argument occurs twice in the PHI node,
- we return NULL. */
-
-static basic_block
-find_bb_for_arg (gimple phi, tree def)
-{
- size_t i;
- bool foundone = false;
- basic_block result = NULL;
- for (i = 0; i < gimple_phi_num_args (phi); i++)
- if (PHI_ARG_DEF (phi, i) == def)
- {
- if (foundone)
- return NULL;
- foundone = true;
- result = gimple_phi_arg_edge (phi, i)->src;
- }
- return result;
-}
-
-/* When the first immediate use is in a statement, then return true if all
- immediate uses in IMM are in the same statement.
- We could also do the case where the first immediate use is in a phi node,
- and all the other uses are in phis in the same basic block, but this
- requires some expensive checking later (you have to make sure no def/vdef
- in the statement occurs for multiple edges in the various phi nodes it's
- used in, so that you only have one place you can sink it to. */
-
-static bool
-all_immediate_uses_same_place (gimple stmt)
-{
- gimple firstuse = NULL;
- ssa_op_iter op_iter;
- 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)
- {
- 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;
- }
- }
-
- return true;
-}
-
-/* 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)
-{
- 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)
- {
- gimple usestmt = USE_STMT (use_p);
- basic_block useblock;
-
- if (gimple_code (usestmt) == GIMPLE_PHI)
- {
- 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);
- }
-
- /* Short circuit. Nothing dominates the entry block. */
- if (useblock == ENTRY_BLOCK_PTR)
- {
- BITMAP_FREE (blocks);
- return NULL;
- }
- bitmap_set_bit (blocks, useblock->index);
- }
- }
- commondom = BASIC_BLOCK (bitmap_first_set_bit (blocks));
- EXECUTE_IF_SET_IN_BITMAP (blocks, 0, j, bi)
- commondom = nearest_common_dominator (CDI_DOMINATORS, commondom,
- BASIC_BLOCK (j));
- BITMAP_FREE (blocks);
- return commondom;
-}
-
-/* Given EARLY_BB and LATE_BB, two blocks in a path through the dominator
- tree, return the best basic block between them (inclusive) to place
- statements.
-
- We want the most control dependent block in the shallowest loop nest.
-
- If the resulting block is in a shallower loop nest, then use it. Else
- only use the resulting block if it has significantly lower execution
- frequency than EARLY_BB to avoid gratutious statement movement. We
- consider statements with VOPS more desirable to move.
-
- This pass would obviously benefit from PDO as it utilizes block
- frequencies. It would also benefit from recomputing frequencies
- if profile data is not available since frequencies often get out
- of sync with reality. */
-
-static basic_block
-select_best_block (basic_block early_bb,
- basic_block late_bb,
- gimple stmt)
-{
- basic_block best_bb = late_bb;
- basic_block temp_bb = late_bb;
- int threshold;
-
- while (temp_bb != early_bb)
- {
- /* If we've moved into a lower loop nest, then that becomes
- our best block. */
- if (bb_loop_depth (temp_bb) < bb_loop_depth (best_bb))
- best_bb = temp_bb;
-
- /* Walk up the dominator tree, hopefully we'll find a shallower
- loop nest. */
- temp_bb = get_immediate_dominator (CDI_DOMINATORS, temp_bb);
- }
-
- /* If we found a shallower loop nest, then we always consider that
- a win. This will always give us the most control dependent block
- within that loop nest. */
- if (bb_loop_depth (best_bb) < bb_loop_depth (early_bb))
- return best_bb;
-
- /* Get the sinking threshold. If the statement to be moved has memory
- operands, then increase the threshold by 7% as those are even more
- profitable to avoid, clamping at 100%. */
- threshold = PARAM_VALUE (PARAM_SINK_FREQUENCY_THRESHOLD);
- if (gimple_vuse (stmt) || gimple_vdef (stmt))
- {
- threshold += 7;
- if (threshold > 100)
- threshold = 100;
- }
-
- /* If BEST_BB is at the same nesting level, then require it to have
- significantly lower execution frequency to avoid gratutious movement. */
- if (bb_loop_depth (best_bb) == bb_loop_depth (early_bb)
- && best_bb->frequency < (early_bb->frequency * threshold / 100.0))
- return best_bb;
-
- /* No better block found, so return EARLY_BB, which happens to be the
- statement's original block. */
- return early_bb;
-}
-
-/* Given a statement (STMT) and the basic block it is currently in (FROMBB),
- determine the location to sink the statement to, if any.
- Returns true if there is such location; in that case, TOGSI points to the
- statement before that STMT should be moved. */
-
-static bool
-statement_sink_location (gimple stmt, basic_block frombb,
- gimple_stmt_iterator *togsi)
-{
- gimple use;
- use_operand_p one_use = NULL_USE_OPERAND_P;
- basic_block sinkbb;
- use_operand_p use_p;
- def_operand_p def_p;
- ssa_op_iter iter;
- imm_use_iterator imm_iter;
-
- /* We only can sink assignments. */
- if (!is_gimple_assign (stmt))
- return false;
-
- /* We only can sink stmts with a single definition. */
- def_p = single_ssa_def_operand (stmt, SSA_OP_ALL_DEFS);
- if (def_p == NULL_DEF_OPERAND_P)
- return false;
-
- /* Return if there are no immediate uses of this stmt. */
- if (has_zero_uses (DEF_FROM_PTR (def_p)))
- return false;
-
- /* There are a few classes of things we can't or don't move, some because we
- don't have code to handle it, some because it's not profitable and some
- because it's not legal.
-
- We can't sink things that may be global stores, at least not without
- calculating a lot more information, because we may cause it to no longer
- 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.
-
- We can't sink statements that have volatile operands.
-
- We don't want to sink dead code, so anything with 0 immediate uses is not
- sunk.
-
- Don't sink BLKmode assignments if current function has any local explicit
- register variables, as BLKmode assignments may involve memcpy or memset
- calls or, on some targets, inline expansion thereof that sometimes need
- to use specific hard registers.
-
- */
- 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;
-
- if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (DEF_FROM_PTR (def_p)))
- return false;
-
- FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_ALL_USES)
- {
- tree use = USE_FROM_PTR (use_p);
- if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (use))
- return false;
- }
-
- use = NULL;
-
- /* If stmt is a store the one and only use needs to be the VOP
- merging PHI node. */
- if (gimple_vdef (stmt))
- {
- FOR_EACH_IMM_USE_FAST (use_p, imm_iter, DEF_FROM_PTR (def_p))
- {
- gimple use_stmt = USE_STMT (use_p);
-
- /* A killing definition is not a use. */
- if (gimple_assign_single_p (use_stmt)
- && gimple_vdef (use_stmt)
- && operand_equal_p (gimple_assign_lhs (stmt),
- gimple_assign_lhs (use_stmt), 0))
- {
- /* If use_stmt is or might be a nop assignment then USE_STMT
- acts as a use as well as definition. */
- if (stmt != use_stmt
- && ref_maybe_used_by_stmt_p (use_stmt,
- gimple_assign_lhs (stmt)))
- return false;
- continue;
- }
-
- if (gimple_code (use_stmt) != GIMPLE_PHI)
- return false;
-
- if (use
- && use != use_stmt)
- return false;
-
- use = use_stmt;
- }
- if (!use)
- return false;
- }
- /* If all the immediate uses are not in the same place, find the nearest
- 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))
- {
- bool debug_stmts = false;
- basic_block commondom = nearest_common_dominator_of_uses (stmt,
- &debug_stmts);
-
- 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. */
- if (!dominated_by_p (CDI_DOMINATORS, commondom, frombb))
- return false;
-
- commondom = select_best_block (frombb, commondom, stmt);
-
- if (commondom == frombb)
- return false;
-
- *togsi = gsi_after_labels (commondom);
-
- return true;
- }
- else
- {
- FOR_EACH_IMM_USE_FAST (one_use, imm_iter, DEF_FROM_PTR (def_p))
- {
- if (is_gimple_debug (USE_STMT (one_use)))
- continue;
- break;
- }
- use = USE_STMT (one_use);
-
- if (gimple_code (use) != GIMPLE_PHI)
- {
- sinkbb = gimple_bb (use);
- sinkbb = select_best_block (frombb, gimple_bb (use), stmt);
-
- if (sinkbb == frombb)
- return false;
-
- *togsi = gsi_for_stmt (use);
-
- return true;
- }
- }
-
- sinkbb = find_bb_for_arg (use, DEF_FROM_PTR (def_p));
-
- /* This can happen if there are multiple uses in a PHI. */
- if (!sinkbb)
- return false;
-
- sinkbb = select_best_block (frombb, sinkbb, stmt);
- if (!sinkbb || sinkbb == frombb)
- return false;
-
- /* If the latch block is empty, don't make it non-empty by sinking
- something into it. */
- if (sinkbb == frombb->loop_father->latch
- && empty_block_p (sinkbb))
- return false;
-
- *togsi = gsi_after_labels (sinkbb);
-
- return true;
-}
-
-/* Perform code sinking on BB */
-
-static void
-sink_code_in_bb (basic_block bb)
-{
- basic_block son;
- gimple_stmt_iterator gsi;
- edge_iterator ei;
- edge e;
- bool last = true;
-
- /* If this block doesn't dominate anything, there can't be any place to sink
- the statements to. */
- if (first_dom_son (CDI_DOMINATORS, bb) == NULL)
- goto earlyout;
-
- /* We can't move things across abnormal edges, so don't try. */
- FOR_EACH_EDGE (e, ei, bb->succs)
- if (e->flags & EDGE_ABNORMAL)
- goto earlyout;
-
- for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi);)
- {
- gimple stmt = gsi_stmt (gsi);
- gimple_stmt_iterator togsi;
-
- if (!statement_sink_location (stmt, bb, &togsi))
- {
- if (!gsi_end_p (gsi))
- gsi_prev (&gsi);
- last = false;
- continue;
- }
- if (dump_file)
- {
- fprintf (dump_file, "Sinking ");
- print_gimple_stmt (dump_file, stmt, 0, TDF_VOPS);
- fprintf (dump_file, " from bb %d to bb %d\n",
- bb->index, (gsi_bb (togsi))->index);
- }
-
- /* Update virtual operands of statements in the path we
- do not sink to. */
- if (gimple_vdef (stmt))
- {
- imm_use_iterator iter;
- use_operand_p use_p;
- gimple vuse_stmt;
-
- FOR_EACH_IMM_USE_STMT (vuse_stmt, iter, gimple_vdef (stmt))
- if (gimple_code (vuse_stmt) != GIMPLE_PHI)
- FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
- SET_USE (use_p, gimple_vuse (stmt));
- }
-
- /* If this is the end of the basic block, we need to insert at the end
- of the basic block. */
- if (gsi_end_p (togsi))
- gsi_move_to_bb_end (&gsi, gsi_bb (togsi));
- else
- gsi_move_before (&gsi, &togsi);
-
- sink_stats.sunk++;
-
- /* If we've just removed the last statement of the BB, the
- gsi_end_p() test below would fail, but gsi_prev() would have
- succeeded, and we want it to succeed. So we keep track of
- whether we're at the last statement and pick up the new last
- statement. */
- if (last)
- {
- gsi = gsi_last_bb (bb);
- continue;
- }
-
- last = false;
- if (!gsi_end_p (gsi))
- gsi_prev (&gsi);
-
- }
- earlyout:
- for (son = first_dom_son (CDI_POST_DOMINATORS, bb);
- son;
- son = next_dom_son (CDI_POST_DOMINATORS, son))
- {
- sink_code_in_bb (son);
- }
-}
-
-/* Perform code sinking.
- This moves code down the flowgraph when we know it would be
- profitable to do so, or it wouldn't increase the number of
- executions of the statement.
-
- IE given
-
- a_1 = b + c;
- if (<something>)
- {
- }
- else
- {
- foo (&b, &c);
- a_5 = b + c;
- }
- a_6 = PHI (a_5, a_1);
- USE a_6.
-
- we'll transform this into:
-
- if (<something>)
- {
- a_1 = b + c;
- }
- else
- {
- foo (&b, &c);
- a_5 = b + c;
- }
- a_6 = PHI (a_5, a_1);
- USE a_6.
-
- 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);
-
- 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);
- 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;
-}
-
-struct gimple_opt_pass pass_sink_code =
-{
- {
- GIMPLE_PASS,
- "sink", /* name */
- OPTGROUP_NONE, /* optinfo_flags */
- gate_sink, /* gate */
- do_sink, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_TREE_SINK, /* tv_id */
- PROP_no_crit_edges | 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_ggc_collect /* todo_flags_finish */
- }
-};