#include "tree.h"
#include "diagnostic.h"
#include "tree-flow.h"
-#include "tree-simple.h"
+#include "tree-gimple.h"
#include "tree-dump.h"
#include "tree-pass.h"
#include "timevar.h"
static inline void mark_stmt_necessary (tree, bool);
static inline void mark_operand_necessary (tree);
-static bool need_to_preserve_store (tree);
static void mark_stmt_if_obviously_necessary (tree, bool);
static void find_obviously_necessary_stmts (struct edge_list *);
VARRAY_PUSH_TREE (worklist, stmt);
}
\f
-/* Return true if a store to a variable needs to be preserved. */
-
-static inline bool
-need_to_preserve_store (tree ssa_name)
-{
- return (needs_to_live_in_memory (SSA_NAME_VAR (ssa_name)));
-}
-\f
/* Mark STMT as necessary if it is obviously is. Add it to the worklist if
it can make other statements necessary.
mark_stmt_if_obviously_necessary (tree stmt, bool aggressive)
{
def_optype defs;
- vdef_optype vdefs;
+ v_may_def_optype v_may_defs;
+ v_must_def_optype v_must_defs;
stmt_ann_t ann;
size_t i;
+ tree op;
/* Statements that are implicitly live. Most function calls, asm and return
statements are required. Labels and BIND_EXPR nodes are kept because
return;
case MODIFY_EXPR:
- if (TREE_CODE (TREE_OPERAND (stmt, 1)) == CALL_EXPR
- && TREE_SIDE_EFFECTS (TREE_OPERAND (stmt, 1)))
+ op = get_call_expr_in (stmt);
+ if (op && TREE_SIDE_EFFECTS (op))
{
mark_stmt_necessary (stmt, true);
return;
}
ann = stmt_ann (stmt);
- /* If the statement has volatile operands, it needs to be preserved. Same
- for statements that can alter control flow in unpredictable ways. */
- if (ann->has_volatile_ops
- || is_ctrl_altering_stmt (stmt))
+
+ /* If the statement has volatile operands, it needs to be preserved.
+ Same for statements that can alter control flow in unpredictable
+ ways. */
+ if (ann->has_volatile_ops || is_ctrl_altering_stmt (stmt))
{
mark_stmt_necessary (stmt, true);
return;
for (i = 0; i < NUM_DEFS (defs); i++)
{
tree def = DEF_OP (defs, i);
- if (need_to_preserve_store (def))
+ if (is_global_var (SSA_NAME_VAR (def)))
{
mark_stmt_necessary (stmt, true);
return;
}
}
- vdefs = VDEF_OPS (ann);
- for (i = 0; i < NUM_VDEFS (vdefs); i++)
+ /* Check virtual definitions. If we get here, the only virtual
+ definitions we should see are those generated by assignment
+ statements. */
+ v_may_defs = V_MAY_DEF_OPS (ann);
+ v_must_defs = V_MUST_DEF_OPS (ann);
+ if (NUM_V_MAY_DEFS (v_may_defs) > 0 || NUM_V_MUST_DEFS (v_must_defs) > 0)
{
- tree vdef = VDEF_RESULT (vdefs, i);
- if (need_to_preserve_store (vdef))
+ tree lhs;
+
+#if defined ENABLE_CHECKING
+ if (TREE_CODE (stmt) != MODIFY_EXPR)
+ abort ();
+#endif
+
+ /* Note that we must not check the individual virtual operands
+ here. In particular, if this is an aliased store, we could
+ end up with something like the following (SSA notation
+ redacted for brevity):
+
+ foo (int *p, int i)
+ {
+ int x;
+ p_1 = (i_2 > 3) ? &x : p_1;
+
+ # x_4 = V_MAY_DEF <x_3>
+ *p_1 = 5;
+
+ return 2;
+ }
+
+ Notice that the store to '*p_1' should be preserved, if we
+ were to check the virtual definitions in that store, we would
+ not mark it needed. This is because 'x' is not a global
+ variable.
+
+ Therefore, we check the base address of the LHS. If the
+ address is a pointer, we check if its name tag or type tag is
+ a global variable. Otherwise, we check if the base variable
+ is a global. */
+ lhs = TREE_OPERAND (stmt, 0);
+ if (TREE_CODE_CLASS (TREE_CODE (lhs)) == 'r')
+ lhs = get_base_address (lhs);
+
+ if (lhs == NULL_TREE)
{
+ /* If LHS is NULL, it means that we couldn't get the base
+ address of the reference. In which case, we should not
+ remove this store. */
mark_stmt_necessary (stmt, true);
- return;
- }
+ }
+ else if (DECL_P (lhs))
+ {
+ /* If the store is to a global symbol, we need to keep it. */
+ if (is_global_var (lhs))
+ mark_stmt_necessary (stmt, true);
+ }
+ else if (TREE_CODE (lhs) == INDIRECT_REF)
+ {
+ tree ptr = TREE_OPERAND (lhs, 0);
+ struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
+ tree nmt = (pi) ? pi->name_mem_tag : NULL_TREE;
+ tree tmt = var_ann (SSA_NAME_VAR (ptr))->type_mem_tag;
+
+ /* If either the name tag or the type tag for PTR is a
+ global variable, then the store is necessary. */
+ if ((nmt && is_global_var (nmt))
+ || (tmt && is_global_var (tmt)))
+ {
+ mark_stmt_necessary (stmt, true);
+ return;
+ }
+ }
+ else
+ abort ();
}
return;
tree phi;
/* Check any PHI nodes in the block. */
- for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi))
+ for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
{
NECESSARY (phi) = 0;
Thus, we only need to mark PHIs for real variables which
need their result preserved as being inherently necessary. */
if (is_gimple_reg (PHI_RESULT (phi))
- && need_to_preserve_store (PHI_RESULT (phi)))
+ && is_global_var (SSA_NAME_VAR (PHI_RESULT (phi))))
mark_stmt_necessary (phi, true);
}
{
int edge_number;
+#ifdef ENABLE_CHECKING
+ if (bb == EXIT_BLOCK_PTR)
+ abort ();
+#endif
+
+ if (bb == ENTRY_BLOCK_PTR)
+ return;
+
EXECUTE_IF_CONTROL_DEPENDENT (bb->index, edge_number,
{
tree t;
SET_BIT (last_stmt_necessary, cd_bb->index);
t = last_stmt (cd_bb);
- if (is_ctrl_stmt (t))
+ if (t && is_ctrl_stmt (t))
mark_stmt_necessary (t, true);
});
}
else
{
/* Propagate through the operands. Examine all the USE, VUSE and
- VDEF operands in this statement. Mark all the statements which
- feed this statement's uses as necessary. */
+ V_MAY_DEF operands in this statement. Mark all the statements
+ which feed this statement's uses as necessary. */
vuse_optype vuses;
- vdef_optype vdefs;
+ v_may_def_optype v_may_defs;
use_optype uses;
stmt_ann_t ann;
size_t k;
for (k = 0; k < NUM_VUSES (vuses); k++)
mark_operand_necessary (VUSE_OP (vuses, k));
- /* The operands of VDEF expressions are also needed as they
+ /* The operands of V_MAY_DEF expressions are also needed as they
represent potential definitions that may reach this
- statement (VDEF operands allow us to follow def-def links). */
- vdefs = VDEF_OPS (ann);
- for (k = 0; k < NUM_VDEFS (vdefs); k++)
- mark_operand_necessary (VDEF_OP (vdefs, k));
+ statement (V_MAY_DEF operands allow us to follow def-def
+ links). */
+ v_may_defs = V_MAY_DEF_OPS (ann);
+ for (k = 0; k < NUM_V_MAY_DEFS (v_may_defs); k++)
+ mark_operand_necessary (V_MAY_DEF_OP (v_may_defs, k));
}
}
}
remove_dead_stmt (&i, bb);
else
{
- if (TREE_CODE (t) == CALL_EXPR)
- notice_special_calls (t);
- else if (TREE_CODE (t) == MODIFY_EXPR
- && TREE_CODE (TREE_OPERAND (t, 1)) == CALL_EXPR)
- notice_special_calls (TREE_OPERAND (t, 1));
+ tree call = get_call_expr_in (t);
+ if (call)
+ notice_special_calls (call);
bsi_next (&i);
}
}
if (! NECESSARY (phi))
{
- tree next = TREE_CHAIN (phi);
+ tree next = PHI_CHAIN (phi);
if (dump_file && (dump_flags & TDF_DETAILS))
{
else
{
prev = phi;
- phi = TREE_CHAIN (phi);
+ phi = PHI_CHAIN (phi);
}
}
}
}
bsi_remove (i);
+ release_defs (t);
}
\f
/* Print out removed statement statistics. */
sbitmap_zero (last_stmt_necessary);
}
- processed = sbitmap_alloc (highest_ssa_version + 1);
+ processed = sbitmap_alloc (num_ssa_names + 1);
sbitmap_zero (processed);
VARRAY_TREE_INIT (worklist, 64, "work list");
NULL, /* next */
0, /* static_pass_number */
TV_TREE_DCE, /* tv_id */
- PROP_cfg | PROP_ssa, /* properties_required */
+ PROP_cfg | PROP_ssa | PROP_alias, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
NULL, /* next */
0, /* static_pass_number */
TV_TREE_CD_DCE, /* tv_id */
- PROP_cfg | PROP_ssa, /* properties_required */
+ PROP_cfg | PROP_ssa | PROP_alias, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */