| Index: gcc/gcc/tree-ssa-dom.c
|
| diff --git a/gcc/gcc/tree-ssa-dom.c b/gcc/gcc/tree-ssa-dom.c
|
| index 3f9e1e8e2929480569683b0b23c08f76702acf73..8b799a3bd1f4d0b534fef3523e421d05d03d110c 100644
|
| --- a/gcc/gcc/tree-ssa-dom.c
|
| +++ b/gcc/gcc/tree-ssa-dom.c
|
| @@ -1,5 +1,5 @@
|
| /* SSA Dominator optimizations for trees
|
| - Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
|
| + Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
|
| Free Software Foundation, Inc.
|
| Contributed by Diego Novillo <dnovillo@redhat.com>
|
|
|
| @@ -83,7 +83,7 @@ struct cond_equivalence
|
|
|
| Computing and storing the edge equivalences instead of creating
|
| them on-demand can save significant amounts of time, particularly
|
| - for pathological cases involving switch statements.
|
| + for pathological cases involving switch statements.
|
|
|
| These structures live for a single iteration of the dominator
|
| optimizer in the edge's AUX field. At the end of an iteration we
|
| @@ -127,19 +127,6 @@ DEF_VEC_ALLOC_P(expr_hash_elt_t,heap);
|
|
|
| static VEC(expr_hash_elt_t,heap) *avail_exprs_stack;
|
|
|
| -/* Stack of statements we need to rescan during finalization for newly
|
| - exposed variables.
|
| -
|
| - Statement rescanning must occur after the current block's available
|
| - expressions are removed from AVAIL_EXPRS. Else we may change the
|
| - hash code for an expression and be unable to find/remove it from
|
| - AVAIL_EXPRS. */
|
| -typedef gimple *gimple_p;
|
| -DEF_VEC_P(gimple_p);
|
| -DEF_VEC_ALLOC_P(gimple_p,heap);
|
| -
|
| -static VEC(gimple_p,heap) *stmts_to_rescan;
|
| -
|
| /* Structure for entries in the expression hash table. */
|
|
|
| struct expr_hash_elt
|
| @@ -187,9 +174,7 @@ struct opt_stats_d
|
| static struct opt_stats_d opt_stats;
|
|
|
| /* Local functions. */
|
| -static void optimize_stmt (struct dom_walk_data *,
|
| - basic_block,
|
| - gimple_stmt_iterator);
|
| +static void optimize_stmt (basic_block, gimple_stmt_iterator);
|
| static tree lookup_avail_expr (gimple, bool);
|
| static hashval_t avail_expr_hash (const void *);
|
| static hashval_t real_avail_expr_hash (const void *);
|
| @@ -200,12 +185,11 @@ static void record_const_or_copy (tree, tree);
|
| static void record_equality (tree, tree);
|
| static void record_equivalences_from_phis (basic_block);
|
| static void record_equivalences_from_incoming_edge (basic_block);
|
| -static bool eliminate_redundant_computations (gimple_stmt_iterator *);
|
| +static void eliminate_redundant_computations (gimple_stmt_iterator *);
|
| static void record_equivalences_from_stmt (gimple, int);
|
| static void dom_thread_across_edge (struct dom_walk_data *, edge);
|
| -static void dom_opt_finalize_block (struct dom_walk_data *, basic_block);
|
| -static void dom_opt_initialize_block (struct dom_walk_data *, basic_block);
|
| -static void propagate_to_outgoing_edges (struct dom_walk_data *, basic_block);
|
| +static void dom_opt_leave_block (struct dom_walk_data *, basic_block);
|
| +static void dom_opt_enter_block (struct dom_walk_data *, basic_block);
|
| static void remove_local_expressions_from_table (void);
|
| static void restore_vars_to_original_value (void);
|
| static edge single_incoming_edge_ignoring_loop_edges (basic_block);
|
| @@ -226,7 +210,7 @@ initialize_hash_element (gimple stmt, tree lhs,
|
| enum tree_code subcode = gimple_assign_rhs_code (stmt);
|
|
|
| expr->type = NULL_TREE;
|
| -
|
| +
|
| switch (get_gimple_rhs_class (subcode))
|
| {
|
| case GIMPLE_SINGLE_RHS:
|
| @@ -271,7 +255,7 @@ initialize_hash_element (gimple stmt, tree lhs,
|
|
|
| if (gimple_call_flags (stmt) & (ECF_CONST | ECF_PURE))
|
| expr->ops.call.pure = true;
|
| - else
|
| + else
|
| expr->ops.call.pure = false;
|
|
|
| expr->ops.call.nargs = nargs;
|
| @@ -309,7 +293,7 @@ static void
|
| initialize_expr_from_cond (tree cond, struct hashable_expr *expr)
|
| {
|
| expr->type = boolean_type_node;
|
| -
|
| +
|
| if (COMPARISON_CLASS_P (cond))
|
| {
|
| expr->kind = EXPR_BINARY;
|
| @@ -431,7 +415,7 @@ hashable_expr_equal_p (const struct hashable_expr *expr0,
|
|
|
| return true;
|
| }
|
| -
|
| +
|
| default:
|
| gcc_unreachable ();
|
| }
|
| @@ -489,7 +473,7 @@ iterative_hash_hashable_expr (const struct hashable_expr *expr, hashval_t val)
|
| val = iterative_hash_expr (expr->ops.call.args[i], val);
|
| }
|
| break;
|
| -
|
| +
|
| default:
|
| gcc_unreachable ();
|
| }
|
| @@ -512,7 +496,7 @@ print_expr_hash_elt (FILE * stream, const struct expr_hash_elt *element)
|
| print_generic_expr (stream, element->lhs, 0);
|
| fprintf (stream, " = ");
|
| }
|
| -
|
| +
|
| switch (element->expr.kind)
|
| {
|
| case EXPR_SINGLE:
|
| @@ -613,7 +597,7 @@ free_all_edge_infos (void)
|
| }
|
| }
|
|
|
| -/* Jump threading, redundancy elimination and const/copy propagation.
|
| +/* Jump threading, redundancy elimination and const/copy propagation.
|
|
|
| This pass may expose new symbols that need to be renamed into SSA. For
|
| every new symbol exposed, its corresponding bit will be set in
|
| @@ -623,7 +607,6 @@ static unsigned int
|
| tree_ssa_dominator_optimize (void)
|
| {
|
| struct dom_walk_data walk_data;
|
| - unsigned int i;
|
|
|
| memset (&opt_stats, 0, sizeof (opt_stats));
|
|
|
| @@ -631,25 +614,18 @@ tree_ssa_dominator_optimize (void)
|
| 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);
|
| - stmts_to_rescan = VEC_alloc (gimple_p, heap, 20);
|
| need_eh_cleanup = BITMAP_ALLOC (NULL);
|
|
|
| /* Setup callbacks for the generic dominator tree walker. */
|
| - walk_data.walk_stmts_backward = false;
|
| walk_data.dom_direction = CDI_DOMINATORS;
|
| walk_data.initialize_block_local_data = NULL;
|
| - walk_data.before_dom_children_before_stmts = dom_opt_initialize_block;
|
| - walk_data.before_dom_children_walk_stmts = optimize_stmt;
|
| - walk_data.before_dom_children_after_stmts = propagate_to_outgoing_edges;
|
| - walk_data.after_dom_children_before_stmts = NULL;
|
| - walk_data.after_dom_children_walk_stmts = NULL;
|
| - walk_data.after_dom_children_after_stmts = dom_opt_finalize_block;
|
| + walk_data.before_dom_children = dom_opt_enter_block;
|
| + walk_data.after_dom_children = dom_opt_leave_block;
|
| /* Right now we only attach a dummy COND_EXPR to the global data pointer.
|
| When we attach more stuff we'll need to fill this out with a real
|
| structure. */
|
| walk_data.global_data = NULL;
|
| walk_data.block_local_data_size = 0;
|
| - walk_data.interesting_blocks = NULL;
|
|
|
| /* Now initialize the dominator walker. */
|
| init_walk_dominator_tree (&walk_data);
|
| @@ -663,11 +639,14 @@ tree_ssa_dominator_optimize (void)
|
| that we update the loop info. */
|
| loop_optimizer_init (LOOPS_HAVE_SIMPLE_LATCHES);
|
|
|
| + /* Initialize the value-handle array. */
|
| + threadedge_initialize_values ();
|
| +
|
| /* We need accurate information regarding back edges in the CFG
|
| for jump threading; this may include back edges that are not part of
|
| a single loop. */
|
| mark_dfs_back_edges ();
|
| -
|
| +
|
| /* Recursively walk the dominator tree optimizing statements. */
|
| walk_dominator_tree (&walk_data, ENTRY_BLOCK_PTR);
|
|
|
| @@ -720,23 +699,6 @@ tree_ssa_dominator_optimize (void)
|
| bitmap_zero (need_eh_cleanup);
|
| }
|
|
|
| - /* Finally, remove everything except invariants in SSA_NAME_VALUE.
|
| -
|
| - Long term we will be able to let everything in SSA_NAME_VALUE
|
| - persist. However, for now, we know this is the safe thing to do. */
|
| - for (i = 0; i < num_ssa_names; i++)
|
| - {
|
| - tree name = ssa_name (i);
|
| - tree value;
|
| -
|
| - if (!name)
|
| - continue;
|
| -
|
| - value = SSA_NAME_VALUE (name);
|
| - if (value && !is_gimple_min_invariant (value))
|
| - SSA_NAME_VALUE (name) = NULL;
|
| - }
|
| -
|
| statistics_counter_event (cfun, "Redundant expressions eliminated",
|
| opt_stats.num_re);
|
| statistics_counter_event (cfun, "Constants propagated",
|
| @@ -758,11 +720,14 @@ tree_ssa_dominator_optimize (void)
|
|
|
| /* 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);
|
| - VEC_free (gimple_p, heap, stmts_to_rescan);
|
| -
|
| +
|
| + /* Free the value-handle array. */
|
| + threadedge_finalize_values ();
|
| + ssa_name_values = NULL;
|
| +
|
| return 0;
|
| }
|
|
|
| @@ -772,7 +737,7 @@ gate_dominator (void)
|
| return flag_tree_dom != 0;
|
| }
|
|
|
| -struct gimple_opt_pass pass_dominator =
|
| +struct gimple_opt_pass pass_dominator =
|
| {
|
| {
|
| GIMPLE_PASS,
|
| @@ -783,7 +748,7 @@ struct gimple_opt_pass pass_dominator =
|
| NULL, /* next */
|
| 0, /* static_pass_number */
|
| TV_TREE_SSA_DOMINATOR_OPTS, /* tv_id */
|
| - PROP_cfg | PROP_ssa | PROP_alias, /* properties_required */
|
| + PROP_cfg | PROP_ssa, /* properties_required */
|
| 0, /* properties_provided */
|
| 0, /* properties_destroyed */
|
| 0, /* todo_flags_start */
|
| @@ -842,24 +807,6 @@ canonicalize_comparison (gimple condstmt)
|
| upon entry to BB. Equivalences can come from the edge traversed to
|
| reach BB or they may come from PHI nodes at the start of BB. */
|
|
|
| -static void
|
| -dom_opt_initialize_block (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
|
| - basic_block bb)
|
| -{
|
| - if (dump_file && (dump_flags & TDF_DETAILS))
|
| - fprintf (dump_file, "\n\nOptimizing block #%d\n\n", bb->index);
|
| -
|
| - /* 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);
|
| -
|
| - record_equivalences_from_incoming_edge (bb);
|
| -
|
| - /* PHI nodes can create equivalences too. */
|
| - record_equivalences_from_phis (bb);
|
| -}
|
| -
|
| /* Remove all the expressions in LOCALS from TABLE, stopping when there are
|
| LIMIT entries left in LOCALs. */
|
|
|
| @@ -869,24 +816,25 @@ 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)
|
| {
|
| - struct expr_hash_elt element;
|
| expr_hash_elt_t victim = VEC_pop (expr_hash_elt_t, avail_exprs_stack);
|
| + void **slot;
|
|
|
| if (victim == NULL)
|
| break;
|
|
|
| - element = *victim;
|
| -
|
| /* This must precede the actual removal from the hash table,
|
| as ELEMENT and the table entry may share a call argument
|
| vector which will be freed during removal. */
|
| if (dump_file && (dump_flags & TDF_DETAILS))
|
| {
|
| fprintf (dump_file, "<<<< ");
|
| - print_expr_hash_elt (dump_file, &element);
|
| + print_expr_hash_elt (dump_file, victim);
|
| }
|
|
|
| - htab_remove_elt_with_hash (avail_exprs, &element, element.hash);
|
| + slot = htab_find_slot_with_hash (avail_exprs,
|
| + victim, victim->hash, NO_INSERT);
|
| + gcc_assert (slot && *slot == (void *) victim);
|
| + htab_clear_slot (avail_exprs, slot);
|
| }
|
| }
|
|
|
| @@ -916,7 +864,7 @@ restore_vars_to_original_value (void)
|
| }
|
|
|
| prev_value = VEC_pop (tree, const_and_copies_stack);
|
| - SSA_NAME_VALUE (dest) = prev_value;
|
| + set_ssa_name_value (dest, prev_value);
|
| }
|
| }
|
|
|
| @@ -950,132 +898,6 @@ dom_thread_across_edge (struct dom_walk_data *walk_data, edge e)
|
| simplify_stmt_for_jump_threading);
|
| }
|
|
|
| -/* We have finished processing the dominator children of BB, perform
|
| - any finalization actions in preparation for leaving this node in
|
| - the dominator tree. */
|
| -
|
| -static void
|
| -dom_opt_finalize_block (struct dom_walk_data *walk_data, basic_block bb)
|
| -{
|
| - gimple last;
|
| -
|
| - /* If we have an outgoing edge to a block with multiple incoming and
|
| - outgoing edges, then we may be able to thread the edge, i.e., we
|
| - may be able to statically determine which of the outgoing edges
|
| - will be traversed when the incoming edge from BB is traversed. */
|
| - if (single_succ_p (bb)
|
| - && (single_succ_edge (bb)->flags & EDGE_ABNORMAL) == 0
|
| - && potentially_threadable_block (single_succ (bb)))
|
| - {
|
| - dom_thread_across_edge (walk_data, single_succ_edge (bb));
|
| - }
|
| - else if ((last = last_stmt (bb))
|
| - && gimple_code (last) == GIMPLE_COND
|
| - && EDGE_COUNT (bb->succs) == 2
|
| - && (EDGE_SUCC (bb, 0)->flags & EDGE_ABNORMAL) == 0
|
| - && (EDGE_SUCC (bb, 1)->flags & EDGE_ABNORMAL) == 0)
|
| - {
|
| - edge true_edge, false_edge;
|
| -
|
| - extract_true_false_edges_from_block (bb, &true_edge, &false_edge);
|
| -
|
| - /* Only try to thread the edge if it reaches a target block with
|
| - more than one predecessor and more than one successor. */
|
| - if (potentially_threadable_block (true_edge->dest))
|
| - {
|
| - struct edge_info *edge_info;
|
| - unsigned int i;
|
| -
|
| - /* 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);
|
| -
|
| - edge_info = (struct edge_info *) true_edge->aux;
|
| -
|
| - /* If we have info associated with this edge, record it into
|
| - our equivalence tables. */
|
| - if (edge_info)
|
| - {
|
| - struct cond_equivalence *cond_equivalences = edge_info->cond_equivalences;
|
| - tree lhs = edge_info->lhs;
|
| - tree rhs = edge_info->rhs;
|
| -
|
| - /* If we have a simple NAME = VALUE equivalence, record it. */
|
| - if (lhs && TREE_CODE (lhs) == SSA_NAME)
|
| - record_const_or_copy (lhs, rhs);
|
| -
|
| - /* If we have 0 = COND or 1 = COND equivalences, record them
|
| - into our expression hash tables. */
|
| - if (cond_equivalences)
|
| - for (i = 0; i < edge_info->max_cond_equivalences; i++)
|
| - record_cond (&cond_equivalences[i]);
|
| - }
|
| -
|
| - dom_thread_across_edge (walk_data, true_edge);
|
| -
|
| - /* And restore the various tables to their state before
|
| - we threaded this edge. */
|
| - remove_local_expressions_from_table ();
|
| - }
|
| -
|
| - /* Similarly for the ELSE arm. */
|
| - if (potentially_threadable_block (false_edge->dest))
|
| - {
|
| - struct edge_info *edge_info;
|
| - unsigned int i;
|
| -
|
| - VEC_safe_push (tree, heap, const_and_copies_stack, NULL_TREE);
|
| - edge_info = (struct edge_info *) false_edge->aux;
|
| -
|
| - /* If we have info associated with this edge, record it into
|
| - our equivalence tables. */
|
| - if (edge_info)
|
| - {
|
| - struct cond_equivalence *cond_equivalences = edge_info->cond_equivalences;
|
| - tree lhs = edge_info->lhs;
|
| - tree rhs = edge_info->rhs;
|
| -
|
| - /* If we have a simple NAME = VALUE equivalence, record it. */
|
| - if (lhs && TREE_CODE (lhs) == SSA_NAME)
|
| - record_const_or_copy (lhs, rhs);
|
| -
|
| - /* If we have 0 = COND or 1 = COND equivalences, record them
|
| - into our expression hash tables. */
|
| - if (cond_equivalences)
|
| - for (i = 0; i < edge_info->max_cond_equivalences; i++)
|
| - record_cond (&cond_equivalences[i]);
|
| - }
|
| -
|
| - /* Now thread the edge. */
|
| - dom_thread_across_edge (walk_data, false_edge);
|
| -
|
| - /* No need to remove local expressions from our tables
|
| - or restore vars to their original value as that will
|
| - be done immediately below. */
|
| - }
|
| - }
|
| -
|
| - remove_local_expressions_from_table ();
|
| - restore_vars_to_original_value ();
|
| -
|
| - /* If we queued any statements to rescan in this block, then
|
| - go ahead and rescan them now. */
|
| - while (VEC_length (gimple_p, stmts_to_rescan) > 0)
|
| - {
|
| - gimple *stmt_p = VEC_last (gimple_p, stmts_to_rescan);
|
| - gimple stmt = *stmt_p;
|
| - basic_block stmt_bb = gimple_bb (stmt);
|
| -
|
| - if (stmt_bb != bb)
|
| - break;
|
| -
|
| - VEC_pop (gimple_p, stmts_to_rescan);
|
| - pop_stmt_changes (stmt_p);
|
| - }
|
| -}
|
| -
|
| /* PHI nodes can create equivalences too.
|
|
|
| Ignoring any alternatives which are the same as the result, if
|
| @@ -1086,7 +908,7 @@ static void
|
| record_equivalences_from_phis (basic_block bb)
|
| {
|
| gimple_stmt_iterator gsi;
|
| -
|
| +
|
| for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
|
| {
|
| gimple phi = gsi_stmt (gsi);
|
| @@ -1128,7 +950,7 @@ record_equivalences_from_phis (basic_block bb)
|
| inferred from a comparison. All uses of this ssa name are dominated
|
| by this assignment, so unwinding just costs time and space. */
|
| if (i == gimple_phi_num_args (phi) && may_propagate_copy (lhs, rhs))
|
| - SSA_NAME_VALUE (lhs) = rhs;
|
| + set_ssa_name_value (lhs, rhs);
|
| }
|
| }
|
|
|
| @@ -1272,7 +1094,7 @@ record_cond (struct cond_equivalence *p)
|
|
|
| /* Build a cond_equivalence record indicating that the comparison
|
| CODE holds between operands OP0 and OP1. */
|
| -
|
| +
|
| static void
|
| build_and_record_new_cond (enum tree_code code,
|
| tree op0, tree op1,
|
| @@ -1441,7 +1263,7 @@ record_conditions (struct edge_info *edge_info, tree cond, tree inverted)
|
| static void
|
| record_const_or_copy_1 (tree x, tree y, tree prev_x)
|
| {
|
| - SSA_NAME_VALUE (x) = y;
|
| + set_ssa_name_value (x, y);
|
|
|
| if (dump_file && (dump_flags & TDF_DETAILS))
|
| {
|
| @@ -1549,7 +1371,7 @@ record_equality (tree x, tree y)
|
|
|
| /* Returns true when STMT is a simple iv increment. It detects the
|
| following situation:
|
| -
|
| +
|
| i_1 = phi (..., i_2)
|
| i_2 = i_1 +/- ... */
|
|
|
| @@ -1588,7 +1410,7 @@ simple_iv_increment_p (gimple stmt)
|
| }
|
|
|
| /* CONST_AND_COPIES is a table which maps an SSA_NAME to the current
|
| - known value for that SSA_NAME (or NULL if no value is known).
|
| + known value for that SSA_NAME (or NULL if no value is known).
|
|
|
| Propagate values from CONST_AND_COPIES into the PHI nodes of the
|
| successors of BB. */
|
| @@ -1653,6 +1475,7 @@ record_edge_info (basic_block bb)
|
| if (! gsi_end_p (gsi))
|
| {
|
| gimple stmt = gsi_stmt (gsi);
|
| + location_t loc = gimple_location (stmt);
|
|
|
| if (gimple_code (stmt) == GIMPLE_SWITCH)
|
| {
|
| @@ -1685,7 +1508,8 @@ record_edge_info (basic_block bb)
|
|
|
| if (label != NULL && label != error_mark_node)
|
| {
|
| - tree x = fold_convert (TREE_TYPE (index), CASE_LOW (label));
|
| + tree x = fold_convert_loc (loc, TREE_TYPE (index),
|
| + CASE_LOW (label));
|
| edge_info = allocate_edge_info (e);
|
| edge_info->lhs = index;
|
| edge_info->rhs = x;
|
| @@ -1749,7 +1573,7 @@ record_edge_info (basic_block bb)
|
| || is_gimple_min_invariant (op1)))
|
| {
|
| tree cond = build2 (code, boolean_type_node, op0, op1);
|
| - tree inverted = invert_truthvalue (cond);
|
| + tree inverted = invert_truthvalue_loc (loc, cond);
|
| struct edge_info *edge_info;
|
|
|
| edge_info = allocate_edge_info (true_edge);
|
| @@ -1764,7 +1588,7 @@ record_edge_info (basic_block bb)
|
| edge_info = allocate_edge_info (false_edge);
|
| record_conditions (edge_info, inverted, cond);
|
|
|
| - if (code == NE_EXPR)
|
| + if (TREE_CODE (inverted) == EQ_EXPR)
|
| {
|
| edge_info->lhs = op1;
|
| edge_info->rhs = op0;
|
| @@ -1776,7 +1600,7 @@ record_edge_info (basic_block bb)
|
| || TREE_CODE (op1) == SSA_NAME))
|
| {
|
| tree cond = build2 (code, boolean_type_node, op0, op1);
|
| - tree inverted = invert_truthvalue (cond);
|
| + tree inverted = invert_truthvalue_loc (loc, cond);
|
| struct edge_info *edge_info;
|
|
|
| edge_info = allocate_edge_info (true_edge);
|
| @@ -1791,7 +1615,7 @@ record_edge_info (basic_block bb)
|
| edge_info = allocate_edge_info (false_edge);
|
| record_conditions (edge_info, inverted, cond);
|
|
|
| - if (TREE_CODE (cond) == NE_EXPR)
|
| + if (TREE_CODE (inverted) == EQ_EXPR)
|
| {
|
| edge_info->lhs = op0;
|
| edge_info->rhs = op1;
|
| @@ -1803,33 +1627,156 @@ record_edge_info (basic_block bb)
|
| }
|
| }
|
|
|
| -/* Propagate information from BB to its outgoing edges.
|
| -
|
| - This can include equivalence information implied by control statements
|
| - at the end of BB and const/copy propagation into PHIs in BB's
|
| - successor blocks. */
|
| -
|
| static void
|
| -propagate_to_outgoing_edges (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
|
| - basic_block bb)
|
| +dom_opt_enter_block (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
|
| + basic_block bb)
|
| {
|
| + gimple_stmt_iterator gsi;
|
| +
|
| + if (dump_file && (dump_flags & TDF_DETAILS))
|
| + fprintf (dump_file, "\n\nOptimizing block #%d\n\n", bb->index);
|
| +
|
| + /* 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);
|
| +
|
| + record_equivalences_from_incoming_edge (bb);
|
| +
|
| + /* PHI nodes can create equivalences too. */
|
| + record_equivalences_from_phis (bb);
|
| +
|
| + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
|
| + optimize_stmt (bb, gsi);
|
| +
|
| + /* Now prepare to process dominated blocks. */
|
| record_edge_info (bb);
|
| cprop_into_successor_phis (bb);
|
| }
|
|
|
| +/* We have finished processing the dominator children of BB, perform
|
| + any finalization actions in preparation for leaving this node in
|
| + the dominator tree. */
|
| +
|
| +static void
|
| +dom_opt_leave_block (struct dom_walk_data *walk_data, basic_block bb)
|
| +{
|
| + gimple last;
|
| +
|
| + /* If we have an outgoing edge to a block with multiple incoming and
|
| + outgoing edges, then we may be able to thread the edge, i.e., we
|
| + may be able to statically determine which of the outgoing edges
|
| + will be traversed when the incoming edge from BB is traversed. */
|
| + if (single_succ_p (bb)
|
| + && (single_succ_edge (bb)->flags & EDGE_ABNORMAL) == 0
|
| + && potentially_threadable_block (single_succ (bb)))
|
| + {
|
| + dom_thread_across_edge (walk_data, single_succ_edge (bb));
|
| + }
|
| + else if ((last = last_stmt (bb))
|
| + && gimple_code (last) == GIMPLE_COND
|
| + && EDGE_COUNT (bb->succs) == 2
|
| + && (EDGE_SUCC (bb, 0)->flags & EDGE_ABNORMAL) == 0
|
| + && (EDGE_SUCC (bb, 1)->flags & EDGE_ABNORMAL) == 0)
|
| + {
|
| + edge true_edge, false_edge;
|
| +
|
| + extract_true_false_edges_from_block (bb, &true_edge, &false_edge);
|
| +
|
| + /* Only try to thread the edge if it reaches a target block with
|
| + more than one predecessor and more than one successor. */
|
| + if (potentially_threadable_block (true_edge->dest))
|
| + {
|
| + struct edge_info *edge_info;
|
| + unsigned int i;
|
| +
|
| + /* 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);
|
| +
|
| + edge_info = (struct edge_info *) true_edge->aux;
|
| +
|
| + /* If we have info associated with this edge, record it into
|
| + our equivalence tables. */
|
| + if (edge_info)
|
| + {
|
| + struct cond_equivalence *cond_equivalences = edge_info->cond_equivalences;
|
| + tree lhs = edge_info->lhs;
|
| + tree rhs = edge_info->rhs;
|
| +
|
| + /* If we have a simple NAME = VALUE equivalence, record it. */
|
| + if (lhs && TREE_CODE (lhs) == SSA_NAME)
|
| + record_const_or_copy (lhs, rhs);
|
| +
|
| + /* If we have 0 = COND or 1 = COND equivalences, record them
|
| + into our expression hash tables. */
|
| + if (cond_equivalences)
|
| + for (i = 0; i < edge_info->max_cond_equivalences; i++)
|
| + record_cond (&cond_equivalences[i]);
|
| + }
|
| +
|
| + dom_thread_across_edge (walk_data, true_edge);
|
| +
|
| + /* And restore the various tables to their state before
|
| + we threaded this edge. */
|
| + remove_local_expressions_from_table ();
|
| + }
|
| +
|
| + /* Similarly for the ELSE arm. */
|
| + if (potentially_threadable_block (false_edge->dest))
|
| + {
|
| + struct edge_info *edge_info;
|
| + unsigned int i;
|
| +
|
| + VEC_safe_push (tree, heap, const_and_copies_stack, NULL_TREE);
|
| + edge_info = (struct edge_info *) false_edge->aux;
|
| +
|
| + /* If we have info associated with this edge, record it into
|
| + our equivalence tables. */
|
| + if (edge_info)
|
| + {
|
| + struct cond_equivalence *cond_equivalences = edge_info->cond_equivalences;
|
| + tree lhs = edge_info->lhs;
|
| + tree rhs = edge_info->rhs;
|
| +
|
| + /* If we have a simple NAME = VALUE equivalence, record it. */
|
| + if (lhs && TREE_CODE (lhs) == SSA_NAME)
|
| + record_const_or_copy (lhs, rhs);
|
| +
|
| + /* If we have 0 = COND or 1 = COND equivalences, record them
|
| + into our expression hash tables. */
|
| + if (cond_equivalences)
|
| + for (i = 0; i < edge_info->max_cond_equivalences; i++)
|
| + record_cond (&cond_equivalences[i]);
|
| + }
|
| +
|
| + /* Now thread the edge. */
|
| + dom_thread_across_edge (walk_data, false_edge);
|
| +
|
| + /* No need to remove local expressions from our tables
|
| + or restore vars to their original value as that will
|
| + be done immediately below. */
|
| + }
|
| + }
|
| +
|
| + remove_local_expressions_from_table ();
|
| + restore_vars_to_original_value ();
|
| +}
|
| +
|
| /* Search for redundant computations in STMT. If any are found, then
|
| replace them with the variable holding the result of the computation.
|
|
|
| If safe, record this expression into the available expression hash
|
| table. */
|
|
|
| -static bool
|
| +static void
|
| eliminate_redundant_computations (gimple_stmt_iterator* gsi)
|
| {
|
| tree expr_type;
|
| tree cached_lhs;
|
| bool insert = true;
|
| - bool retval = false;
|
| bool assigns_var_p = false;
|
|
|
| gimple stmt = gsi_stmt (*gsi);
|
| @@ -1841,7 +1788,7 @@ eliminate_redundant_computations (gimple_stmt_iterator* gsi)
|
| if (! def
|
| || TREE_CODE (def) != SSA_NAME
|
| || SSA_NAME_OCCURS_IN_ABNORMAL_PHI (def)
|
| - || !ZERO_SSA_OPERANDS (stmt, SSA_OP_VDEF)
|
| + || gimple_vdef (stmt)
|
| /* Do not record equivalences for increments of ivs. This would create
|
| overlapping live ranges for a very questionable gain. */
|
| || simple_iv_increment_p (stmt))
|
| @@ -1872,7 +1819,7 @@ eliminate_redundant_computations (gimple_stmt_iterator* gsi)
|
| gcc_unreachable ();
|
|
|
| if (!cached_lhs)
|
| - return false;
|
| + return;
|
|
|
| /* It is safe to ignore types here since we have already done
|
| type checking in the hashing and equality routines. In fact
|
| @@ -1900,11 +1847,6 @@ eliminate_redundant_computations (gimple_stmt_iterator* gsi)
|
|
|
| opt_stats.num_re++;
|
|
|
| - if (TREE_CODE (cached_lhs) == ADDR_EXPR
|
| - || (POINTER_TYPE_P (expr_type)
|
| - && is_gimple_min_invariant (cached_lhs)))
|
| - retval = true;
|
| -
|
| if (assigns_var_p
|
| && !useless_type_conversion_p (expr_type, TREE_TYPE (cached_lhs)))
|
| cached_lhs = fold_convert (expr_type, cached_lhs);
|
| @@ -1916,27 +1858,6 @@ eliminate_redundant_computations (gimple_stmt_iterator* gsi)
|
| itself. */
|
| gimple_set_modified (gsi_stmt (*gsi), true);
|
| }
|
| - return retval;
|
| -}
|
| -
|
| -/* Return true if statement GS is an assignment that peforms a useless
|
| - type conversion. It is is intended to be a tuples analog of function
|
| - tree_ssa_useless_type_conversion. */
|
| -
|
| -static bool
|
| -gimple_assign_unary_useless_conversion_p (gimple gs)
|
| -{
|
| - if (is_gimple_assign (gs)
|
| - && (CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (gs))
|
| - || gimple_assign_rhs_code (gs) == VIEW_CONVERT_EXPR
|
| - || gimple_assign_rhs_code (gs) == NON_LVALUE_EXPR))
|
| - {
|
| - tree lhs_type = TREE_TYPE (gimple_assign_lhs (gs));
|
| - tree rhs_type = TREE_TYPE (gimple_assign_rhs1 (gs));
|
| - return useless_type_conversion_p (lhs_type, rhs_type);
|
| - }
|
| -
|
| - return false;
|
| }
|
|
|
| /* STMT, a GIMPLE_ASSIGN, may create certain equivalences, in either
|
| @@ -1957,13 +1878,9 @@ record_equivalences_from_stmt (gimple stmt, int may_optimize_p)
|
| lhs_code = TREE_CODE (lhs);
|
|
|
| if (lhs_code == SSA_NAME
|
| - && (gimple_assign_single_p (stmt)
|
| - || gimple_assign_unary_useless_conversion_p (stmt)))
|
| + && gimple_assign_single_p (stmt))
|
| {
|
| tree rhs = gimple_assign_rhs1 (stmt);
|
| -
|
| - /* Strip away any useless type conversions. */
|
| - STRIP_USELESS_TYPE_CONVERSION (rhs);
|
|
|
| /* If the RHS of the assignment is a constant or another variable that
|
| may be propagated, register it in the CONST_AND_COPIES table. We
|
| @@ -1984,7 +1901,7 @@ record_equivalences_from_stmt (gimple stmt, int may_optimize_p)
|
| fprintf (dump_file, "\n");
|
| }
|
|
|
| - SSA_NAME_VALUE (lhs) = rhs;
|
| + set_ssa_name_value (lhs, rhs);
|
| }
|
| }
|
|
|
| @@ -2021,7 +1938,7 @@ record_equivalences_from_stmt (gimple stmt, int may_optimize_p)
|
| else
|
| new_stmt = gimple_build_assign (rhs, lhs);
|
|
|
| - create_ssa_artificial_load_stmt (new_stmt, stmt, true);
|
| + gimple_set_vuse (new_stmt, gimple_vdef (stmt));
|
|
|
| /* Finally enter the statement into the available expression
|
| table. */
|
| @@ -2032,10 +1949,9 @@ record_equivalences_from_stmt (gimple stmt, int may_optimize_p)
|
| /* Replace *OP_P in STMT with any known equivalent value for *OP_P from
|
| CONST_AND_COPIES. */
|
|
|
| -static bool
|
| +static void
|
| cprop_operand (gimple stmt, use_operand_p op_p)
|
| {
|
| - bool may_have_exposed_new_symbols = false;
|
| tree val;
|
| tree op = USE_FROM_PTR (op_p);
|
|
|
| @@ -2054,18 +1970,18 @@ cprop_operand (gimple stmt, use_operand_p op_p)
|
| && (TREE_CODE (val) != SSA_NAME
|
| || is_gimple_reg (val)
|
| || get_virtual_var (val) != get_virtual_var (op)))
|
| - return false;
|
| + return;
|
|
|
| /* Do not replace hard register operands in asm statements. */
|
| if (gimple_code (stmt) == GIMPLE_ASM
|
| && !may_propagate_copy_into_asm (op))
|
| - return false;
|
| + return;
|
|
|
| /* Certain operands are not allowed to be copy propagated due
|
| to their interaction with exception handling and some GCC
|
| extensions. */
|
| if (!may_propagate_copy (op, val))
|
| - return false;
|
| + return;
|
|
|
| /* Do not propagate addresses that point to volatiles into memory
|
| stmts without volatile operands. */
|
| @@ -2073,7 +1989,7 @@ cprop_operand (gimple stmt, use_operand_p op_p)
|
| && TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (val)))
|
| && gimple_has_mem_ops (stmt)
|
| && !gimple_has_volatile_ops (stmt))
|
| - return false;
|
| + return;
|
|
|
| /* Do not propagate copies if the propagated value is at a deeper loop
|
| depth than the propagatee. Otherwise, this may move loop variant
|
| @@ -2081,7 +1997,13 @@ cprop_operand (gimple stmt, use_operand_p op_p)
|
| opportunities. If the value was loop invariant, it will be hoisted
|
| by LICM and exposed for copy propagation. */
|
| if (loop_depth_of_name (val) > loop_depth_of_name (op))
|
| - return false;
|
| + return;
|
| +
|
| + /* Do not propagate copies into simple IV increment statements.
|
| + See PR23821 for how this can disturb IV analysis. */
|
| + if (TREE_CODE (val) != INTEGER_CST
|
| + && simple_iv_increment_p (stmt))
|
| + return;
|
|
|
| /* Dump details. */
|
| if (dump_file && (dump_flags & TDF_DETAILS))
|
| @@ -2094,13 +2016,6 @@ cprop_operand (gimple stmt, use_operand_p op_p)
|
| fprintf (dump_file, "'\n");
|
| }
|
|
|
| - /* If VAL is an ADDR_EXPR or a constant of pointer type, note
|
| - that we may have exposed a new symbol for SSA renaming. */
|
| - if (TREE_CODE (val) == ADDR_EXPR
|
| - || (POINTER_TYPE_P (TREE_TYPE (op))
|
| - && is_gimple_min_invariant (val)))
|
| - may_have_exposed_new_symbols = true;
|
| -
|
| if (TREE_CODE (val) != SSA_NAME)
|
| opt_stats.num_const_prop++;
|
| else
|
| @@ -2113,33 +2028,29 @@ cprop_operand (gimple stmt, use_operand_p op_p)
|
| rescan the statement and rewrite its operands again. */
|
| gimple_set_modified (stmt, true);
|
| }
|
| - return may_have_exposed_new_symbols;
|
| }
|
|
|
| /* CONST_AND_COPIES is a table which maps an SSA_NAME to the current
|
| - known value for that SSA_NAME (or NULL if no value is known).
|
| + known value for that SSA_NAME (or NULL if no value is known).
|
|
|
| Propagate values from CONST_AND_COPIES into the uses, vuses and
|
| vdef_ops of STMT. */
|
|
|
| -static bool
|
| +static void
|
| cprop_into_stmt (gimple stmt)
|
| {
|
| - bool may_have_exposed_new_symbols = false;
|
| 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)
|
| - may_have_exposed_new_symbols |= cprop_operand (stmt, op_p);
|
| + cprop_operand (stmt, op_p);
|
| }
|
| -
|
| - return may_have_exposed_new_symbols;
|
| }
|
|
|
| /* Optimize the statement pointed to by iterator SI.
|
| -
|
| +
|
| We try to perform some simplistic global redundancy elimination and
|
| constant propagation:
|
|
|
| @@ -2154,22 +2065,19 @@ cprop_into_stmt (gimple stmt)
|
| the variable in the LHS in the CONST_AND_COPIES table. */
|
|
|
| static void
|
| -optimize_stmt (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
|
| - basic_block bb, gimple_stmt_iterator si)
|
| +optimize_stmt (basic_block bb, gimple_stmt_iterator si)
|
| {
|
| gimple stmt, old_stmt;
|
| bool may_optimize_p;
|
| - bool may_have_exposed_new_symbols;
|
| bool modified_p = false;
|
|
|
| old_stmt = stmt = gsi_stmt (si);
|
| -
|
| +
|
| if (gimple_code (stmt) == GIMPLE_COND)
|
| canonicalize_comparison (stmt);
|
| -
|
| +
|
| update_stmt_if_modified (stmt);
|
| opt_stats.num_stmts++;
|
| - push_stmt_changes (gsi_stmt_ptr (&si));
|
|
|
| if (dump_file && (dump_flags & TDF_DETAILS))
|
| {
|
| @@ -2178,7 +2086,7 @@ optimize_stmt (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
|
| }
|
|
|
| /* Const/copy propagate into USES, VUSES and the RHS of VDEFs. */
|
| - may_have_exposed_new_symbols = cprop_into_stmt (stmt);
|
| + cprop_into_stmt (stmt);
|
|
|
| /* If the statement has been modified with constant replacements,
|
| fold its RHS before checking for redundant computations. */
|
| @@ -2191,6 +2099,7 @@ optimize_stmt (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
|
| if (fold_stmt (&si))
|
| {
|
| stmt = gsi_stmt (si);
|
| + gimple_set_modified (stmt, true);
|
|
|
| if (dump_file && (dump_flags & TDF_DETAILS))
|
| {
|
| @@ -2211,12 +2120,6 @@ optimize_stmt (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
|
| if (rhs && TREE_CODE (rhs) == ADDR_EXPR)
|
| recompute_tree_invariant_for_addr_expr (rhs);
|
|
|
| - /* Constant/copy propagation above may change the set of
|
| - virtual operands associated with this statement. Folding
|
| - may remove the need for some virtual operands.
|
| -
|
| - Indicate we will need to rescan and rewrite the statement. */
|
| - may_have_exposed_new_symbols = true;
|
| /* Indicate that maybe_clean_or_replace_eh_stmt needs to be called,
|
| even if fold_stmt updated the stmt already and thus cleared
|
| gimple_modified_p flag on it. */
|
| @@ -2236,7 +2139,23 @@ optimize_stmt (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
|
|
|
| if (may_optimize_p)
|
| {
|
| - may_have_exposed_new_symbols |= eliminate_redundant_computations (&si);
|
| + if (gimple_code (stmt) == GIMPLE_CALL)
|
| + {
|
| + /* Resolve __builtin_constant_p. If it hasn't been
|
| + folded to integer_one_node by now, it's fairly
|
| + certain that the value simply isn't constant. */
|
| + tree callee = gimple_call_fndecl (stmt);
|
| + if (callee
|
| + && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL
|
| + && DECL_FUNCTION_CODE (callee) == BUILT_IN_CONSTANT_P)
|
| + {
|
| + propagate_tree_value_into_stmt (&si, integer_zero_node);
|
| + stmt = gsi_stmt (si);
|
| + }
|
| + }
|
| +
|
| + update_stmt_if_modified (stmt);
|
| + eliminate_redundant_computations (&si);
|
| stmt = gsi_stmt (si);
|
| }
|
|
|
| @@ -2248,7 +2167,7 @@ optimize_stmt (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
|
| where it goes. If that is the case, then mark the CFG as altered.
|
|
|
| This will cause us to later call remove_unreachable_blocks and
|
| - cleanup_tree_cfg when it is safe to do so. It is not safe to
|
| + cleanup_tree_cfg when it is safe to do so. It is not safe to
|
| clean things up here since removal of edges and such can trigger
|
| the removal of PHI nodes, which in turn can release SSA_NAMEs to
|
| the manager.
|
| @@ -2273,8 +2192,11 @@ optimize_stmt (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
|
| {
|
| tree val = NULL;
|
|
|
| + update_stmt_if_modified (stmt);
|
| +
|
| if (gimple_code (stmt) == GIMPLE_COND)
|
| - val = fold_binary (gimple_cond_code (stmt), boolean_type_node,
|
| + val = fold_binary_loc (gimple_location (stmt),
|
| + gimple_cond_code (stmt), boolean_type_node,
|
| gimple_cond_lhs (stmt), gimple_cond_rhs (stmt));
|
| else if (gimple_code (stmt) == GIMPLE_SWITCH)
|
| val = gimple_switch_index (stmt);
|
| @@ -2291,22 +2213,6 @@ optimize_stmt (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
|
| fprintf (dump_file, " Flagged to clear EH edges.\n");
|
| }
|
| }
|
| -
|
| - if (may_have_exposed_new_symbols)
|
| - {
|
| - /* Queue the statement to be re-scanned after all the
|
| - AVAIL_EXPRS have been processed. The change buffer stack for
|
| - all the pushed statements will be processed when this queue
|
| - is emptied. */
|
| - VEC_safe_push (gimple_p, heap, stmts_to_rescan, gsi_stmt_ptr (&si));
|
| - }
|
| - else
|
| - {
|
| - /* Otherwise, just discard the recently pushed change buffer. If
|
| - not, the STMTS_TO_RESCAN queue will get out of synch with the
|
| - change buffer stack. */
|
| - discard_stmt_changes (gsi_stmt_ptr (&si));
|
| - }
|
| }
|
|
|
| /* Search for an existing instance of STMT in the AVAIL_EXPRS table.
|
| @@ -2323,50 +2229,47 @@ lookup_avail_expr (gimple stmt, bool insert)
|
| void **slot;
|
| tree lhs;
|
| tree temp;
|
| - struct expr_hash_elt *element = XNEW (struct expr_hash_elt);
|
| + struct expr_hash_elt element;
|
|
|
| /* Get LHS of assignment or call, else NULL_TREE. */
|
| lhs = gimple_get_lhs (stmt);
|
|
|
| - initialize_hash_element (stmt, lhs, element);
|
| + initialize_hash_element (stmt, lhs, &element);
|
|
|
| if (dump_file && (dump_flags & TDF_DETAILS))
|
| {
|
| fprintf (dump_file, "LKUP ");
|
| - print_expr_hash_elt (dump_file, element);
|
| + print_expr_hash_elt (dump_file, &element);
|
| }
|
|
|
| /* Don't bother remembering constant assignments and copy operations.
|
| Constants and copy operations are handled by the constant/copy propagator
|
| in optimize_stmt. */
|
| - if (element->expr.kind == EXPR_SINGLE
|
| - && (TREE_CODE (element->expr.ops.single.rhs) == SSA_NAME
|
| - || is_gimple_min_invariant (element->expr.ops.single.rhs)))
|
| - {
|
| - free (element);
|
| - return NULL_TREE;
|
| - }
|
| + if (element.expr.kind == EXPR_SINGLE
|
| + && (TREE_CODE (element.expr.ops.single.rhs) == SSA_NAME
|
| + || is_gimple_min_invariant (element.expr.ops.single.rhs)))
|
| + return NULL_TREE;
|
|
|
| /* Finally try to find the expression in the main expression hash table. */
|
| - slot = htab_find_slot_with_hash (avail_exprs, element, element->hash,
|
| + slot = htab_find_slot_with_hash (avail_exprs, &element, element.hash,
|
| (insert ? INSERT : NO_INSERT));
|
| if (slot == NULL)
|
| - {
|
| - free (element);
|
| - return NULL_TREE;
|
| - }
|
| + return NULL_TREE;
|
|
|
| if (*slot == NULL)
|
| {
|
| - *slot = (void *) element;
|
| + struct expr_hash_elt *element2 = XNEW (struct expr_hash_elt);
|
| + *element2 = element;
|
| + element2->stamp = element2;
|
| + *slot = (void *) element2;
|
|
|
| if (dump_file && (dump_flags & TDF_DETAILS))
|
| {
|
| fprintf (dump_file, "2>>> ");
|
| - print_expr_hash_elt (dump_file, element);
|
| + print_expr_hash_elt (dump_file, element2);
|
| }
|
|
|
| - VEC_safe_push (expr_hash_elt_t, heap, avail_exprs_stack, element);
|
| + VEC_safe_push (expr_hash_elt_t, heap, avail_exprs_stack, element2);
|
| return NULL_TREE;
|
| }
|
|
|
| @@ -2383,8 +2286,6 @@ lookup_avail_expr (gimple stmt, bool insert)
|
| lhs = temp;
|
| }
|
|
|
| - free (element);
|
| -
|
| if (dump_file && (dump_flags & TDF_DETAILS))
|
| {
|
| fprintf (dump_file, "FIND: ");
|
| @@ -2405,7 +2306,6 @@ avail_expr_hash (const void *p)
|
| gimple stmt = ((const struct expr_hash_elt *)p)->stmt;
|
| const struct hashable_expr *expr = &((const struct expr_hash_elt *)p)->expr;
|
| tree vuse;
|
| - ssa_op_iter iter;
|
| hashval_t val = 0;
|
|
|
| val = iterative_hash_hashable_expr (expr, val);
|
| @@ -2416,11 +2316,11 @@ avail_expr_hash (const void *p)
|
| if (!stmt)
|
| return val;
|
|
|
| - /* Add the SSA version numbers of every vuse operand. This is important
|
| + /* Add the SSA version numbers of the vuse operand. This is important
|
| because compound variables like arrays are not renamed in the
|
| operands. Rather, the rename is done on the virtual variable
|
| representing all the elements of the array. */
|
| - FOR_EACH_SSA_TREE_OPERAND (vuse, stmt, iter, SSA_OP_VUSE)
|
| + if ((vuse = gimple_vuse (stmt)))
|
| val = iterative_hash_expr (vuse, val);
|
|
|
| return val;
|
| @@ -2462,8 +2362,8 @@ avail_expr_eq (const void *p1, const void *p2)
|
| && types_compatible_p (expr1->type, expr2->type))
|
| {
|
| /* Note that STMT1 and/or STMT2 may be NULL. */
|
| - bool ret = compare_ssa_operands_equal (stmt1, stmt2, SSA_OP_VUSE);
|
| - return ret;
|
| + return ((stmt1 ? gimple_vuse (stmt1) : NULL_TREE)
|
| + == (stmt2 ? gimple_vuse (stmt2) : NULL_TREE));
|
| }
|
|
|
| return false;
|
| @@ -2475,7 +2375,7 @@ avail_expr_eq (const void *p1, const void *p2)
|
| /* Given PHI, return its RHS if the PHI is a degenerate, otherwise return
|
| NULL. */
|
|
|
| -static tree
|
| +tree
|
| degenerate_phi_result (gimple phi)
|
| {
|
| tree lhs = gimple_phi_result (phi);
|
| @@ -2495,7 +2395,14 @@ degenerate_phi_result (gimple phi)
|
| break;
|
| else if (!val)
|
| val = arg;
|
| - else if (!operand_equal_p (arg, val, 0))
|
| + else if (arg == val)
|
| + continue;
|
| + /* We bring in some of operand_equal_p not only to speed things
|
| + up, but also to avoid crashing when dereferencing the type of
|
| + a released SSA name. */
|
| + else if (TREE_CODE (val) != TREE_CODE (arg)
|
| + || TREE_CODE (val) == SSA_NAME
|
| + || !operand_equal_p (arg, val, 0))
|
| break;
|
| }
|
| return (i == gimple_phi_num_args (phi) ? val : NULL);
|
| @@ -2559,7 +2466,7 @@ get_lhs_or_phi_result (gimple stmt)
|
| nodes as well in an effort to pick up secondary optimization
|
| opportunities. */
|
|
|
| -static void
|
| +static void
|
| propagate_rhs_into_lhs (gimple stmt, tree lhs, tree rhs, bitmap interesting_names)
|
| {
|
| /* First verify that propagation is valid and isn't going to move a
|
| @@ -2586,12 +2493,17 @@ propagate_rhs_into_lhs (gimple stmt, tree lhs, tree rhs, bitmap interesting_name
|
| fprintf (dump_file, "'\n");
|
| }
|
|
|
| - /* Walk over every use of LHS and try to replace the use with RHS.
|
| + /* Walk over every use of LHS and try to replace the use with RHS.
|
| At this point the only reason why such a propagation would not
|
| be successful would be if the use occurs in an ASM_EXPR. */
|
| FOR_EACH_IMM_USE_STMT (use_stmt, iter, lhs)
|
| {
|
| -
|
| + /* Leave debug stmts alone. If we succeed in propagating
|
| + all non-debug uses, we'll drop the DEF, and propagation
|
| + into debug stmts will occur then. */
|
| + if (gimple_debug_bind_p (use_stmt))
|
| + continue;
|
| +
|
| /* It's not always safe to propagate into an ASM_EXPR. */
|
| if (gimple_code (use_stmt) == GIMPLE_ASM
|
| && ! may_propagate_copy_into_asm (lhs))
|
| @@ -2600,6 +2512,20 @@ propagate_rhs_into_lhs (gimple stmt, tree lhs, tree rhs, bitmap interesting_name
|
| continue;
|
| }
|
|
|
| + /* It's not ok to propagate into the definition stmt of RHS.
|
| + <bb 9>:
|
| + # prephitmp.12_36 = PHI <g_67.1_6(9)>
|
| + g_67.1_6 = prephitmp.12_36;
|
| + goto <bb 9>;
|
| + While this is strictly all dead code we do not want to
|
| + deal with this here. */
|
| + if (TREE_CODE (rhs) == SSA_NAME
|
| + && SSA_NAME_DEF_STMT (rhs) == use_stmt)
|
| + {
|
| + all = false;
|
| + continue;
|
| + }
|
| +
|
| /* Dump details. */
|
| if (dump_file && (dump_flags & TDF_DETAILS))
|
| {
|
| @@ -2607,8 +2533,6 @@ propagate_rhs_into_lhs (gimple stmt, tree lhs, tree rhs, bitmap interesting_name
|
| print_gimple_stmt (dump_file, use_stmt, 0, dump_flags);
|
| }
|
|
|
| - push_stmt_changes (&use_stmt);
|
| -
|
| /* Propagate the RHS into this use of the LHS. */
|
| FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
|
| propagate_value (use_p, rhs);
|
| @@ -2643,11 +2567,10 @@ propagate_rhs_into_lhs (gimple stmt, tree lhs, tree rhs, bitmap interesting_name
|
| bitmap_set_bit (interesting_names, SSA_NAME_VERSION (result));
|
| }
|
|
|
| - discard_stmt_changes (&use_stmt);
|
| continue;
|
| }
|
|
|
| - /* From this point onward we are propagating into a
|
| + /* From this point onward we are propagating into a
|
| real statement. Folding may (or may not) be possible,
|
| we may expose new operands, expose dead EH edges,
|
| etc. */
|
| @@ -2660,9 +2583,8 @@ propagate_rhs_into_lhs (gimple stmt, tree lhs, tree rhs, bitmap interesting_name
|
| fold_stmt_inplace (use_stmt);
|
|
|
| /* Sometimes propagation can expose new operands to the
|
| - renamer. Note this will call update_stmt at the
|
| - appropriate time. */
|
| - pop_stmt_changes (&use_stmt);
|
| + renamer. */
|
| + update_stmt (use_stmt);
|
|
|
| /* Dump details. */
|
| if (dump_file && (dump_flags & TDF_DETAILS))
|
| @@ -2709,7 +2631,8 @@ propagate_rhs_into_lhs (gimple stmt, tree lhs, tree rhs, bitmap interesting_name
|
| tree val;
|
|
|
| if (gimple_code (use_stmt) == GIMPLE_COND)
|
| - val = fold_binary (gimple_cond_code (use_stmt),
|
| + val = fold_binary_loc (gimple_location (use_stmt),
|
| + gimple_cond_code (use_stmt),
|
| boolean_type_node,
|
| gimple_cond_lhs (use_stmt),
|
| gimple_cond_rhs (use_stmt));
|
| @@ -2768,7 +2691,7 @@ propagate_rhs_into_lhs (gimple stmt, tree lhs, tree rhs, bitmap interesting_name
|
| }
|
| }
|
|
|
| - /* Ensure there is nothing else to do. */
|
| + /* Ensure there is nothing else to do. */
|
| gcc_assert (!all || has_zero_uses (lhs));
|
|
|
| /* If we were able to propagate away all uses of LHS, then
|
| @@ -2892,7 +2815,7 @@ eliminate_degenerate_phis (void)
|
| A set bit indicates that the statement or PHI node which
|
| defines the SSA_NAME should be (re)examined to determine if
|
| it has become a degenerate PHI or trivial const/copy propagation
|
| - opportunity.
|
| + opportunity.
|
|
|
| Experiments have show we generally get better compilation
|
| time behavior with bitmaps rather than sbitmaps. */
|
| @@ -2965,12 +2888,12 @@ struct gimple_opt_pass pass_phi_only_cprop =
|
| NULL, /* next */
|
| 0, /* static_pass_number */
|
| TV_TREE_PHI_CPROP, /* tv_id */
|
| - PROP_cfg | PROP_ssa | PROP_alias, /* properties_required */
|
| + PROP_cfg | PROP_ssa, /* properties_required */
|
| 0, /* properties_provided */
|
| 0, /* properties_destroyed */
|
| 0, /* todo_flags_start */
|
| TODO_cleanup_cfg
|
| - | TODO_dump_func
|
| + | TODO_dump_func
|
| | TODO_ggc_collect
|
| | TODO_verify_ssa
|
| | TODO_verify_stmts
|
|
|