X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Ftree-ssa-propagate.c;h=80b33e11d80ec16a77de893a5c29756f991559a7;hb=ab98db53d3e6829e061f862d9bcb9d695112f8ca;hp=d7243e9822676b77908e43074ea5c2a9848407ff;hpb=ce084dfc1cd60d867d38dbed86a914d82fa908d1;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/tree-ssa-propagate.c b/gcc/tree-ssa-propagate.c index d7243e98226..80b33e11d80 100644 --- a/gcc/tree-ssa-propagate.c +++ b/gcc/tree-ssa-propagate.c @@ -1,5 +1,5 @@ /* Generic SSA value propagation engine. - Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 + Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. Contributed by Diego Novillo @@ -28,9 +28,7 @@ #include "tm_p.h" #include "basic-block.h" #include "output.h" -#include "expr.h" #include "function.h" -#include "diagnostic.h" #include "gimple-pretty-print.h" #include "timevar.h" #include "tree-dump.h" @@ -603,20 +601,17 @@ valid_gimple_rhs_p (tree expr) } break; - case TRUTH_NOT_EXPR: - if (!is_gimple_val (TREE_OPERAND (expr, 0))) - return false; - break; - - case TRUTH_AND_EXPR: - case TRUTH_XOR_EXPR: - case TRUTH_OR_EXPR: - if (!is_gimple_val (TREE_OPERAND (expr, 0)) - || !is_gimple_val (TREE_OPERAND (expr, 1))) - return false; - break; - default: + if (get_gimple_rhs_class (code) == GIMPLE_TERNARY_RHS) + { + if (((code == VEC_COND_EXPR || code == COND_EXPR) + ? !is_gimple_condexpr (TREE_OPERAND (expr, 0)) + : !is_gimple_val (TREE_OPERAND (expr, 0))) + || !is_gimple_val (TREE_OPERAND (expr, 1)) + || !is_gimple_val (TREE_OPERAND (expr, 2))) + return false; + break; + } return false; } break; @@ -641,7 +636,7 @@ valid_gimple_rhs_p (tree expr) as a single GIMPLE_CALL statement. If the arguments require further gimplification, return false. */ -bool +static bool valid_gimple_call_p (tree expr) { unsigned i, nargs; @@ -651,8 +646,17 @@ valid_gimple_call_p (tree expr) nargs = call_expr_nargs (expr); for (i = 0; i < nargs; i++) - if (! is_gimple_operand (CALL_EXPR_ARG (expr, i))) - return false; + { + tree arg = CALL_EXPR_ARG (expr, i); + if (is_gimple_reg_type (arg)) + { + if (!is_gimple_val (arg)) + return false; + } + else + if (!is_gimple_lvalue (arg)) + return false; + } return true; } @@ -679,6 +683,40 @@ move_ssa_defining_stmt_for_defs (gimple new_stmt, gimple old_stmt) } } +/* Helper function for update_gimple_call and update_call_from_tree. + A GIMPLE_CALL STMT is being replaced with GIMPLE_CALL NEW_STMT. */ + +static void +finish_update_gimple_call (gimple_stmt_iterator *si_p, gimple new_stmt, + gimple stmt) +{ + gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt)); + move_ssa_defining_stmt_for_defs (new_stmt, stmt); + gimple_set_vuse (new_stmt, gimple_vuse (stmt)); + gimple_set_vdef (new_stmt, gimple_vdef (stmt)); + gimple_set_location (new_stmt, gimple_location (stmt)); + if (gimple_block (new_stmt) == NULL_TREE) + gimple_set_block (new_stmt, gimple_block (stmt)); + gsi_replace (si_p, new_stmt, false); +} + +/* Update a GIMPLE_CALL statement at iterator *SI_P to call to FN + with number of arguments NARGS, where the arguments in GIMPLE form + follow NARGS argument. */ + +bool +update_gimple_call (gimple_stmt_iterator *si_p, tree fn, int nargs, ...) +{ + va_list ap; + gimple new_stmt, stmt = gsi_stmt (*si_p); + + gcc_assert (is_gimple_call (stmt)); + va_start (ap, nargs); + new_stmt = gimple_build_call_valist (fn, nargs, ap); + finish_update_gimple_call (si_p, new_stmt, stmt); + va_end (ap); + return true; +} /* Update a GIMPLE_CALL statement at iterator *SI_P to reflect the value of EXPR, which is expected to be the result of folding the @@ -695,14 +733,8 @@ move_ssa_defining_stmt_for_defs (gimple new_stmt, gimple old_stmt) bool update_call_from_tree (gimple_stmt_iterator *si_p, tree expr) { - tree lhs; - gimple stmt = gsi_stmt (*si_p); - gcc_assert (is_gimple_call (stmt)); - - lhs = gimple_call_lhs (stmt); - if (valid_gimple_call_p (expr)) { /* The call has simplified to another call. */ @@ -722,18 +754,14 @@ update_call_from_tree (gimple_stmt_iterator *si_p, tree expr) } new_stmt = gimple_build_call_vec (fn, args); - gimple_call_set_lhs (new_stmt, lhs); - move_ssa_defining_stmt_for_defs (new_stmt, stmt); - gimple_set_vuse (new_stmt, gimple_vuse (stmt)); - gimple_set_vdef (new_stmt, gimple_vdef (stmt)); - gimple_set_location (new_stmt, gimple_location (stmt)); - gsi_replace (si_p, new_stmt, false); + finish_update_gimple_call (si_p, new_stmt, stmt); VEC_free (tree, heap, args); return true; } else if (valid_gimple_rhs_p (expr)) { + tree lhs = gimple_call_lhs (stmt); gimple new_stmt; /* The call has simplified to an expression @@ -753,8 +781,11 @@ update_call_from_tree (gimple_stmt_iterator *si_p, tree expr) /* No value is expected, and EXPR has no effect. Replace it with an empty statement. */ new_stmt = gimple_build_nop (); - unlink_stmt_vdef (stmt); - release_defs (stmt); + if (gimple_in_ssa_p (cfun)) + { + unlink_stmt_vdef (stmt); + release_defs (stmt); + } } else { @@ -766,7 +797,8 @@ update_call_from_tree (gimple_stmt_iterator *si_p, tree expr) lhs = create_tmp_var (TREE_TYPE (expr), NULL); new_stmt = gimple_build_assign (lhs, expr); add_referenced_var (lhs); - lhs = make_ssa_name (lhs, new_stmt); + if (gimple_in_ssa_p (cfun)) + lhs = make_ssa_name (lhs, new_stmt); gimple_assign_set_lhs (new_stmt, lhs); gimple_set_vuse (new_stmt, gimple_vuse (stmt)); gimple_set_vdef (new_stmt, gimple_vdef (stmt)); @@ -865,7 +897,7 @@ static struct prop_stats_d prop_stats; PROP_VALUE. Return true if at least one reference was replaced. */ static bool -replace_uses_in (gimple stmt, prop_value_t *prop_value) +replace_uses_in (gimple stmt, ssa_prop_get_value_fn get_value) { bool replaced = false; use_operand_p use; @@ -874,7 +906,7 @@ replace_uses_in (gimple stmt, prop_value_t *prop_value) FOR_EACH_SSA_USE_OPERAND (use, stmt, iter, SSA_OP_USE) { tree tuse = USE_FROM_PTR (use); - tree val = prop_value[SSA_NAME_VERSION (tuse)].value; + tree val = (*get_value) (tuse); if (val == tuse || val == NULL_TREE) continue; @@ -904,7 +936,7 @@ replace_uses_in (gimple stmt, prop_value_t *prop_value) values from PROP_VALUE. */ static void -replace_phi_args_in (gimple phi, prop_value_t *prop_value) +replace_phi_args_in (gimple phi, ssa_prop_get_value_fn get_value) { size_t i; bool replaced = false; @@ -921,7 +953,7 @@ replace_phi_args_in (gimple phi, prop_value_t *prop_value) if (TREE_CODE (arg) == SSA_NAME) { - tree val = prop_value[SSA_NAME_VERSION (arg)].value; + tree val = (*get_value) (arg); if (val && val != arg && may_propagate_copy (arg, val)) { @@ -966,15 +998,23 @@ replace_phi_args_in (gimple phi, prop_value_t *prop_value) If FOLD_FN is non-NULL the function will be invoked on all statements before propagating values for pass specific simplification. + DO_DCE is true if trivially dead stmts can be removed. + + If DO_DCE is true, the statements within a BB are walked from + last to first element. Otherwise we scan from first to last element. + Return TRUE when something changed. */ bool -substitute_and_fold (prop_value_t *prop_value, ssa_prop_fold_stmt_fn fold_fn) +substitute_and_fold (ssa_prop_get_value_fn get_value_fn, + ssa_prop_fold_stmt_fn fold_fn, + bool do_dce) { basic_block bb; bool something_changed = false; + unsigned i; - if (prop_value == NULL && !fold_fn) + if (!get_value_fn && !fold_fn) return false; if (dump_file && (dump_flags & TDF_DETAILS)) @@ -982,19 +1022,71 @@ substitute_and_fold (prop_value_t *prop_value, ssa_prop_fold_stmt_fn fold_fn) memset (&prop_stats, 0, sizeof (prop_stats)); - /* Substitute values in every statement of every basic block. */ + /* Substitute lattice values at definition sites. */ + if (get_value_fn) + for (i = 1; i < num_ssa_names; ++i) + { + tree name = ssa_name (i); + tree val; + gimple def_stmt; + gimple_stmt_iterator gsi; + + if (!name + || !is_gimple_reg (name)) + continue; + + def_stmt = SSA_NAME_DEF_STMT (name); + if (gimple_nop_p (def_stmt) + /* Do not substitute ASSERT_EXPR rhs, this will confuse VRP. */ + || (gimple_assign_single_p (def_stmt) + && gimple_assign_rhs_code (def_stmt) == ASSERT_EXPR) + || !(val = (*get_value_fn) (name)) + || !may_propagate_copy (name, val)) + continue; + + gsi = gsi_for_stmt (def_stmt); + if (is_gimple_assign (def_stmt)) + { + gimple_assign_set_rhs_with_ops (&gsi, TREE_CODE (val), + val, NULL_TREE); + gcc_assert (gsi_stmt (gsi) == def_stmt); + if (maybe_clean_eh_stmt (def_stmt)) + gimple_purge_dead_eh_edges (gimple_bb (def_stmt)); + update_stmt (def_stmt); + } + else if (is_gimple_call (def_stmt)) + { + if (update_call_from_tree (&gsi, val) + && maybe_clean_or_replace_eh_stmt (def_stmt, gsi_stmt (gsi))) + gimple_purge_dead_eh_edges (gimple_bb (gsi_stmt (gsi))); + } + else if (gimple_code (def_stmt) == GIMPLE_PHI) + { + gimple new_stmt = gimple_build_assign (name, val); + gimple_stmt_iterator gsi2; + SSA_NAME_DEF_STMT (name) = new_stmt; + gsi2 = gsi_after_labels (gimple_bb (def_stmt)); + gsi_insert_before (&gsi2, new_stmt, GSI_SAME_STMT); + remove_phi_node (&gsi, false); + } + + something_changed = true; + } + + /* Propagate into all uses and fold. */ FOR_EACH_BB (bb) { gimple_stmt_iterator i; /* Propagate known values into PHI nodes. */ - if (prop_value) + if (get_value_fn) for (i = gsi_start_phis (bb); !gsi_end_p (i); gsi_next (&i)) - replace_phi_args_in (gsi_stmt (i), prop_value); + replace_phi_args_in (gsi_stmt (i), get_value_fn); - /* Propagate known values into stmts. Do a backward walk to expose - more trivially deletable stmts. */ - for (i = gsi_last_bb (bb); !gsi_end_p (i);) + /* Propagate known values into stmts. Do a backward walk if + do_dce is true. In some case it exposes + more trivially deletable stmts to walk backward. */ + for (i = (do_dce ? gsi_last_bb (bb) : gsi_start_bb (bb)); !gsi_end_p (i);) { bool did_replace; gimple stmt = gsi_stmt (i); @@ -1003,7 +1095,10 @@ substitute_and_fold (prop_value_t *prop_value, ssa_prop_fold_stmt_fn fold_fn) gimple_stmt_iterator oldi; oldi = i; - gsi_prev (&i); + if (do_dce) + gsi_prev (&i); + else + gsi_next (&i); /* Ignore ASSERT_EXPRs. They are used by VRP to generate range information for names and they are discarded @@ -1014,8 +1109,12 @@ substitute_and_fold (prop_value_t *prop_value, ssa_prop_fold_stmt_fn fold_fn) continue; /* No point propagating into a stmt whose result is not used, - but instead we might be able to remove a trivially dead stmt. */ - if (gimple_get_lhs (stmt) + but instead we might be able to remove a trivially dead stmt. + Don't do this when called from VRP, since the SSA_NAME which + is going to be released could be still referenced in VRP + ranges. */ + if (do_dce + && gimple_get_lhs (stmt) && TREE_CODE (gimple_get_lhs (stmt)) == SSA_NAME && has_zero_uses (gimple_get_lhs (stmt)) && !stmt_could_throw_p (stmt) @@ -1055,13 +1154,13 @@ substitute_and_fold (prop_value_t *prop_value, ssa_prop_fold_stmt_fn fold_fn) { did_replace = true; prop_stats.num_stmts_folded++; + stmt = gsi_stmt (oldi); + update_stmt (stmt); } - /* Only replace real uses if we couldn't fold the - statement using value range information. */ - if (prop_value - && !did_replace) - did_replace |= replace_uses_in (stmt, prop_value); + /* Replace real uses in the statement. */ + if (get_value_fn) + did_replace |= replace_uses_in (stmt, get_value_fn); /* If we made a replacement, fold the statement. */ if (did_replace)