aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-ssa-sink.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/tree-ssa-sink.cc')
-rw-r--r--gcc/tree-ssa-sink.cc73
1 files changed, 49 insertions, 24 deletions
diff --git a/gcc/tree-ssa-sink.cc b/gcc/tree-ssa-sink.cc
index 959e0d5..2244e89f 100644
--- a/gcc/tree-ssa-sink.cc
+++ b/gcc/tree-ssa-sink.cc
@@ -356,37 +356,54 @@ statement_sink_location (gimple *stmt, basic_block frombb,
use = NULL;
- /* If stmt is a store the one and only use needs to be the VOP
- merging PHI node. */
+ /* If stmt is a store the one and only use needs to be a VUSE on
+ the live path. */
if (virtual_operand_p (DEF_FROM_PTR (def_p)))
{
+ tree lhs = gimple_get_lhs (stmt);
+ ao_ref ref;
+ ao_ref_init (&ref, lhs);
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_has_lhs (use_stmt)
- && operand_equal_p (gimple_get_lhs (stmt),
- gimple_get_lhs (use_stmt), 0))
- || stmt_kills_ref_p (use_stmt, gimple_get_lhs (stmt)))
+ if (gimple_vdef (use_stmt)
+ && ((gimple_has_lhs (use_stmt)
+ && operand_equal_p (lhs,
+ gimple_get_lhs (use_stmt), 0))
+ || stmt_kills_ref_p (use_stmt, &ref)))
{
/* 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_get_lhs (stmt)))
- return false;
+ && ref_maybe_used_by_stmt_p (use_stmt, &ref))
+ {
+ if (use && use != use_stmt)
+ return false;
+ use = use_stmt;
+ }
continue;
}
- if (gimple_code (use_stmt) != GIMPLE_PHI)
- return false;
-
- if (use
- && use != use_stmt)
- return false;
+ if (is_a <gphi *> (use_stmt)
+ || ref_maybe_used_by_stmt_p (use_stmt, &ref))
+ {
+ if (use && use != use_stmt)
+ return false;
+ use = use_stmt;
+ continue;
+ }
- use = use_stmt;
+ if (gimple_vdef (use_stmt))
+ {
+ if (stmt_may_clobber_ref_p_1 (use_stmt, &ref, false))
+ return false;
+ /* We do not look past VDEFs, so treat them as sink location. */
+ if (use && use != use_stmt)
+ return false;
+ use = use_stmt;
+ }
}
if (!use)
return false;
@@ -448,18 +465,26 @@ statement_sink_location (gimple *stmt, basic_block frombb,
break;
}
use = USE_STMT (one_use);
+ }
- if (gimple_code (use) != GIMPLE_PHI)
- {
- sinkbb = select_best_block (frombb, gimple_bb (use), stmt);
+ if (gimple_code (use) != GIMPLE_PHI)
+ {
+ sinkbb = select_best_block (frombb, gimple_bb (use), stmt);
- if (sinkbb == frombb)
- return false;
+ if (sinkbb == frombb)
+ return false;
- *togsi = gsi_after_labels (sinkbb);
+ /* The SSA update for sinking of stores cannot insert PHIs, the
+ sink location has to lead to exit without crossing any CFG
+ merge points to paths not dominated by the sink location. */
+ if (gimple_vdef (stmt)
+ && (!single_succ_p (sinkbb)
+ || single_succ (sinkbb)->index != EXIT_BLOCK))
+ return false;
- return true;
- }
+ *togsi = gsi_after_labels (sinkbb);
+
+ return true;
}
sinkbb = find_bb_for_arg (as_a <gphi *> (use), DEF_FROM_PTR (def_p));