+/* Information to pass into make_eh_edge_and_update_phi. */
+
+struct update_info
+{
+ basic_block bb_to_remove, bb;
+ edge edge_to_remove;
+};
+
+/* DATA points to update-info structure.
+ Like make_eh_edge create EH edge from DATA->bb to basic block containing
+ handler of REGION. In addition also update PHI operands by copying
+ operands from DATA->bb_to_remove. */
+
+static void
+make_eh_edge_and_update_phi (struct eh_region_d *region, void *data)
+{
+ struct update_info *info = (struct update_info *) data;
+ edge e, e2;
+ tree lab;
+ basic_block src, dst;
+ gimple_stmt_iterator si;
+
+ lab = get_eh_region_tree_label (region);
+
+ src = info->bb;
+ dst = label_to_block (lab);
+
+ e = find_edge (src, dst);
+ if (e)
+ {
+ gcc_assert (e->flags & EDGE_EH);
+ e->aux = e;
+ return;
+ }
+ dominance_info_invalidated = true;
+ e2 = find_edge (info->bb_to_remove, dst);
+ e = make_edge (src, dst, EDGE_EH);
+ e->aux = e;
+ gcc_assert (e2);
+ for (si = gsi_start_phis (dst); !gsi_end_p (si); gsi_next (&si))
+ {
+ gimple phi = gsi_stmt (si);
+ tree use = USE_FROM_PTR (PHI_ARG_DEF_PTR_FROM_EDGE (phi, e2));
+ gimple def = (TREE_CODE (use) == SSA_NAME
+ ? SSA_NAME_DEF_STMT (use) : NULL);
+
+ if (def && gimple_bb (def) == info->bb_to_remove)
+ {
+ use = USE_FROM_PTR (PHI_ARG_DEF_PTR_FROM_EDGE (def,
+ info->edge_to_remove));
+ gcc_assert (info->bb_to_remove == info->edge_to_remove->dest);
+ def = TREE_CODE (use) == SSA_NAME ? SSA_NAME_DEF_STMT (use) : NULL;
+ gcc_assert (!def
+ || gimple_bb (def) != info->bb_to_remove
+ || !is_gimple_reg (use));
+ }
+ SET_USE (PHI_ARG_DEF_PTR_FROM_EDGE (phi, e), use);
+ }
+}
+
+/* Make EH edges corresponding to STMT while updating PHI nodes after removal
+ empty cleanup BB_TO_REMOVE joined to BB containing STMT
+ by EDGE_TO_REMOVE.
+
+ Return if EDGE_TO_REMOVE was really removed. It might stay reachable when
+ not all EH regions are cleaned up. */
+
+static bool
+update_eh_edges (gimple stmt, basic_block bb_to_remove, edge edge_to_remove)
+{
+ int region_nr;
+ bool is_resx;
+ bool inlinable = false;
+ struct update_info info;
+ edge_iterator ei;
+ edge e;
+ int probability_sum = 0;
+ bool removed = false;
+
+ info.bb_to_remove = bb_to_remove;
+ info.bb = gimple_bb (stmt);
+ info.edge_to_remove = edge_to_remove;
+
+ if (gimple_code (stmt) == GIMPLE_RESX)
+ {
+ region_nr = gimple_resx_region (stmt);
+ is_resx = true;
+ }
+ else
+ {
+ region_nr = lookup_stmt_eh_region (stmt);
+ is_resx = false;
+ inlinable = inlinable_call_p (stmt);
+ }
+
+ /* First add new edges as neccesary. */
+ foreach_reachable_handler (region_nr, is_resx, inlinable,
+ make_eh_edge_and_update_phi, &info);
+
+ /* And remove edges we didn't marked. */
+ for (ei = ei_start (info.bb->succs); (e = ei_safe_edge (ei)); )
+ {
+ if ((e->flags & EDGE_EH) && !e->aux)
+ {
+ dominance_info_invalidated = true;
+ if (e == edge_to_remove)
+ removed = true;
+ remove_edge (e);
+ }
+ else
+ {
+ e->aux = NULL;
+ probability_sum += e->probability;
+ ei_next (&ei);
+ }
+ }
+
+ /* Make CFG profile more consistent assuming that exception will resume to
+ first available EH handler. In practice this makes little difference, but
+ we get fewer consistency errors in the dumps. */
+ if (is_resx && EDGE_COUNT (info.bb->succs) && !probability_sum)
+ EDGE_SUCC (info.bb, 0)->probability = REG_BR_PROB_BASE;
+ return removed;
+}
+