/* Generic SSA value propagation engine.
- Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
Contributed by Diego Novillo <dnovillo@redhat.com>
This file is part of GCC.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
- Software Foundation, 59 Temple Place - Suite 330, Boston, MA
- 02111-1307, USA. */
+ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
#include "config.h"
#include "system.h"
#include "ggc.h"
#include "basic-block.h"
#include "output.h"
-#include "errors.h"
#include "expr.h"
#include "function.h"
#include "diagnostic.h"
static sbitmap executable_blocks;
/* Array of control flow edges on the worklist. */
-static GTY(()) varray_type cfg_blocks = NULL;
+static VEC(basic_block,heap) *cfg_blocks;
static unsigned int cfg_blocks_num = 0;
static int cfg_blocks_tail;
else
{
cfg_blocks_num++;
- if (cfg_blocks_num > VARRAY_SIZE (cfg_blocks))
+ if (cfg_blocks_num > VEC_length (basic_block, cfg_blocks))
{
- /* We have to grow the array now. Adjust to queue to occupy the
- full space of the original array. */
- cfg_blocks_tail = VARRAY_SIZE (cfg_blocks);
+ /* We have to grow the array now. Adjust to queue to occupy
+ the full space of the original array. We do not need to
+ initialize the newly allocated portion of the array
+ because we keep track of CFG_BLOCKS_HEAD and
+ CFG_BLOCKS_HEAD. */
+ cfg_blocks_tail = VEC_length (basic_block, cfg_blocks);
cfg_blocks_head = 0;
- VARRAY_GROW (cfg_blocks, 2 * VARRAY_SIZE (cfg_blocks));
+ VEC_safe_grow (basic_block, heap, cfg_blocks, 2 * cfg_blocks_tail);
}
else
- cfg_blocks_tail = (cfg_blocks_tail + 1) % VARRAY_SIZE (cfg_blocks);
+ cfg_blocks_tail = ((cfg_blocks_tail + 1)
+ % VEC_length (basic_block, cfg_blocks));
}
- VARRAY_BB (cfg_blocks, cfg_blocks_tail) = bb;
+ VEC_replace (basic_block, cfg_blocks, cfg_blocks_tail, bb);
SET_BIT (bb_in_list, bb->index);
}
{
basic_block bb;
- bb = VARRAY_BB (cfg_blocks, cfg_blocks_head);
+ bb = VEC_index (basic_block, cfg_blocks, cfg_blocks_head);
gcc_assert (!cfg_blocks_empty_p ());
gcc_assert (bb);
- cfg_blocks_head = (cfg_blocks_head + 1) % VARRAY_SIZE (cfg_blocks);
+ cfg_blocks_head = ((cfg_blocks_head + 1)
+ % VEC_length (basic_block, cfg_blocks));
--cfg_blocks_num;
RESET_BIT (bb_in_list, bb->index);
if (dump_file && (dump_flags & TDF_DETAILS))
dump_immediate_uses (dump_file);
- VARRAY_BB_INIT (cfg_blocks, 20, "cfg_blocks");
+ cfg_blocks = VEC_alloc (basic_block, heap, 20);
+ VEC_safe_grow (basic_block, heap, cfg_blocks, 20);
/* Initialize the values for every SSA_NAME. */
for (i = 1; i < num_ssa_names; i++)
{
VEC_free (tree, gc, interesting_ssa_edges);
VEC_free (tree, gc, varying_ssa_edges);
+ VEC_free (basic_block, heap, cfg_blocks);
cfg_blocks = NULL;
sbitmap_free (bb_in_list);
sbitmap_free (executable_blocks);
break;
case COND_EXPR:
+ if (!is_gimple_condexpr (expr))
+ return false;
COND_EXPR_COND (stmt) = expr;
break;
case SWITCH_EXPR:
*stmt_p = TREE_SIDE_EFFECTS (expr) ? expr : build_empty_stmt ();
(*stmt_p)->common.ann = (tree_ann_t) ann;
- if (TREE_SIDE_EFFECTS (expr))
+ if (in_ssa_p
+ && TREE_SIDE_EFFECTS (expr))
{
/* Fix all the SSA_NAMEs created by *STMT_P to point to its new
replacement. */
{
long num_const_prop;
long num_copy_prop;
+ long num_pred_folded;
};
static struct prop_stats_d prop_stats;
replace_phi_args_in (tree phi, prop_value_t *prop_value)
{
int i;
+ bool replaced = false;
+ tree prev_phi = NULL;
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ prev_phi = unshare_expr (phi);
for (i = 0; i < PHI_NUM_ARGS (phi); i++)
{
prop_stats.num_copy_prop++;
propagate_value (PHI_ARG_DEF_PTR (phi, i), val);
+ replaced = true;
/* If we propagated a copy and this argument flows
through an abnormal edge, update the replacement
}
}
}
+
+ if (replaced && dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Folded PHI node: ");
+ print_generic_stmt (dump_file, prev_phi, TDF_SLIM);
+ fprintf (dump_file, " into: ");
+ print_generic_stmt (dump_file, phi, TDF_SLIM);
+ fprintf (dump_file, "\n");
+ }
+}
+
+
+/* If STMT has a predicate whose value can be computed using the value
+ range information computed by VRP, compute its value and return true.
+ Otherwise, return false. */
+
+static bool
+fold_predicate_in (tree stmt)
+{
+ tree *pred_p = NULL;
+ bool modify_expr_p = false;
+ tree val;
+
+ if (TREE_CODE (stmt) == MODIFY_EXPR
+ && COMPARISON_CLASS_P (TREE_OPERAND (stmt, 1)))
+ {
+ modify_expr_p = true;
+ pred_p = &TREE_OPERAND (stmt, 1);
+ }
+ else if (TREE_CODE (stmt) == COND_EXPR)
+ pred_p = &COND_EXPR_COND (stmt);
+ else
+ return false;
+
+ val = vrp_evaluate_conditional (*pred_p, true);
+ if (val)
+ {
+ if (modify_expr_p)
+ val = fold_convert (TREE_TYPE (*pred_p), val);
+
+ if (dump_file)
+ {
+ fprintf (dump_file, "Folding predicate ");
+ print_generic_expr (dump_file, *pred_p, 0);
+ fprintf (dump_file, " to ");
+ print_generic_expr (dump_file, val, 0);
+ fprintf (dump_file, "\n");
+ }
+
+ prop_stats.num_pred_folded++;
+ *pred_p = val;
+ return true;
+ }
+
+ return false;
}
-/* Perform final substitution and folding of propagated values. */
+/* Perform final substitution and folding of propagated values.
+
+ PROP_VALUE[I] contains the single value that should be substituted
+ at every use of SSA name N_I. If PROP_VALUE is NULL, no values are
+ substituted.
+
+ If USE_RANGES_P is true, statements that contain predicate
+ expressions are evaluated with a call to vrp_evaluate_conditional.
+ This will only give meaningful results when called from tree-vrp.c
+ (the information used by vrp_evaluate_conditional is built by the
+ VRP pass). */
void
-substitute_and_fold (prop_value_t *prop_value)
+substitute_and_fold (prop_value_t *prop_value, bool use_ranges_p)
{
basic_block bb;
+ if (prop_value == NULL && !use_ranges_p)
+ return;
+
if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file,
- "\nSubstituing values and folding statements\n\n");
+ fprintf (dump_file, "\nSubstituing values and folding statements\n\n");
memset (&prop_stats, 0, sizeof (prop_stats));
block_stmt_iterator i;
tree phi;
- /* Propagate our known values into PHI nodes. */
- for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
- {
- if (dump_file && (dump_flags & TDF_DETAILS))
- {
- fprintf (dump_file, "Replaced ");
- print_generic_stmt (dump_file, phi, TDF_SLIM);
- }
-
+ /* Propagate known values into PHI nodes. */
+ if (prop_value)
+ for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
replace_phi_args_in (phi, prop_value);
- if (dump_file && (dump_flags & TDF_DETAILS))
- {
- fprintf (dump_file, " with ");
- print_generic_stmt (dump_file, phi, TDF_SLIM);
- fprintf (dump_file, "\n");
- }
- }
-
for (i = bsi_start (bb); !bsi_end_p (i); bsi_next (&i))
{
bool replaced_address, did_replace;
+ tree prev_stmt = NULL;
tree stmt = bsi_stmt (i);
+ /* Ignore ASSERT_EXPRs. They are used by VRP to generate
+ range information for names and they are discarded
+ afterwards. */
+ if (TREE_CODE (stmt) == MODIFY_EXPR
+ && TREE_CODE (TREE_OPERAND (stmt, 1)) == ASSERT_EXPR)
+ continue;
+
/* Replace the statement with its folded version and mark it
folded. */
+ did_replace = false;
+ replaced_address = false;
if (dump_file && (dump_flags & TDF_DETAILS))
+ prev_stmt = unshare_expr (stmt);
+
+ /* If we have range information, see if we can fold
+ predicate expressions. */
+ if (use_ranges_p)
+ did_replace = fold_predicate_in (stmt);
+
+ if (prop_value)
{
- fprintf (dump_file, "Replaced ");
- print_generic_stmt (dump_file, stmt, TDF_SLIM);
+ /* Only replace real uses if we couldn't fold the
+ statement using value range information (value range
+ information is not collected on virtuals, so we only
+ need to check this for real uses). */
+ if (!did_replace)
+ did_replace |= replace_uses_in (stmt, &replaced_address,
+ prop_value);
+
+ did_replace |= replace_vuses_in (stmt, &replaced_address,
+ prop_value);
}
- replaced_address = false;
- did_replace = replace_uses_in (stmt, &replaced_address, prop_value);
- did_replace |= replace_vuses_in (stmt, &replaced_address, prop_value);
+ /* If we made a replacement, fold and cleanup the statement. */
if (did_replace)
{
tree old_stmt = stmt;
rhs = get_rhs (stmt);
if (TREE_CODE (rhs) == ADDR_EXPR)
- recompute_tree_invarant_for_addr_expr (rhs);
+ recompute_tree_invariant_for_addr_expr (rhs);
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Folded statement: ");
+ print_generic_stmt (dump_file, prev_stmt, TDF_SLIM);
+ fprintf (dump_file, " into: ");
+ print_generic_stmt (dump_file, stmt, TDF_SLIM);
+ fprintf (dump_file, "\n");
+ }
}
- if (dump_file && (dump_flags & TDF_DETAILS))
- {
- fprintf (dump_file, " with ");
- print_generic_stmt (dump_file, stmt, TDF_SLIM);
- fprintf (dump_file, "\n");
- }
+ /* Some statements may be simplified using ranges. For
+ example, division may be replaced by shifts, modulo
+ replaced with bitwise and, etc. Do this after
+ substituting constants, folding, etc so that we're
+ presented with a fully propagated, canonicalized
+ statement. */
+ if (use_ranges_p)
+ simplify_stmt_using_ranges (stmt);
+
}
}
prop_stats.num_const_prop);
fprintf (dump_file, "Copies propagated: %6ld\n",
prop_stats.num_copy_prop);
+ fprintf (dump_file, "Predicates folded: %6ld\n",
+ prop_stats.num_pred_folded);
}
}
+
#include "gt-tree-ssa-propagate.h"