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"
definition has changed. SSA edges are def-use edges in the SSA
web. For each D-U edge, we store the target statement or PHI node
U. */
-static GTY(()) VEC(tree) *interesting_ssa_edges;
+static GTY(()) VEC(tree,gc) *interesting_ssa_edges;
/* Identical to INTERESTING_SSA_EDGES. For performance reasons, the
list of SSA edges is split into two. One contains all SSA edges
don't use a separate worklist for VARYING edges, we end up with
situations where lattice values move from
UNDEFINED->INTERESTING->VARYING instead of UNDEFINED->VARYING. */
-static GTY(()) VEC(tree) *varying_ssa_edges;
+static GTY(()) VEC(tree,gc) *varying_ssa_edges;
/* Return true if the block worklist empty. */
{
STMT_IN_SSA_EDGE_WORKLIST (use_stmt) = 1;
if (is_varying)
- VEC_safe_push (tree, varying_ssa_edges, use_stmt);
+ VEC_safe_push (tree, gc, varying_ssa_edges, use_stmt);
else
- VEC_safe_push (tree, interesting_ssa_edges, use_stmt);
+ VEC_safe_push (tree, gc, interesting_ssa_edges, use_stmt);
}
}
}
SSA edge is added to it in simulate_stmt. */
static void
-process_ssa_edge_worklist (VEC(tree) **worklist)
+process_ssa_edge_worklist (VEC(tree,gc) **worklist)
{
/* Drain the entire worklist. */
while (VEC_length (tree, *worklist) > 0)
size_t i;
/* Worklists of SSA edges. */
- interesting_ssa_edges = VEC_alloc (tree, 20);
- varying_ssa_edges = VEC_alloc (tree, 20);
+ interesting_ssa_edges = VEC_alloc (tree, gc, 20);
+ varying_ssa_edges = VEC_alloc (tree, gc, 20);
executable_blocks = sbitmap_alloc (last_basic_block);
sbitmap_zero (executable_blocks);
static void
ssa_prop_fini (void)
{
- VEC_free (tree, interesting_ssa_edges);
- VEC_free (tree, varying_ssa_edges);
+ VEC_free (tree, gc, interesting_ssa_edges);
+ VEC_free (tree, gc, varying_ssa_edges);
cfg_blocks = NULL;
sbitmap_free (bb_in_list);
sbitmap_free (executable_blocks);
if (!is_gimple_val (TREE_OPERAND (expr, 0)))
return false;
}
+ else if (code == ADDR_EXPR)
+ {
+ if (TREE_CODE (TREE_OPERAND (expr, 0)) == ARRAY_REF
+ && !is_gimple_val (TREE_OPERAND (TREE_OPERAND (expr, 0), 1)))
+ return false;
+ }
else if (code == COMPOUND_EXPR)
return false;
break;
case COND_EXPR:
+ if (!is_gimple_condexpr (expr))
+ return false;
COND_EXPR_COND (stmt) = expr;
break;
case SWITCH_EXPR:
tree
first_vdef (tree stmt)
{
- if (NUM_V_MAY_DEFS (STMT_V_MAY_DEF_OPS (stmt)) > 0)
- return V_MAY_DEF_RESULT (STMT_V_MAY_DEF_OPS (stmt), 0);
- else if (NUM_V_MUST_DEFS (STMT_V_MUST_DEF_OPS (stmt)) > 0)
- return V_MUST_DEF_RESULT (STMT_V_MUST_DEF_OPS (stmt), 0);
- else
- gcc_unreachable ();
+ ssa_op_iter iter;
+ tree op;
+
+ /* Simply return the first operand we arrive at. */
+ FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_VIRTUAL_DEFS)
+ return (op);
+
+ gcc_unreachable ();
}
if (TREE_CODE (stmt) != MODIFY_EXPR)
return false;
- if (NUM_V_MAY_DEFS (STMT_V_MAY_DEF_OPS (stmt)) == 0
- && NUM_VUSES (STMT_VUSE_OPS (stmt)) == 0)
+ if (ZERO_SSA_OPERANDS (stmt, SSA_OP_VMAYDEF|SSA_OP_VUSE))
return false;
rhs = TREE_OPERAND (stmt, 1);
return (!TREE_THIS_VOLATILE (rhs)
&& (DECL_P (rhs)
- || TREE_CODE_CLASS (TREE_CODE (rhs)) == tcc_reference));
+ || REFERENCE_CLASS_P (rhs)));
}
if (TREE_CODE (stmt) != MODIFY_EXPR)
return false;
- if (NUM_V_MAY_DEFS (STMT_V_MAY_DEF_OPS (stmt)) == 0
- && NUM_V_MUST_DEFS (STMT_V_MUST_DEF_OPS (stmt)) == 0)
+ if (ZERO_SSA_OPERANDS (stmt, SSA_OP_VMAYDEF|SSA_OP_VMUSTDEF))
return false;
lhs = TREE_OPERAND (stmt, 0);
return (!TREE_THIS_VOLATILE (lhs)
&& (DECL_P (lhs)
- || TREE_CODE_CLASS (TREE_CODE (lhs)) == tcc_reference));
+ || REFERENCE_CLASS_P (lhs)));
}
{
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");
+ }
}
-/* Perform final substitution and folding of propagated values. */
+/* 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.
+
+ 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)
{
- fprintf (dump_file, "Replaced ");
- print_generic_stmt (dump_file, stmt, TDF_SLIM);
+ did_replace = fold_predicate_in (stmt);
+
+ /* Some statements may be simplified using ranges. For
+ example, division may be replaced by shifts, modulo
+ replaced with bitwise and, etc. */
+ simplify_stmt_using_ranges (stmt);
}
- replaced_address = false;
- did_replace = replace_uses_in (stmt, &replaced_address, prop_value);
- did_replace |= replace_vuses_in (stmt, &replaced_address, prop_value);
+ if (prop_value)
+ {
+ /* 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);
+ }
+
+ /* If we made a replacement, fold and cleanup the statement. */
if (did_replace)
{
+ tree old_stmt = stmt;
+ tree rhs;
+
fold_stmt (bsi_stmt_ptr (i));
- stmt = bsi_stmt(i);
+ stmt = bsi_stmt (i);
/* If we folded a builtin function, we'll likely
need to rename VDEFs. */
/* If we cleaned up EH information from the statement,
remove EH edges. */
- if (maybe_clean_eh_stmt (stmt))
+ if (maybe_clean_or_replace_eh_stmt (old_stmt, stmt))
tree_purge_dead_eh_edges (bb);
- }
- if (dump_file && (dump_flags & TDF_DETAILS))
- {
- fprintf (dump_file, " with ");
- print_generic_stmt (dump_file, stmt, TDF_SLIM);
- fprintf (dump_file, "\n");
+ rhs = get_rhs (stmt);
+ if (TREE_CODE (rhs) == ADDR_EXPR)
+ recompute_tree_invarant_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");
+ }
}
}
}
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"