/* Copy edges from BB into its copy constructed earlier, scale profile
accordingly. Edges will be taken care of later. Assume aux
- pointers to point to the copies of each BB. */
+ pointers to point to the copies of each BB. Return true if any
+ debug stmts are left after a statement that must end the basic block. */
-static void
+static bool
copy_edges_for_bb (basic_block bb, gcov_type count_scale, basic_block ret_bb)
{
basic_block new_bb = (basic_block) bb->aux;
edge old_edge;
gimple_stmt_iterator si;
int flags;
+ bool need_debug_cleanup = false;
/* Use the indices from the original blocks to create edges for the
new ones. */
}
if (bb->index == ENTRY_BLOCK || bb->index == EXIT_BLOCK)
- return;
+ return false;
for (si = gsi_start_bb (new_bb); !gsi_end_p (si);)
{
if (can_throw || nonlocal_goto)
{
+ if (!gsi_end_p (si))
+ {
+ while (!gsi_end_p (si) && is_gimple_debug (gsi_stmt (si)))
+ gsi_next (&si);
+ if (gsi_end_p (si))
+ need_debug_cleanup = true;
+ }
if (!gsi_end_p (si))
/* Note that bb's predecessor edges aren't necessarily
right at this point; split_block doesn't care. */
update_ssa_across_abnormal_edges (gimple_bb (copy_stmt), ret_bb,
can_throw, nonlocal_goto);
}
+ return need_debug_cleanup;
}
/* Copy the PHIs. All blocks and edges are copied, some blocks
pop_cfun ();
}
+/* Helper function for copy_cfg_body. Move debug stmts from the end
+ of NEW_BB to the beginning of successor basic blocks when needed. If the
+ successor has multiple predecessors, reset them, otherwise keep
+ their value. */
+
+static void
+maybe_move_debug_stmts_to_successors (copy_body_data *id, basic_block new_bb)
+{
+ edge e;
+ edge_iterator ei;
+ gimple_stmt_iterator si = gsi_last_nondebug_bb (new_bb);
+
+ if (gsi_end_p (si)
+ || gsi_one_before_end_p (si)
+ || !(stmt_can_throw_internal (gsi_stmt (si))
+ || stmt_can_make_abnormal_goto (gsi_stmt (si))))
+ return;
+
+ FOR_EACH_EDGE (e, ei, new_bb->succs)
+ {
+ gimple_stmt_iterator ssi = gsi_last_bb (new_bb);
+ gimple_stmt_iterator dsi = gsi_after_labels (e->dest);
+ while (is_gimple_debug (gsi_stmt (ssi)))
+ {
+ gimple stmt = gsi_stmt (ssi), new_stmt;
+ tree var;
+ tree value;
+
+ /* For the last edge move the debug stmts instead of copying
+ them. */
+ if (ei_one_before_end_p (ei))
+ {
+ si = ssi;
+ gsi_prev (&ssi);
+ if (!single_pred_p (e->dest))
+ gimple_debug_bind_reset_value (stmt);
+ gsi_remove (&si, false);
+ gsi_insert_before (&dsi, stmt, GSI_SAME_STMT);
+ continue;
+ }
+
+ var = gimple_debug_bind_get_var (stmt);
+ if (single_pred_p (e->dest))
+ {
+ value = gimple_debug_bind_get_value (stmt);
+ value = unshare_expr (value);
+ }
+ else
+ value = NULL_TREE;
+ new_stmt = gimple_build_debug_bind (var, value, stmt);
+ gsi_insert_before (&dsi, new_stmt, GSI_SAME_STMT);
+ VEC_safe_push (gimple, heap, id->debug_stmts, new_stmt);
+ gsi_prev (&ssi);
+ }
+ }
+}
+
/* Make a copy of the body of FN so that it can be inserted inline in
another function. Walks FN via CFG, returns new fndecl. */
struct function *cfun_to_copy;
basic_block bb;
tree new_fndecl = NULL;
+ bool need_debug_cleanup = false;
gcov_type count_scale;
int last;
/* Now that we've duplicated the blocks, duplicate their edges. */
FOR_ALL_BB_FN (bb, cfun_to_copy)
- copy_edges_for_bb (bb, count_scale, exit_block_map);
+ need_debug_cleanup |= copy_edges_for_bb (bb, count_scale, exit_block_map);
if (gimple_in_ssa_p (cfun))
FOR_ALL_BB_FN (bb, cfun_to_copy)
FOR_ALL_BB_FN (bb, cfun_to_copy)
{
+ if (need_debug_cleanup
+ && bb->index != ENTRY_BLOCK
+ && bb->index != EXIT_BLOCK)
+ maybe_move_debug_stmts_to_successors (id, (basic_block) bb->aux);
((basic_block)bb->aux)->aux = NULL;
bb->aux = NULL;
}
/* Zero out AUX fields of newly created block during EH edge
insertion. */
for (; last < last_basic_block; last++)
- BASIC_BLOCK (last)->aux = NULL;
+ {
+ if (need_debug_cleanup)
+ maybe_move_debug_stmts_to_successors (id, BASIC_BLOCK (last));
+ BASIC_BLOCK (last)->aux = NULL;
+ }
entry_block_map->aux = NULL;
exit_block_map->aux = NULL;