is replaced. If the call is expected to produces a result, then it
is replaced by an assignment of the new RHS to the result variable.
If the result is to be ignored, then the call is replaced by a
- GIMPLE_NOP. */
+ GIMPLE_NOP. A proper VDEF chain is retained by making the first
+ VUSE and the last VDEF of the whole sequence be the same as the replaced
+ statement and using new SSA names for stores in between. */
static void
gimplify_and_update_call_from_tree (gimple_stmt_iterator *si_p, tree expr)
gimple_stmt_iterator i;
gimple_seq stmts = gimple_seq_alloc();
struct gimplify_ctx gctx;
+ gimple last = NULL;
+ gimple laststore = NULL;
+ tree reaching_vuse;
stmt = gsi_stmt (*si_p);
gcc_assert (is_gimple_call (stmt));
lhs = gimple_call_lhs (stmt);
+ reaching_vuse = gimple_vuse (stmt);
push_gimplify_context (&gctx);
if (lhs == NULL_TREE)
- gimplify_and_add (expr, &stmts);
+ {
+ gimplify_and_add (expr, &stmts);
+ /* We can end up with folding a memcpy of an empty class assignment
+ which gets optimized away by C++ gimplification. */
+ if (gimple_seq_empty_p (stmts))
+ {
+ pop_gimplify_context (NULL);
+ if (gimple_in_ssa_p (cfun))
+ {
+ unlink_stmt_vdef (stmt);
+ release_defs (stmt);
+ }
+ gsi_remove (si_p, true);
+ return;
+ }
+ }
else
tmp = get_initialized_tmp_var (expr, &stmts, NULL);
/* The replacement can expose previously unreferenced variables. */
for (i = gsi_start (stmts); !gsi_end_p (i); gsi_next (&i))
- {
- new_stmt = gsi_stmt (i);
- find_new_referenced_vars (new_stmt);
- gsi_insert_before (si_p, new_stmt, GSI_NEW_STMT);
- mark_symbols_for_renaming (new_stmt);
- gsi_next (si_p);
- }
+ {
+ if (last)
+ {
+ gsi_insert_before (si_p, last, GSI_NEW_STMT);
+ gsi_next (si_p);
+ }
+ new_stmt = gsi_stmt (i);
+ if (gimple_in_ssa_p (cfun))
+ {
+ find_new_referenced_vars (new_stmt);
+ mark_symbols_for_renaming (new_stmt);
+ }
+ /* If the new statement has a VUSE, update it with exact SSA name we
+ know will reach this one. */
+ if (gimple_vuse (new_stmt))
+ {
+ /* If we've also seen a previous store create a new VDEF for
+ the latter one, and make that the new reaching VUSE. */
+ if (laststore)
+ {
+ reaching_vuse = make_ssa_name (gimple_vop (cfun), laststore);
+ gimple_set_vdef (laststore, reaching_vuse);
+ update_stmt (laststore);
+ laststore = NULL;
+ }
+ gimple_set_vuse (new_stmt, reaching_vuse);
+ gimple_set_modified (new_stmt, true);
+ }
+ if (gimple_assign_single_p (new_stmt)
+ && !is_gimple_reg (gimple_assign_lhs (new_stmt)))
+ {
+ laststore = new_stmt;
+ }
+ last = new_stmt;
+ }
if (lhs == NULL_TREE)
{
- new_stmt = gimple_build_nop ();
- unlink_stmt_vdef (stmt);
- release_defs (stmt);
+ /* If we replace a call without LHS that has a VDEF and our new
+ sequence ends with a store we must make that store have the same
+ vdef in order not to break the sequencing. This can happen
+ for instance when folding memcpy calls into assignments. */
+ if (gimple_vdef (stmt) && laststore)
+ {
+ gimple_set_vdef (laststore, gimple_vdef (stmt));
+ if (TREE_CODE (gimple_vdef (stmt)) == SSA_NAME)
+ SSA_NAME_DEF_STMT (gimple_vdef (stmt)) = laststore;
+ update_stmt (laststore);
+ }
+ else if (gimple_in_ssa_p (cfun))
+ {
+ unlink_stmt_vdef (stmt);
+ release_defs (stmt);
+ }
+ new_stmt = last;
}
else
{
+ if (last)
+ {
+ gsi_insert_before (si_p, last, GSI_NEW_STMT);
+ gsi_next (si_p);
+ }
+ if (laststore && is_gimple_reg (lhs))
+ {
+ gimple_set_vdef (laststore, gimple_vdef (stmt));
+ update_stmt (laststore);
+ if (TREE_CODE (gimple_vdef (stmt)) == SSA_NAME)
+ SSA_NAME_DEF_STMT (gimple_vdef (stmt)) = laststore;
+ laststore = NULL;
+ }
+ else if (laststore)
+ {
+ reaching_vuse = make_ssa_name (gimple_vop (cfun), laststore);
+ gimple_set_vdef (laststore, reaching_vuse);
+ update_stmt (laststore);
+ laststore = NULL;
+ }
new_stmt = gimple_build_assign (lhs, tmp);
- gimple_set_vuse (new_stmt, gimple_vuse (stmt));
- gimple_set_vdef (new_stmt, gimple_vdef (stmt));
- move_ssa_defining_stmt_for_defs (new_stmt, stmt);
+ if (!is_gimple_reg (tmp))
+ gimple_set_vuse (new_stmt, reaching_vuse);
+ if (!is_gimple_reg (lhs))
+ {
+ gimple_set_vdef (new_stmt, gimple_vdef (stmt));
+ if (TREE_CODE (gimple_vdef (stmt)) == SSA_NAME)
+ SSA_NAME_DEF_STMT (gimple_vdef (stmt)) = new_stmt;
+ }
+ else if (reaching_vuse == gimple_vuse (stmt))
+ unlink_stmt_vdef (stmt);
}
gimple_set_location (new_stmt, gimple_location (stmt));