/* Structure to keep track of the value of a dereferenced PHI result
- and the set of virtual operands used for that dereference. */
+ and the virtual operand used for that dereference. */
struct phiprop_d
{
tree value;
- gimple vop_stmt;
+ tree vuse;
};
/* Verify if the value recorded for NAME in PHIVN is still valid at
static bool
phivn_valid_p (struct phiprop_d *phivn, tree name, basic_block bb)
{
- gimple vop_stmt = phivn[SSA_NAME_VERSION (name)].vop_stmt;
- ssa_op_iter ui;
- tree vuse;
+ tree vuse = phivn[SSA_NAME_VERSION (name)].vuse;
+ gimple use_stmt;
+ imm_use_iterator ui2;
+ bool ok = true;
- /* The def stmts of all virtual uses need to be post-dominated
- by bb. */
- FOR_EACH_SSA_TREE_OPERAND (vuse, vop_stmt, ui, SSA_OP_VUSE)
- {
- gimple use_stmt;
- imm_use_iterator ui2;
- bool ok = true;
+ /* The def stmts of the virtual uses need to be dominated by bb. */
+ gcc_assert (vuse != NULL_TREE);
- FOR_EACH_IMM_USE_STMT (use_stmt, ui2, vuse)
+ FOR_EACH_IMM_USE_STMT (use_stmt, ui2, vuse)
+ {
+ /* If BB does not dominate a VDEF, the value is invalid. */
+ if ((gimple_vdef (use_stmt) != NULL_TREE
+ || gimple_code (use_stmt) == GIMPLE_PHI)
+ && !dominated_by_p (CDI_DOMINATORS, gimple_bb (use_stmt), bb))
{
- /* If BB does not dominate a VDEF, the value is invalid. */
- if (((is_gimple_assign (use_stmt)
- && !ZERO_SSA_OPERANDS (use_stmt, SSA_OP_VDEF))
- || gimple_code (use_stmt) == GIMPLE_PHI)
- && !dominated_by_p (CDI_DOMINATORS, gimple_bb (use_stmt), bb))
- {
- ok = false;
- BREAK_FROM_IMM_USE_STMT (ui2);
- }
+ ok = false;
+ BREAK_FROM_IMM_USE_STMT (ui2);
}
- if (!ok)
- return false;
}
- return true;
+ return ok;
}
/* Insert a new phi node for the dereference of PHI at basic_block
res = gimple_assign_lhs (use_stmt);
SSA_NAME_DEF_STMT (res) = new_phi = create_phi_node (res, bb);
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Inserting PHI for result of load ");
+ print_gimple_stmt (dump_file, use_stmt, 0, 0);
+ }
+
/* Add PHI arguments for each edge inserting loads of the
addressable operands. */
FOR_EACH_EDGE (e, ei, bb->preds)
{
tree old_arg, new_var;
gimple tmp;
+ source_location locus;
old_arg = PHI_ARG_DEF_FROM_EDGE (phi, e);
+ locus = gimple_phi_arg_location_from_edge (phi, e);
while (TREE_CODE (old_arg) == SSA_NAME
&& (SSA_NAME_VERSION (old_arg) >= n
|| phivn[SSA_NAME_VERSION (old_arg)].value == NULL_TREE))
{
gimple def_stmt = SSA_NAME_DEF_STMT (old_arg);
old_arg = gimple_assign_rhs1 (def_stmt);
+ locus = gimple_location (def_stmt);
}
if (TREE_CODE (old_arg) == SSA_NAME)
- /* Reuse a formerly created dereference. */
- new_var = phivn[SSA_NAME_VERSION (old_arg)].value;
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, " for edge defining ");
+ print_generic_expr (dump_file, PHI_ARG_DEF_FROM_EDGE (phi, e), 0);
+ fprintf (dump_file, " reusing PHI result ");
+ print_generic_expr (dump_file,
+ phivn[SSA_NAME_VERSION (old_arg)].value, 0);
+ fprintf (dump_file, "\n");
+ }
+ /* Reuse a formerly created dereference. */
+ new_var = phivn[SSA_NAME_VERSION (old_arg)].value;
+ }
else
{
gcc_assert (TREE_CODE (old_arg) == ADDR_EXPR);
old_arg = TREE_OPERAND (old_arg, 0);
- new_var = create_tmp_var (TREE_TYPE (old_arg), NULL);
+ new_var = create_tmp_reg (TREE_TYPE (old_arg), NULL);
tmp = gimple_build_assign (new_var, unshare_expr (old_arg));
- if (TREE_CODE (TREE_TYPE (old_arg)) == COMPLEX_TYPE
- || TREE_CODE (TREE_TYPE (old_arg)) == VECTOR_TYPE)
- DECL_GIMPLE_REG_P (new_var) = 1;
gcc_assert (is_gimple_reg (new_var));
add_referenced_var (new_var);
new_var = make_ssa_name (new_var, tmp);
gimple_assign_set_lhs (tmp, new_var);
+ gimple_set_location (tmp, locus);
gsi_insert_on_edge (e, tmp);
-
update_stmt (tmp);
- mark_symbols_for_renaming (tmp);
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, " for edge defining ");
+ print_generic_expr (dump_file, PHI_ARG_DEF_FROM_EDGE (phi, e), 0);
+ fprintf (dump_file, " inserting load ");
+ print_gimple_stmt (dump_file, tmp, 0, 0);
+ }
}
- add_phi_arg (new_phi, new_var, e);
+ add_phi_arg (new_phi, new_var, e, locus);
}
update_stmt (new_phi);
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ print_gimple_stmt (dump_file, new_phi, 0, 0);
+
return res;
}
ssa_op_iter i;
bool phi_inserted;
- if (MTAG_P (SSA_NAME_VAR (ptr))
- || !POINTER_TYPE_P (TREE_TYPE (ptr))
+ if (!POINTER_TYPE_P (TREE_TYPE (ptr))
|| !is_gimple_reg_type (TREE_TYPE (TREE_TYPE (ptr))))
return false;
|| phivn[SSA_NAME_VERSION (arg)].value == NULL_TREE))
{
gimple def_stmt = SSA_NAME_DEF_STMT (arg);
- if (gimple_code (def_stmt) != GIMPLE_ASSIGN)
+ if (!gimple_assign_single_p (def_stmt))
return false;
arg = gimple_assign_rhs1 (def_stmt);
}
/* Avoid to have to decay *&a to a[0] later. */
|| !is_gimple_reg_type (TREE_TYPE (TREE_OPERAND (arg, 0))))
&& !(TREE_CODE (arg) == SSA_NAME
+ && SSA_NAME_VERSION (arg) < n
&& phivn[SSA_NAME_VERSION (arg)].value != NULL_TREE
&& phivn_valid_p (phivn, arg, bb)))
return false;
phi_inserted = false;
FOR_EACH_IMM_USE_STMT (use_stmt, ui, ptr)
{
- ssa_op_iter ui2;
+ gimple def_stmt;
tree vuse;
/* Check whether this is a load of *ptr. */
if (!(is_gimple_assign (use_stmt)
- && TREE_CODE (gimple_assign_lhs (use_stmt)) == SSA_NAME
+ && TREE_CODE (gimple_assign_lhs (use_stmt)) == SSA_NAME
&& gimple_assign_rhs_code (use_stmt) == INDIRECT_REF
&& TREE_OPERAND (gimple_assign_rhs1 (use_stmt), 0) == ptr
/* We cannot replace a load that may throw or is volatile. */
&& !stmt_can_throw_internal (use_stmt)))
continue;
- /* Check if we can move the loads. The def stmts of all virtual uses
- need to be post-dominated by bb. */
- FOR_EACH_SSA_TREE_OPERAND (vuse, use_stmt, ui2, SSA_OP_VUSE)
- {
- gimple def_stmt = SSA_NAME_DEF_STMT (vuse);
- if (!SSA_NAME_IS_DEFAULT_DEF (vuse)
- && (gimple_bb (def_stmt) == bb
- || !dominated_by_p (CDI_DOMINATORS,
- bb, gimple_bb (def_stmt))))
- goto next;
- }
+ /* Check if we can move the loads. The def stmt of the virtual use
+ needs to be in a different basic block dominating bb. */
+ vuse = gimple_vuse (use_stmt);
+ def_stmt = SSA_NAME_DEF_STMT (vuse);
+ if (!SSA_NAME_IS_DEFAULT_DEF (vuse)
+ && (gimple_bb (def_stmt) == bb
+ || !dominated_by_p (CDI_DOMINATORS,
+ bb, gimple_bb (def_stmt))))
+ goto next;
/* Found a proper dereference. Insert a phi node if this
is the first load transformation. */
/* Remember the value we created for *ptr. */
phivn[SSA_NAME_VERSION (ptr)].value = res;
- phivn[SSA_NAME_VERSION (ptr)].vop_stmt = use_stmt;
+ phivn[SSA_NAME_VERSION (ptr)].vuse = vuse;
/* Remove old stmt. The phi is taken care of by DCE, if we
want to delete it here we also have to delete all intermediate
return phi_inserted;
}
-/* Helper walking the dominator tree starting from BB and processing
- phi nodes with global data PHIVN and N. */
-
-static bool
-tree_ssa_phiprop_1 (basic_block bb, struct phiprop_d *phivn, size_t n)
-{
- bool did_something = false;
- basic_block son;
- gimple_stmt_iterator gsi;
-
- for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
- did_something |= propagate_with_phi (bb, gsi_stmt (gsi), phivn, n);
-
- for (son = first_dom_son (CDI_DOMINATORS, bb);
- son;
- son = next_dom_son (CDI_DOMINATORS, son))
- did_something |= tree_ssa_phiprop_1 (son, phivn, n);
-
- return did_something;
-}
-
/* Main entry for phiprop pass. */
static unsigned int
tree_ssa_phiprop (void)
{
+ VEC(basic_block, heap) *bbs;
struct phiprop_d *phivn;
+ bool did_something = false;
+ basic_block bb;
+ gimple_stmt_iterator gsi;
+ unsigned i;
+ size_t n;
calculate_dominance_info (CDI_DOMINATORS);
- phivn = XCNEWVEC (struct phiprop_d, num_ssa_names);
+ n = num_ssa_names;
+ phivn = XCNEWVEC (struct phiprop_d, n);
+
+ /* Walk the dominator tree in preorder. */
+ bbs = get_all_dominated_blocks (CDI_DOMINATORS,
+ single_succ (ENTRY_BLOCK_PTR));
+ for (i = 0; VEC_iterate (basic_block, bbs, i, bb); ++i)
+ for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+ did_something |= propagate_with_phi (bb, gsi_stmt (gsi), phivn, n);
- if (tree_ssa_phiprop_1 (ENTRY_BLOCK_PTR, phivn, num_ssa_names))
+ if (did_something)
gsi_commit_edge_inserts ();
+ VEC_free (basic_block, heap, bbs);
free (phivn);
return 0;
static bool
gate_phiprop (void)
{
- return 1;
+ return flag_tree_phiprop;
}
-struct gimple_opt_pass pass_phiprop =
+struct gimple_opt_pass pass_phiprop =
{
{
GIMPLE_PASS,