summaryrefslogtreecommitdiff
path: root/gcc/tree-sra.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/tree-sra.c')
-rw-r--r--gcc/tree-sra.c87
1 files changed, 59 insertions, 28 deletions
diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c
index 91286b44842..49bbee3deb7 100644
--- a/gcc/tree-sra.c
+++ b/gcc/tree-sra.c
@@ -1142,17 +1142,41 @@ build_access_from_expr (tree expr, gimple stmt, bool write)
return false;
}
-/* Disqualify LHS and RHS for scalarization if STMT must end its basic block in
- modes in which it matters, return true iff they have been disqualified. RHS
- may be NULL, in that case ignore it. If we scalarize an aggregate in
- intra-SRA we may need to add statements after each statement. This is not
- possible if a statement unconditionally has to end the basic block. */
+/* Return the single non-EH successor edge of BB or NULL if there is none or
+ more than one. */
+
+static edge
+single_non_eh_succ (basic_block bb)
+{
+ edge e, res = NULL;
+ edge_iterator ei;
+
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ if (!(e->flags & EDGE_EH))
+ {
+ if (res)
+ return NULL;
+ res = e;
+ }
+
+ return res;
+}
+
+/* Disqualify LHS and RHS for scalarization if STMT has to terminate its BB and
+ there is no alternative spot where to put statements SRA might need to
+ generate after it. The spot we are looking for is an edge leading to a
+ single non-EH successor, if it exists and is indeed single. RHS may be
+ NULL, in that case ignore it. */
+
static bool
-disqualify_ops_if_throwing_stmt (gimple stmt, tree lhs, tree rhs)
+disqualify_if_bad_bb_terminating_stmt (gimple stmt, tree lhs, tree rhs)
{
if ((sra_mode == SRA_MODE_EARLY_INTRA || sra_mode == SRA_MODE_INTRA)
- && (stmt_can_throw_internal (stmt) || stmt_ends_bb_p (stmt)))
+ && stmt_ends_bb_p (stmt))
{
+ if (single_non_eh_succ (gimple_bb (stmt)))
+ return false;
+
disqualify_base_of_expr (lhs, "LHS of a throwing stmt.");
if (rhs)
disqualify_base_of_expr (rhs, "RHS of a throwing stmt.");
@@ -1180,7 +1204,7 @@ build_accesses_from_assign (gimple stmt)
lhs = gimple_assign_lhs (stmt);
rhs = gimple_assign_rhs1 (stmt);
- if (disqualify_ops_if_throwing_stmt (stmt, lhs, rhs))
+ if (disqualify_if_bad_bb_terminating_stmt (stmt, lhs, rhs))
return false;
racc = build_access_from_expr_1 (rhs, stmt, false);
@@ -1319,7 +1343,7 @@ scan_function (void)
}
t = gimple_call_lhs (stmt);
- if (t && !disqualify_ops_if_throwing_stmt (stmt, t, NULL))
+ if (t && !disqualify_if_bad_bb_terminating_stmt (stmt, t, NULL))
ret |= build_access_from_expr (t, stmt, true);
break;
@@ -2763,6 +2787,13 @@ sra_modify_expr (tree *expr, gimple_stmt_iterator *gsi, bool write)
type = TREE_TYPE (*expr);
loc = gimple_location (gsi_stmt (*gsi));
+ gimple_stmt_iterator alt_gsi = gsi_none ();
+ if (write && stmt_ends_bb_p (gsi_stmt (*gsi)))
+ {
+ alt_gsi = gsi_start_edge (single_non_eh_succ (gsi_bb (*gsi)));
+ gsi = &alt_gsi;
+ }
+
if (access->grp_to_be_replaced)
{
tree repl = get_access_replacement (access);
@@ -3226,14 +3257,23 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi)
if (modify_this_stmt
|| gimple_has_volatile_ops (*stmt)
|| contains_vce_or_bfcref_p (rhs)
- || contains_vce_or_bfcref_p (lhs))
+ || contains_vce_or_bfcref_p (lhs)
+ || stmt_ends_bb_p (*stmt))
{
if (access_has_children_p (racc))
generate_subtree_copies (racc->first_child, racc->base, 0, 0, 0,
gsi, false, false, loc);
if (access_has_children_p (lacc))
- generate_subtree_copies (lacc->first_child, lacc->base, 0, 0, 0,
- gsi, true, true, loc);
+ {
+ gimple_stmt_iterator alt_gsi = gsi_none ();
+ if (stmt_ends_bb_p (*stmt))
+ {
+ alt_gsi = gsi_start_edge (single_non_eh_succ (gsi_bb (*gsi)));
+ gsi = &alt_gsi;
+ }
+ generate_subtree_copies (lacc->first_child, lacc->base, 0, 0, 0,
+ gsi, true, true, loc);
+ }
sra_stats.separate_lhs_rhs_handling++;
/* This gimplification must be done after generate_subtree_copies,
@@ -3397,6 +3437,7 @@ sra_modify_function_body (void)
}
}
+ gsi_commit_edge_inserts ();
return cfg_changed;
}
@@ -3507,7 +3548,6 @@ const pass_data pass_data_sra_early =
GIMPLE_PASS, /* type */
"esra", /* name */
OPTGROUP_NONE, /* optinfo_flags */
- true, /* has_gate */
true, /* has_execute */
TV_TREE_SRA, /* tv_id */
( PROP_cfg | PROP_ssa ), /* properties_required */
@@ -3525,8 +3565,8 @@ public:
{}
/* opt_pass methods: */
- bool gate () { return gate_intra_sra (); }
- unsigned int execute () { return early_intra_sra (); }
+ virtual bool gate (function *) { return gate_intra_sra (); }
+ virtual unsigned int execute (function *) { return early_intra_sra (); }
}; // class pass_sra_early
@@ -3545,7 +3585,6 @@ const pass_data pass_data_sra =
GIMPLE_PASS, /* type */
"sra", /* name */
OPTGROUP_NONE, /* optinfo_flags */
- true, /* has_gate */
true, /* has_execute */
TV_TREE_SRA, /* tv_id */
( PROP_cfg | PROP_ssa ), /* properties_required */
@@ -3563,8 +3602,8 @@ public:
{}
/* opt_pass methods: */
- bool gate () { return gate_intra_sra (); }
- unsigned int execute () { return late_intra_sra (); }
+ virtual bool gate (function *) { return gate_intra_sra (); }
+ virtual unsigned int execute (function *) { return late_intra_sra (); }
}; // class pass_sra
@@ -5053,13 +5092,6 @@ ipa_early_sra (void)
return ret;
}
-/* Return if early ipa sra shall be performed. */
-static bool
-ipa_early_sra_gate (void)
-{
- return flag_ipa_sra && dbg_cnt (eipa_sra);
-}
-
namespace {
const pass_data pass_data_early_ipa_sra =
@@ -5067,7 +5099,6 @@ const pass_data pass_data_early_ipa_sra =
GIMPLE_PASS, /* type */
"eipa_sra", /* name */
OPTGROUP_NONE, /* optinfo_flags */
- true, /* has_gate */
true, /* has_execute */
TV_IPA_SRA, /* tv_id */
0, /* properties_required */
@@ -5085,8 +5116,8 @@ public:
{}
/* opt_pass methods: */
- bool gate () { return ipa_early_sra_gate (); }
- unsigned int execute () { return ipa_early_sra (); }
+ virtual bool gate (function *) { return flag_ipa_sra && dbg_cnt (eipa_sra); }
+ virtual unsigned int execute (function *) { return ipa_early_sra (); }
}; // class pass_early_ipa_sra