/* Generic SSA value propagation engine.
- Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010
+ Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
Free Software Foundation, Inc.
Contributed by Diego Novillo <dnovillo@redhat.com>
}
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;
}
}
+/* 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
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. */
}
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
/* 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
{
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));
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
}
else if (is_gimple_call (def_stmt))
{
+ int flags = gimple_call_flags (def_stmt);
+
+ /* Don't optimize away calls that have side-effects. */
+ if ((flags & (ECF_CONST|ECF_PURE)) == 0
+ || (flags & ECF_LOOPING_CONST_OR_PURE))
+ continue;
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)));
for (i = gsi_start_phis (bb); !gsi_end_p (i); gsi_next (&i))
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);
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
{
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 (get_value_fn
- && !did_replace)
+ /* 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. */