/* SSA Dominator optimizations for trees
- Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
- Free Software Foundation, Inc.
+ Copyright (C) 2001-2013 Free Software Foundation, Inc.
Contributed by Diego Novillo <dnovillo@redhat.com>
This file is part of GCC.
#include "tm_p.h"
#include "basic-block.h"
#include "cfgloop.h"
-#include "output.h"
#include "function.h"
-#include "tree-pretty-print.h"
#include "gimple-pretty-print.h"
-#include "timevar.h"
-#include "tree-dump.h"
#include "tree-flow.h"
#include "domwalk.h"
#include "tree-pass.h"
EXPR_UNARY,
EXPR_BINARY,
EXPR_TERNARY,
- EXPR_CALL
+ EXPR_CALL,
+ EXPR_PHI
};
struct hashable_expr
struct { enum tree_code op; tree opnd; } unary;
struct { enum tree_code op; tree opnd0, opnd1; } binary;
struct { enum tree_code op; tree opnd0, opnd1, opnd2; } ternary;
- struct { tree fn; bool pure; size_t nargs; tree *args; } call;
+ struct { gimple fn_from; bool pure; size_t nargs; tree *args; } call;
+ struct { size_t nargs; tree *args; } phi;
} ops;
};
tree value;
} cond_equivalence;
-DEF_VEC_O(cond_equivalence);
-DEF_VEC_ALLOC_O(cond_equivalence,heap);
/* Structure for recording edge equivalences as well as any pending
edge redirections during the dominator optimizer.
/* Traversing an edge may also indicate one or more particular conditions
are true or false. */
- VEC(cond_equivalence, heap) *cond_equivalences;
+ vec<cond_equivalence> cond_equivalences;
};
/* Hash table with expressions made available during the renaming process.
remove the expressions from the global hash table until we hit the
marker. */
typedef struct expr_hash_elt * expr_hash_elt_t;
-DEF_VEC_P(expr_hash_elt_t);
-DEF_VEC_ALLOC_P(expr_hash_elt_t,heap);
-static VEC(expr_hash_elt_t,heap) *avail_exprs_stack;
+static vec<expr_hash_elt_t> avail_exprs_stack;
/* Structure for entries in the expression hash table. */
A NULL entry is used to mark the end of pairs which need to be
restored during finalization of this block. */
-static VEC(tree,heap) *const_and_copies_stack;
+static vec<tree> const_and_copies_stack;
/* Track whether or not we have changed the control flow graph. */
static bool cfg_altered;
{
enum tree_code subcode = gimple_assign_rhs_code (stmt);
- expr->type = NULL_TREE;
-
switch (get_gimple_rhs_class (subcode))
{
case GIMPLE_SINGLE_RHS:
expr->kind = EXPR_SINGLE;
+ expr->type = TREE_TYPE (gimple_assign_rhs1 (stmt));
expr->ops.single.rhs = gimple_assign_rhs1 (stmt);
break;
case GIMPLE_UNARY_RHS:
expr->type = TREE_TYPE (gimple_call_lhs (stmt));
expr->kind = EXPR_CALL;
- expr->ops.call.fn = gimple_call_fn (stmt);
+ expr->ops.call.fn_from = stmt;
if (gimple_call_flags (stmt) & (ECF_CONST | ECF_PURE))
expr->ops.call.pure = true;
expr->ops.call.pure = false;
expr->ops.call.nargs = nargs;
- expr->ops.call.args = (tree *) xcalloc (nargs, sizeof (tree));
+ expr->ops.call.args = XCNEWVEC (tree, nargs);
for (i = 0; i < nargs; i++)
expr->ops.call.args[i] = gimple_call_arg (stmt, i);
}
expr->kind = EXPR_SINGLE;
expr->ops.single.rhs = gimple_goto_dest (stmt);
}
+ else if (code == GIMPLE_PHI)
+ {
+ size_t nargs = gimple_phi_num_args (stmt);
+ size_t i;
+
+ expr->type = TREE_TYPE (gimple_phi_result (stmt));
+ expr->kind = EXPR_PHI;
+ expr->ops.phi.nargs = nargs;
+ expr->ops.phi.args = XCNEWVEC (tree, nargs);
+
+ for (i = 0; i < nargs; i++)
+ expr->ops.phi.args[i] = gimple_phi_arg_def (stmt, i);
+ }
else
gcc_unreachable ();
/* If the calls are to different functions, then they
clearly cannot be equal. */
- if (! operand_equal_p (expr0->ops.call.fn,
- expr1->ops.call.fn, 0))
+ if (!gimple_call_same_target_p (expr0->ops.call.fn_from,
+ expr1->ops.call.fn_from))
return false;
if (! expr0->ops.call.pure)
return true;
}
+ case EXPR_PHI:
+ {
+ size_t i;
+
+ if (expr0->ops.phi.nargs != expr1->ops.phi.nargs)
+ return false;
+
+ for (i = 0; i < expr0->ops.phi.nargs; i++)
+ if (! operand_equal_p (expr0->ops.phi.args[i],
+ expr1->ops.phi.args[i], 0))
+ return false;
+
+ return true;
+ }
+
default:
gcc_unreachable ();
}
{
size_t i;
enum tree_code code = CALL_EXPR;
+ gimple fn_from;
val = iterative_hash_object (code, val);
- val = iterative_hash_expr (expr->ops.call.fn, val);
+ fn_from = expr->ops.call.fn_from;
+ if (gimple_call_internal_p (fn_from))
+ val = iterative_hash_hashval_t
+ ((hashval_t) gimple_call_internal_fn (fn_from), val);
+ else
+ val = iterative_hash_expr (gimple_call_fn (fn_from), val);
for (i = 0; i < expr->ops.call.nargs; i++)
val = iterative_hash_expr (expr->ops.call.args[i], val);
}
break;
+ case EXPR_PHI:
+ {
+ size_t i;
+
+ for (i = 0; i < expr->ops.phi.nargs; i++)
+ val = iterative_hash_expr (expr->ops.phi.args[i], val);
+ }
+ break;
+
default:
gcc_unreachable ();
}
{
size_t i;
size_t nargs = element->expr.ops.call.nargs;
-
- print_generic_expr (stream, element->expr.ops.call.fn, 0);
+ gimple fn_from;
+
+ fn_from = element->expr.ops.call.fn_from;
+ if (gimple_call_internal_p (fn_from))
+ fputs (internal_fn_name (gimple_call_internal_fn (fn_from)),
+ stream);
+ else
+ print_generic_expr (stream, gimple_call_fn (fn_from), 0);
fprintf (stream, " (");
for (i = 0; i < nargs; i++)
{
fprintf (stream, ")");
}
break;
+
+ case EXPR_PHI:
+ {
+ size_t i;
+ size_t nargs = element->expr.ops.phi.nargs;
+
+ fprintf (stream, "PHI <");
+ for (i = 0; i < nargs; i++)
+ {
+ print_generic_expr (stream, element->expr.ops.phi.args[i], 0);
+ if (i + 1 < nargs)
+ fprintf (stream, ", ");
+ }
+ fprintf (stream, ">");
+ }
+ break;
}
fprintf (stream, "\n");
}
}
-/* Delete an expr_hash_elt and reclaim its storage. */
+/* Delete variable sized pieces of the expr_hash_elt ELEMENT. */
static void
-free_expr_hash_elt (void *elt)
+free_expr_hash_elt_contents (struct expr_hash_elt *element)
{
- struct expr_hash_elt *element = ((struct expr_hash_elt *)elt);
-
if (element->expr.kind == EXPR_CALL)
free (element->expr.ops.call.args);
+ else if (element->expr.kind == EXPR_PHI)
+ free (element->expr.ops.phi.args);
+}
+
+/* Delete an expr_hash_elt and reclaim its storage. */
+static void
+free_expr_hash_elt (void *elt)
+{
+ struct expr_hash_elt *element = ((struct expr_hash_elt *)elt);
+ free_expr_hash_elt_contents (element);
free (element);
}
if (edge_info)
{
- if (edge_info->cond_equivalences)
- VEC_free (cond_equivalence, heap, edge_info->cond_equivalences);
+ edge_info->cond_equivalences.release ();
free (edge_info);
e->aux = NULL;
}
/* Create our hash tables. */
avail_exprs = htab_create (1024, real_avail_expr_hash, avail_expr_eq, free_expr_hash_elt);
- avail_exprs_stack = VEC_alloc (expr_hash_elt_t, heap, 20);
- const_and_copies_stack = VEC_alloc (tree, heap, 20);
+ avail_exprs_stack.create (20);
+ const_and_copies_stack.create (20);
need_eh_cleanup = BITMAP_ALLOC (NULL);
/* Setup callbacks for the generic dominator tree walker. */
gimple_stmt_iterator gsi;
basic_block bb;
FOR_EACH_BB (bb)
- {for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
update_stmt_if_modified (gsi_stmt (gsi));
}
}
/* Jump threading may have created forwarder blocks from blocks
needing EH cleanup; the new successor of these blocks, which
- has inherited from the original block, needs the cleanup. */
+ has inherited from the original block, needs the cleanup.
+ Don't clear bits in the bitmap, as that can break the bitmap
+ iterator. */
EXECUTE_IF_SET_IN_BITMAP (need_eh_cleanup, 0, i, bi)
{
basic_block bb = BASIC_BLOCK (i);
- if (single_succ_p (bb) == 1
- && (single_succ_edge (bb)->flags & EDGE_EH) == 0)
- {
- bitmap_clear_bit (need_eh_cleanup, i);
- bitmap_set_bit (need_eh_cleanup, single_succ (bb)->index);
- }
+ if (bb == NULL)
+ continue;
+ while (single_succ_p (bb)
+ && (single_succ_edge (bb)->flags & EDGE_EH) == 0)
+ bb = single_succ (bb);
+ if (bb == EXIT_BLOCK_PTR)
+ continue;
+ if ((unsigned) bb->index != i)
+ bitmap_set_bit (need_eh_cleanup, bb->index);
}
gimple_purge_all_dead_eh_edges (need_eh_cleanup);
- bitmap_zero (need_eh_cleanup);
+ bitmap_clear (need_eh_cleanup);
}
statistics_counter_event (cfun, "Redundant expressions eliminated",
/* Free asserted bitmaps and stacks. */
BITMAP_FREE (need_eh_cleanup);
- VEC_free (expr_hash_elt_t, heap, avail_exprs_stack);
- VEC_free (tree, heap, const_and_copies_stack);
+ avail_exprs_stack.release ();
+ const_and_copies_stack.release ();
/* Free the value-handle array. */
threadedge_finalize_values ();
- ssa_name_values = NULL;
+ ssa_name_values.release ();
return 0;
}
{
GIMPLE_PASS,
"dom", /* name */
+ OPTGROUP_NONE, /* optinfo_flags */
gate_dominator, /* gate */
tree_ssa_dominator_optimize, /* execute */
NULL, /* sub */
TODO_cleanup_cfg
| TODO_update_ssa
| TODO_verify_ssa
- | TODO_verify_flow
- | TODO_dump_func /* todo_flags_finish */
+ | TODO_verify_flow /* todo_flags_finish */
}
};
remove_local_expressions_from_table (void)
{
/* Remove all the expressions made available in this block. */
- while (VEC_length (expr_hash_elt_t, avail_exprs_stack) > 0)
+ while (avail_exprs_stack.length () > 0)
{
- expr_hash_elt_t victim = VEC_pop (expr_hash_elt_t, avail_exprs_stack);
+ expr_hash_elt_t victim = avail_exprs_stack.pop ();
void **slot;
if (victim == NULL)
static void
restore_vars_to_original_value (void)
{
- while (VEC_length (tree, const_and_copies_stack) > 0)
+ while (const_and_copies_stack.length () > 0)
{
tree prev_value, dest;
- dest = VEC_pop (tree, const_and_copies_stack);
+ dest = const_and_copies_stack.pop ();
if (dest == NULL)
break;
fprintf (dump_file, "\n");
}
- prev_value = VEC_pop (tree, const_and_copies_stack);
+ prev_value = const_and_copies_stack.pop ();
set_ssa_name_value (dest, prev_value);
}
}
if (lhs)
record_equality (lhs, rhs);
- for (i = 0; VEC_iterate (cond_equivalence,
- edge_info->cond_equivalences, i, eq); ++i)
+ /* If LHS is an SSA_NAME and RHS is a constant integer and LHS was
+ set via a widening type conversion, then we may be able to record
+ additional equivalences. */
+ if (lhs
+ && TREE_CODE (lhs) == SSA_NAME
+ && is_gimple_constant (rhs)
+ && TREE_CODE (rhs) == INTEGER_CST)
+ {
+ gimple defstmt = SSA_NAME_DEF_STMT (lhs);
+
+ if (defstmt
+ && is_gimple_assign (defstmt)
+ && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (defstmt)))
+ {
+ tree old_rhs = gimple_assign_rhs1 (defstmt);
+
+ /* If the conversion widens the original value and
+ the constant is in the range of the type of OLD_RHS,
+ then convert the constant and record the equivalence.
+
+ Note that int_fits_type_p does not check the precision
+ if the upper and lower bounds are OK. */
+ if (INTEGRAL_TYPE_P (TREE_TYPE (old_rhs))
+ && (TYPE_PRECISION (TREE_TYPE (lhs))
+ > TYPE_PRECISION (TREE_TYPE (old_rhs)))
+ && int_fits_type_p (rhs, TREE_TYPE (old_rhs)))
+ {
+ tree newval = fold_convert (TREE_TYPE (old_rhs), rhs);
+ record_equality (old_rhs, newval);
+ }
+ }
+ }
+
+ for (i = 0; edge_info->cond_equivalences.iterate (i, &eq); ++i)
record_cond (eq);
}
}
print_expr_hash_elt (dump_file, element);
}
- VEC_safe_push (expr_hash_elt_t, heap, avail_exprs_stack, element);
+ avail_exprs_stack.safe_push (element);
}
else
- free (element);
+ free_expr_hash_elt (element);
}
/* Build a cond_equivalence record indicating that the comparison
static void
build_and_record_new_cond (enum tree_code code,
tree op0, tree op1,
- VEC(cond_equivalence, heap) **p)
+ vec<cond_equivalence> *p)
{
cond_equivalence c;
struct hashable_expr *cond = &c.cond;
cond->ops.binary.opnd1 = op1;
c.value = boolean_true_node;
- VEC_safe_push (cond_equivalence, heap, *p, &c);
+ p->safe_push (c);
}
/* Record that COND is true and INVERTED is false into the edge information
two slots. */
initialize_expr_from_cond (cond, &c.cond);
c.value = boolean_true_node;
- VEC_safe_push (cond_equivalence, heap, edge_info->cond_equivalences, &c);
+ edge_info->cond_equivalences.safe_push (c);
/* It is possible for INVERTED to be the negation of a comparison,
and not a valid RHS or GIMPLE_COND condition. This happens because
obey the trichotomy law. */
initialize_expr_from_cond (inverted, &c.cond);
c.value = boolean_false_node;
- VEC_safe_push (cond_equivalence, heap, edge_info->cond_equivalences, &c);
+ edge_info->cond_equivalences.safe_push (c);
}
/* A helper function for record_const_or_copy and record_equality.
fprintf (dump_file, "\n");
}
- VEC_reserve (tree, heap, const_and_copies_stack, 2);
- VEC_quick_push (tree, const_and_copies_stack, prev_x);
- VEC_quick_push (tree, const_and_copies_stack, x);
+ const_and_copies_stack.reserve (2);
+ const_and_copies_stack.quick_push (prev_x);
+ const_and_copies_stack.quick_push (x);
}
/* Return the loop depth of the basic block of the defining statement of X.
if (!defbb)
return 0;
- return defbb->loop_depth;
+ return bb_loop_depth (defbb);
}
/* Record that X is equal to Y in const_and_copies. Record undo
i_1 = phi (..., i_2)
i_2 = i_1 +/- ... */
-static bool
+bool
simple_iv_increment_p (gimple stmt)
{
+ enum tree_code code;
tree lhs, preinc;
gimple phi;
size_t i;
if (TREE_CODE (lhs) != SSA_NAME)
return false;
- if (gimple_assign_rhs_code (stmt) != PLUS_EXPR
- && gimple_assign_rhs_code (stmt) != MINUS_EXPR)
+ code = gimple_assign_rhs_code (stmt);
+ if (code != PLUS_EXPR
+ && code != MINUS_EXPR
+ && code != POINTER_PLUS_EXPR)
return false;
preinc = gimple_assign_rhs1 (stmt);
-
if (TREE_CODE (preinc) != SSA_NAME)
return false;
{
tree cond = build2 (code, boolean_type_node, op0, op1);
tree inverted = invert_truthvalue_loc (loc, cond);
+ bool can_infer_simple_equiv
+ = !(HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (op0)))
+ && real_zerop (op0));
struct edge_info *edge_info;
edge_info = allocate_edge_info (true_edge);
record_conditions (edge_info, cond, inverted);
- if (code == EQ_EXPR)
+ if (can_infer_simple_equiv && code == EQ_EXPR)
{
edge_info->lhs = op1;
edge_info->rhs = op0;
edge_info = allocate_edge_info (false_edge);
record_conditions (edge_info, inverted, cond);
- if (TREE_CODE (inverted) == EQ_EXPR)
+ if (can_infer_simple_equiv && TREE_CODE (inverted) == EQ_EXPR)
{
edge_info->lhs = op1;
edge_info->rhs = op0;
}
else if (TREE_CODE (op0) == SSA_NAME
- && (is_gimple_min_invariant (op1)
- || TREE_CODE (op1) == SSA_NAME))
+ && (TREE_CODE (op1) == SSA_NAME
+ || is_gimple_min_invariant (op1)))
{
tree cond = build2 (code, boolean_type_node, op0, op1);
tree inverted = invert_truthvalue_loc (loc, cond);
+ bool can_infer_simple_equiv
+ = !(HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (op1)))
+ && (TREE_CODE (op1) == SSA_NAME || real_zerop (op1)));
struct edge_info *edge_info;
edge_info = allocate_edge_info (true_edge);
record_conditions (edge_info, cond, inverted);
- if (code == EQ_EXPR)
+ if (can_infer_simple_equiv && code == EQ_EXPR)
{
edge_info->lhs = op0;
edge_info->rhs = op1;
edge_info = allocate_edge_info (false_edge);
record_conditions (edge_info, inverted, cond);
- if (TREE_CODE (inverted) == EQ_EXPR)
+ if (can_infer_simple_equiv && TREE_CODE (inverted) == EQ_EXPR)
{
edge_info->lhs = op0;
edge_info->rhs = op1;
/* Push a marker on the stacks of local information so that we know how
far to unwind when we finalize this block. */
- VEC_safe_push (expr_hash_elt_t, heap, avail_exprs_stack, NULL);
- VEC_safe_push (tree, heap, const_and_copies_stack, NULL_TREE);
+ avail_exprs_stack.safe_push (NULL);
+ const_and_copies_stack.safe_push (NULL_TREE);
record_equivalences_from_incoming_edge (bb);
/* PHI nodes can create equivalences too. */
record_equivalences_from_phis (bb);
+ /* Create equivalences from redundant PHIs. PHIs are only truly
+ redundant when they exist in the same block, so push another
+ marker and unwind right afterwards. */
+ avail_exprs_stack.safe_push (NULL);
+ for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+ eliminate_redundant_computations (&gsi);
+ remove_local_expressions_from_table ();
+
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
optimize_stmt (bb, gsi);
&& (single_succ_edge (bb)->flags & EDGE_ABNORMAL) == 0
&& potentially_threadable_block (single_succ (bb)))
{
+ /* Push a marker on the stack, which thread_across_edge expects
+ and will remove. */
+ const_and_copies_stack.safe_push (NULL_TREE);
dom_thread_across_edge (walk_data, single_succ_edge (bb));
}
else if ((last = last_stmt (bb))
/* Push a marker onto the available expression stack so that we
unwind any expressions related to the TRUE arm before processing
the false arm below. */
- VEC_safe_push (expr_hash_elt_t, heap, avail_exprs_stack, NULL);
- VEC_safe_push (tree, heap, const_and_copies_stack, NULL_TREE);
+ avail_exprs_stack.safe_push (NULL);
+ const_and_copies_stack.safe_push (NULL_TREE);
edge_info = (struct edge_info *) true_edge->aux;
/* If we have 0 = COND or 1 = COND equivalences, record them
into our expression hash tables. */
- for (i = 0; VEC_iterate (cond_equivalence,
- edge_info->cond_equivalences, i, eq); ++i)
+ for (i = 0; edge_info->cond_equivalences.iterate (i, &eq); ++i)
record_cond (eq);
}
struct edge_info *edge_info;
unsigned int i;
- VEC_safe_push (tree, heap, const_and_copies_stack, NULL_TREE);
+ const_and_copies_stack.safe_push (NULL_TREE);
edge_info = (struct edge_info *) false_edge->aux;
/* If we have info associated with this edge, record it into
/* If we have 0 = COND or 1 = COND equivalences, record them
into our expression hash tables. */
- for (i = 0; VEC_iterate (cond_equivalence,
- edge_info->cond_equivalences, i, eq); ++i)
+ for (i = 0; edge_info->cond_equivalences.iterate (i, &eq); ++i)
record_cond (eq);
}
{
tree expr_type;
tree cached_lhs;
+ tree def;
bool insert = true;
bool assigns_var_p = false;
gimple stmt = gsi_stmt (*gsi);
- tree def = gimple_get_lhs (stmt);
+ if (gimple_code (stmt) == GIMPLE_PHI)
+ def = gimple_phi_result (stmt);
+ else
+ def = gimple_get_lhs (stmt);
/* Certain expressions on the RHS can be optimized away, but can not
themselves be entered into the hash tables. */
}
else if (gimple_code (stmt) == GIMPLE_SWITCH)
expr_type = TREE_TYPE (gimple_switch_index (stmt));
+ else if (gimple_code (stmt) == GIMPLE_PHI)
+ /* We can't propagate into a phi, so the logic below doesn't apply.
+ Instead record an equivalence between the cached LHS and the
+ PHI result of this statement, provided they are in the same block.
+ This should be sufficient to kill the redundant phi. */
+ {
+ if (def && cached_lhs)
+ record_const_or_copy (def, cached_lhs);
+ return;
+ }
else
gcc_unreachable ();
val = SSA_NAME_VALUE (op);
if (val && val != op)
{
- /* Do not change the base variable in the virtual operand
- tables. That would make it impossible to reconstruct
- the renamed virtual operand if we later modify this
- statement. Also only allow the new value to be an SSA_NAME
- for propagation into virtual operands. */
- if (!is_gimple_reg (op)
- && (TREE_CODE (val) != SSA_NAME
- || is_gimple_reg (val)
- || get_virtual_var (val) != get_virtual_var (op)))
- return;
-
/* Do not replace hard register operands in asm statements. */
if (gimple_code (stmt) == GIMPLE_ASM
&& !may_propagate_copy_into_asm (op))
use_operand_p op_p;
ssa_op_iter iter;
- FOR_EACH_SSA_USE_OPERAND (op_p, stmt, iter, SSA_OP_ALL_USES)
- {
- if (TREE_CODE (USE_FROM_PTR (op_p)) == SSA_NAME)
- cprop_operand (stmt, op_p);
- }
+ FOR_EACH_SSA_USE_OPERAND (op_p, stmt, iter, SSA_OP_USE)
+ cprop_operand (stmt, op_p);
}
/* Optimize the statement pointed to by iterator SI.
old_stmt = stmt = gsi_stmt (si);
- if (gimple_code (stmt) == GIMPLE_COND)
- canonicalize_comparison (stmt);
-
- update_stmt_if_modified (stmt);
- opt_stats.num_stmts++;
-
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "Optimizing statement ");
print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
}
+ if (gimple_code (stmt) == GIMPLE_COND)
+ canonicalize_comparison (stmt);
+
+ update_stmt_if_modified (stmt);
+ opt_stats.num_stmts++;
+
/* Const/copy propagate into USES, VUSES and the RHS of VDEFs. */
cprop_into_stmt (stmt);
/* Check for redundant computations. Do this optimization only
for assignments that have no volatile ops and conditionals. */
- may_optimize_p = (!gimple_has_volatile_ops (stmt)
- && ((is_gimple_assign (stmt)
- && !gimple_rhs_has_side_effects (stmt))
+ may_optimize_p = (!gimple_has_side_effects (stmt)
+ && (is_gimple_assign (stmt)
|| (is_gimple_call (stmt)
- && gimple_call_lhs (stmt) != NULL_TREE
- && !gimple_rhs_has_side_effects (stmt))
+ && gimple_call_lhs (stmt) != NULL_TREE)
|| gimple_code (stmt) == GIMPLE_COND
|| gimple_code (stmt) == GIMPLE_SWITCH));
&& rhs == cached_lhs)
{
basic_block bb = gimple_bb (stmt);
- int lp_nr = lookup_stmt_eh_lp (stmt);
unlink_stmt_vdef (stmt);
- gsi_remove (&si, true);
- if (lp_nr != 0)
+ if (gsi_remove (&si, true))
{
bitmap_set_bit (need_eh_cleanup, bb->index);
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, " Flagged to clear EH edges.\n");
}
+ release_defs (stmt);
return;
}
}
tree temp;
struct expr_hash_elt element;
- /* Get LHS of assignment or call, else NULL_TREE. */
- lhs = gimple_get_lhs (stmt);
+ /* Get LHS of phi, assignment, or call; else NULL_TREE. */
+ if (gimple_code (stmt) == GIMPLE_PHI)
+ lhs = gimple_phi_result (stmt);
+ else
+ lhs = gimple_get_lhs (stmt);
initialize_hash_element (stmt, lhs, &element);
slot = htab_find_slot_with_hash (avail_exprs, &element, element.hash,
(insert ? INSERT : NO_INSERT));
if (slot == NULL)
- return NULL_TREE;
-
- if (*slot == NULL)
+ {
+ free_expr_hash_elt_contents (&element);
+ return NULL_TREE;
+ }
+ else if (*slot == NULL)
{
struct expr_hash_elt *element2 = XNEW (struct expr_hash_elt);
*element2 = element;
print_expr_hash_elt (dump_file, element2);
}
- VEC_safe_push (expr_hash_elt_t, heap, avail_exprs_stack, element2);
+ avail_exprs_stack.safe_push (element2);
return NULL_TREE;
}
+ else
+ free_expr_hash_elt_contents (&element);
/* Extract the LHS of the assignment so that it can be used as the current
definition of another variable. */
/* Special cases to avoid useless calls into the folding
routines, operand scanning, etc.
- First, propagation into a PHI may cause the PHI to become
+ Propagation into a PHI may cause the PHI to become
a degenerate, so mark the PHI as interesting. No other
- actions are necessary.
-
- Second, if we're propagating a virtual operand and the
- propagation does not change the underlying _DECL node for
- the virtual operand, then no further actions are necessary. */
- if (gimple_code (use_stmt) == GIMPLE_PHI
- || (! is_gimple_reg (lhs)
- && TREE_CODE (rhs) == SSA_NAME
- && SSA_NAME_VAR (lhs) == SSA_NAME_VAR (rhs)))
+ actions are necessary. */
+ if (gimple_code (use_stmt) == GIMPLE_PHI)
{
+ tree result;
+
/* Dump details. */
if (dump_file && (dump_flags & TDF_DETAILS))
{
print_gimple_stmt (dump_file, use_stmt, 0, dump_flags);
}
- /* Propagation into a PHI may expose new degenerate PHIs,
- so mark the result of the PHI as interesting. */
- if (gimple_code (use_stmt) == GIMPLE_PHI)
- {
- tree result = get_lhs_or_phi_result (use_stmt);
- bitmap_set_bit (interesting_names, SSA_NAME_VERSION (result));
- }
-
+ result = get_lhs_or_phi_result (use_stmt);
+ bitmap_set_bit (interesting_names, SSA_NAME_VERSION (result));
continue;
}
GIMPLE_ASSIGN, and there is no way to effect such a
transformation in-place. We might want to consider
using the more general fold_stmt here. */
- fold_stmt_inplace (use_stmt);
+ {
+ gimple_stmt_iterator gsi = gsi_for_stmt (use_stmt);
+ fold_stmt_inplace (&gsi);
+ }
/* Sometimes propagation can expose new operands to the
renamer. */
}
if (cfg_altered)
- free_dominance_info (CDI_DOMINATORS);
+ {
+ free_dominance_info (CDI_DOMINATORS);
+ /* If we changed the CFG schedule loops for fixup by cfgcleanup. */
+ if (current_loops)
+ loops_state_set (LOOPS_NEED_FIXUP);
+ }
/* Propagation of const and copies may make some EH edges dead. Purge
such edges from the CFG as needed. */
{
GIMPLE_PASS,
"phicprop", /* name */
+ OPTGROUP_NONE, /* optinfo_flags */
gate_dominator, /* gate */
eliminate_degenerate_phis, /* execute */
NULL, /* sub */
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_cleanup_cfg
- | TODO_dump_func
- | TODO_ggc_collect
| TODO_verify_ssa
| TODO_verify_stmts
| TODO_update_ssa /* todo_flags_finish */