===================================================================
@@ -0,0 +1,24 @@
+// PR81354 reported this test as crashing in a limited range of revisions.
+// { dg-do compile }
+
+struct T { double a; double b; };
+
+void foo(T Ad[], int As[2])
+{
+ int j;
+ int i;
+ int Bs[2] = {0,0};
+ T Bd[16];
+
+ for (j = 0; j < 4; j++) {
+ for (i = 0; i + 1 <= j + 1; i++) {
+ Ad[i + As[0] * j] = Bd[i + Bs[0] * j];
+ }
+
+ i = j + 1; // <- comment out this line and it does not crash
+ for (; i + 1 < 5; i++) {
+ Ad[i + As[0] * j].a = 0.0;
+ Ad[i + As[0] * j].b = 0.0;
+ }
+ }
+}
===================================================================
@@ -154,6 +154,7 @@ static void make_gimple_switch_edges (gswitch *, b
static bool make_goto_expr_edges (basic_block);
static void make_gimple_asm_edges (basic_block);
static edge gimple_redirect_edge_and_branch (edge, basic_block);
+static edge gimple_redirect_edge_and_branch_1 (edge, basic_block);
static edge gimple_try_redirect_by_replacing_jump (edge, basic_block);
/* Various helpers. */
@@ -2776,35 +2777,6 @@ last_and_only_stmt (basic_block bb)
return NULL;
}
-/* Reinstall those PHI arguments queued in OLD_EDGE to NEW_EDGE. */
-
-static void
-reinstall_phi_args (edge new_edge, edge old_edge)
-{
- edge_var_map *vm;
- int i;
- gphi_iterator phis;
-
- vec<edge_var_map> *v = redirect_edge_var_map_vector (old_edge);
- if (!v)
- return;
-
- for (i = 0, phis = gsi_start_phis (new_edge->dest);
- v->iterate (i, &vm) && !gsi_end_p (phis);
- i++, gsi_next (&phis))
- {
- gphi *phi = phis.phi ();
- tree result = redirect_edge_var_map_result (vm);
- tree arg = redirect_edge_var_map_def (vm);
-
- gcc_assert (result == gimple_phi_result (phi));
-
- add_phi_arg (phi, arg, new_edge, redirect_edge_var_map_location (vm));
- }
-
- redirect_edge_var_map_clear (old_edge);
-}
-
/* Returns the basic block after which the new basic block created
by splitting edge EDGE_IN should be placed. Tries to keep the new block
near its "logical" location. This is of most help to humans looking
@@ -2825,6 +2797,24 @@ split_edge_bb_loc (edge edge_in)
return dest_prev;
}
+/* Create a single-predecessor edge from SRC to DST, replacing the
+ predecessor edge E_IN of DST, with flags FLAGS. This is done in
+ situ so that phis in DST will not get re-allocated. */
+
+static edge
+make_replacement_pred_edge (basic_block src, basic_block dest,
+ edge e_in, int flags)
+{
+ edge e = ggc_cleared_alloc<edge_def> ();
+ n_edges_for_fn (cfun)++;
+ e->src = src;
+ e->dest = dest;
+ e->flags = flags;
+ vec_safe_push (src->succs, e);
+ e->dest_idx = e_in->dest_idx;
+ return e;
+}
+
/* Split a (typically critical) edge EDGE_IN. Return the new block.
Abort on abnormal edges. */
@@ -2832,7 +2822,7 @@ static basic_block
gimple_split_edge (edge edge_in)
{
basic_block new_bb, after_bb, dest;
- edge new_edge, e;
+ edge e, f;
/* Abnormal edges cannot be split. */
gcc_assert (!(edge_in->flags & EDGE_ABNORMAL));
@@ -2841,15 +2831,33 @@ gimple_split_edge (edge edge_in)
after_bb = split_edge_bb_loc (edge_in);
+ /* Create a new block, and an edge F from that block to the original
+ destination. */
new_bb = create_empty_bb (after_bb);
new_bb->frequency = EDGE_FREQUENCY (edge_in);
new_bb->count = edge_in->count;
- new_edge = make_single_succ_edge (new_bb, dest, EDGE_FALLTHRU);
+ f = make_replacement_pred_edge (new_bb, dest, edge_in, EDGE_FALLTHRU);
- e = redirect_edge_and_branch (edge_in, new_bb);
+ /* Redirect the original edge to its new successor. */
+ e = gimple_redirect_edge_and_branch_1 (edge_in, new_bb);
gcc_assert (e == edge_in);
- reinstall_phi_args (new_edge, e);
+ e->dest = new_bb;
+ vec_safe_push (new_bb->preds, e);
+ e->dest_idx = 0;
+ /* Fix up the predecessor edge for DEST to now be F. We can't do
+ this prior to gimple_redirect_edge_and_branch_1 without raising
+ havoc in the switch code. */
+ int idx = -1;
+ for (unsigned int i = 0; i < EDGE_COUNT (dest->preds); i++)
+ if (EDGE_PRED (dest, i) == edge_in)
+ {
+ idx = i;
+ break;
+ }
+ gcc_assert (idx != -1);
+ EDGE_PRED (dest, idx) = f;
+
return new_bb;
}
@@ -5740,12 +5748,10 @@ gimple_try_redirect_by_replacing_jump (edge e, bas
return NULL;
}
+/* Primary worker for gimple_redirect_edge_and_branch. */
-/* Redirect E to DEST. Return NULL on failure. Otherwise, return the
- edge representing the redirected branch. */
-
static edge
-gimple_redirect_edge_and_branch (edge e, basic_block dest)
+gimple_redirect_edge_and_branch_1 (edge e, basic_block dest)
{
basic_block bb = e->src;
gimple_stmt_iterator gsi;
@@ -5759,7 +5765,10 @@ static edge
return NULL;
if (e->flags & EDGE_EH)
- return redirect_eh_edge (e, dest);
+ {
+ redirect_eh_edge_1 (e, dest, false);
+ return e;
+ }
if (e->src != ENTRY_BLOCK_PTR_FOR_FN (cfun))
{
@@ -5887,9 +5896,19 @@ static edge
gcc_assert (e->flags & EDGE_FALLTHRU);
break;
}
+ return e;
+}
- /* Update/insert PHI nodes as necessary. */
+/* Redirect E to DEST. Return NULL on failure. Otherwise, return the
+ edge representing the redirected branch. */
+static edge
+gimple_redirect_edge_and_branch (edge e, basic_block dest)
+{
+ edge f = gimple_redirect_edge_and_branch_1 (e, dest);
+ if (f != e)
+ return f;
+
/* Now update the edges in the CFG. */
e = ssa_redirect_edge (e, dest);
@@ -8636,13 +8655,18 @@ split_critical_edges (void)
basic_block bb;
edge e;
edge_iterator ei;
+ int first_free_block;
/* split_edge can redirect edges out of SWITCH_EXPRs, which can get
expensive. So we want to enable recording of edge to CASE_LABEL_EXPR
mappings around the calls to split_edge. */
start_recording_case_labels ();
+ first_free_block = last_basic_block_for_fn (cfun);
FOR_ALL_BB_FN (bb, cfun)
{
+ /* Don't re-split edges we've already split. */
+ if (bb->index >= first_free_block)
+ continue;
FOR_EACH_EDGE (e, ei, bb->succs)
{
if (EDGE_CRITICAL_P (e) && !(e->flags & EDGE_ABNORMAL))
===================================================================
@@ -2279,7 +2279,7 @@ make_eh_edges (gimple *stmt)
If false, we're being called from generic cfg manipulation code and we
should preserve our place within the region tree. */
-static void
+void
redirect_eh_edge_1 (edge edge_in, basic_block new_bb, bool change_region)
{
eh_landing_pad old_lp, new_lp;
===================================================================
@@ -32,6 +32,7 @@ extern int lookup_stmt_eh_lp (gimple *);
extern bool make_eh_dispatch_edges (geh_dispatch *);
extern void make_eh_edges (gimple *);
extern edge redirect_eh_edge (edge, basic_block);
+extern void redirect_eh_edge_1 (edge, basic_block, bool);
extern void redirect_eh_dispatch_edge (geh_dispatch *, edge, basic_block);
extern bool operation_could_trap_helper_p (enum tree_code, bool, bool, bool,
bool, tree, bool *);