/* Backward propagation of indirect loads through PHIs.
- Copyright (C) 2007, 2008 Free Software Foundation, Inc.
+ Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
Contributed by Richard Guenther <rguenther@suse.de>
This file is part of GCC.
#include "system.h"
#include "coretypes.h"
#include "tm.h"
-#include "ggc.h"
#include "tree.h"
-#include "rtl.h"
#include "tm_p.h"
#include "basic-block.h"
#include "timevar.h"
-#include "diagnostic.h"
+#include "tree-pretty-print.h"
+#include "gimple-pretty-print.h"
#include "tree-flow.h"
#include "tree-pass.h"
#include "tree-dump.h"
edge e;
gcc_assert (is_gimple_assign (use_stmt)
- && gimple_assign_rhs_code (use_stmt) == INDIRECT_REF);
+ && gimple_assign_rhs_code (use_stmt) == MEM_REF);
/* Build a new PHI node to replace the definition of
the indirect reference lhs. */
{
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)
}
else
{
+ tree rhs = gimple_assign_rhs1 (use_stmt);
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);
- 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;
+ new_var = create_tmp_reg (TREE_TYPE (rhs), NULL);
+ if (!is_gimple_min_invariant (old_arg))
+ old_arg = PHI_ARG_DEF_FROM_EDGE (phi, e);
+ else
+ old_arg = unshare_expr (old_arg);
+ tmp = gimple_build_assign (new_var,
+ fold_build2 (MEM_REF, TREE_TYPE (rhs),
+ old_arg,
+ TREE_OPERAND (rhs, 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);
}
}
- add_phi_arg (new_phi, new_var, e);
+ add_phi_arg (new_phi, new_var, e, locus);
}
update_stmt (new_phi);
use_operand_p arg_p, use;
ssa_op_iter i;
bool phi_inserted;
+ tree type = NULL_TREE;
+ bool one_invariant = false;
if (!POINTER_TYPE_P (TREE_TYPE (ptr))
|| !is_gimple_reg_type (TREE_TYPE (TREE_TYPE (ptr))))
return false;
arg = gimple_assign_rhs1 (def_stmt);
}
- if ((TREE_CODE (arg) != ADDR_EXPR
- /* Avoid to have to decay *&a to a[0] later. */
- || !is_gimple_reg_type (TREE_TYPE (TREE_OPERAND (arg, 0))))
+ if (TREE_CODE (arg) != ADDR_EXPR
&& !(TREE_CODE (arg) == SSA_NAME
&& SSA_NAME_VERSION (arg) < n
&& phivn[SSA_NAME_VERSION (arg)].value != NULL_TREE
+ && (!type
+ || types_compatible_p
+ (type, TREE_TYPE (phivn[SSA_NAME_VERSION (arg)].value)))
&& phivn_valid_p (phivn, arg, bb)))
return false;
+ if (!type
+ && TREE_CODE (arg) == SSA_NAME)
+ type = TREE_TYPE (phivn[SSA_NAME_VERSION (arg)].value);
+ if (TREE_CODE (arg) == ADDR_EXPR
+ && is_gimple_min_invariant (arg))
+ one_invariant = true;
}
+ /* If we neither have an address of a decl nor can reuse a previously
+ inserted load, do not hoist anything. */
+ if (!one_invariant
+ && !type)
+ return false;
+
/* Find a dereferencing use. First follow (single use) ssa
copy chains for ptr. */
while (single_imm_use (ptr, &use, &use_stmt)
/* Check whether this is a load of *ptr. */
if (!(is_gimple_assign (use_stmt)
- && TREE_CODE (gimple_assign_lhs (use_stmt)) == SSA_NAME
- && gimple_assign_rhs_code (use_stmt) == INDIRECT_REF
+ && TREE_CODE (gimple_assign_lhs (use_stmt)) == SSA_NAME
+ && gimple_assign_rhs_code (use_stmt) == MEM_REF
&& TREE_OPERAND (gimple_assign_rhs1 (use_stmt), 0) == ptr
+ && integer_zerop (TREE_OPERAND (gimple_assign_rhs1 (use_stmt), 1))
+ && (!type
+ || types_compatible_p
+ (TREE_TYPE (gimple_assign_lhs (use_stmt)), type))
/* We cannot replace a load that may throw or is volatile. */
&& !stmt_can_throw_internal (use_stmt)))
continue;
if (!phi_inserted)
{
res = phiprop_insert_phi (bb, phi, use_stmt, phivn, n);
+ type = TREE_TYPE (res);
/* Remember the value we created for *ptr. */
phivn[SSA_NAME_VERSION (ptr)].value = res;
want to delete it here we also have to delete all intermediate
copies. */
gsi = gsi_for_stmt (use_stmt);
- gsi_remove (&gsi, false);
+ gsi_remove (&gsi, true);
phi_inserted = true;
}
{
VEC(basic_block, heap) *bbs;
struct phiprop_d *phivn;
- bool did_something = false;
+ bool did_something = false;
basic_block bb;
gimple_stmt_iterator gsi;
unsigned i;
/* 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_EACH_VEC_ELT (basic_block, bbs, i, bb)
for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
did_something |= propagate_with_phi (bb, gsi_stmt (gsi), phivn, n);
return flag_tree_phiprop;
}
-struct gimple_opt_pass pass_phiprop =
+struct gimple_opt_pass pass_phiprop =
{
{
GIMPLE_PASS,
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_dump_func
- | TODO_ggc_collect
+ TODO_ggc_collect
| TODO_update_ssa
| TODO_verify_ssa /* todo_flags_finish */
}