/* This file implements optimizations on the dominator tree. */
+
+/* Structure for recording edge equivalences as well as any pending
+ edge redirections during the dominator optimizer.
+
+ 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.
+
+ These structures live for a single iteration of the dominator
+ optimizer in the edge's AUX field. At the end of an iteration we
+ free each of these structures and update the AUX field to point
+ to any requested redirection target (the code for updating the
+ CFG and SSA graph for edge redirection expects redirection edge
+ targets to be in the AUX field for each edge. */
+
+struct edge_info
+{
+ /* If this edge creates a simple equivalence, the LHS and RHS of
+ the equivalence will be stored here. */
+ tree lhs;
+ tree rhs;
+
+ /* Traversing an edge may also indicate one or more particular conditions
+ are true or false. The number of recorded conditions can vary, but
+ can be determined by the condition's code. So we have an array
+ and its maximum index rather than use a varray. */
+ tree *cond_equivalences;
+ unsigned int max_cond_equivalences;
+
+ /* If we can thread this edge this field records the new target. */
+ edge redirection_target;
+};
+
+
/* Hash table with expressions made available during the renaming process.
When an assignment of the form X_i = EXPR is found, the statement is
stored in this table. If the same expression EXPR is later found on the
static htab_t vrp_data;
/* An entry in the VRP_DATA hash table. We record the variable and a
- varray of VRP_ELEMENT records associated with that variable. */
+ varray of VRP_ELEMENT records associated with that variable. */
struct vrp_hash_elt
{
basic_block bb,
block_stmt_iterator);
static tree lookup_avail_expr (tree, bool);
-static struct eq_expr_value get_eq_expr_value (tree, int, basic_block);
static hashval_t vrp_hash (const void *);
static int vrp_eq (const void *, const void *);
static hashval_t avail_expr_hash (const void *);
static int avail_expr_eq (const void *, const void *);
static void htab_statistics (FILE *, htab_t);
static void record_cond (tree, tree);
-static void record_dominating_conditions (tree);
static void record_const_or_copy (tree, tree);
static void record_equality (tree, tree);
static tree update_rhs_and_lookup_avail_expr (tree, tree, bool);
static tree find_equivalent_equality_comparison (tree);
static void record_range (tree, basic_block);
static bool extract_range_from_cond (tree, tree *, tree *, int *);
-static void record_equivalences_from_phis (struct dom_walk_data *, basic_block);
-static void record_equivalences_from_incoming_edge (struct dom_walk_data *,
- basic_block);
+static void record_equivalences_from_phis (basic_block);
+static void record_equivalences_from_incoming_edge (basic_block);
static bool eliminate_redundant_computations (struct dom_walk_data *,
tree, stmt_ann_t);
static void record_equivalences_from_stmt (tree, int, stmt_ann_t);
static void 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 cprop_into_phis (struct dom_walk_data *, basic_block);
+static void propagate_to_outgoing_edges (struct dom_walk_data *, basic_block);
static void remove_local_expressions_from_table (void);
static void restore_vars_to_original_value (void);
static void restore_currdefs_to_original_value (void);
static void register_definitions_for_stmt (tree);
static edge single_incoming_edge_ignoring_loop_edges (basic_block);
static void restore_nonzero_vars_to_original_value (void);
+static inline bool unsafe_associative_fp_binop (tree);
/* Local version of fold that doesn't introduce cruft. */
return t;
}
+/* Allocate an EDGE_INFO for edge E and attach it to E.
+ Return the new EDGE_INFO structure. */
+
+static struct edge_info *
+allocate_edge_info (edge e)
+{
+ struct edge_info *edge_info;
+
+ edge_info = xcalloc (1, sizeof (struct edge_info));
+
+ e->aux = edge_info;
+ return edge_info;
+}
+
+/* Free all EDGE_INFO structures associated with edges in the CFG.
+ If a particular edge can be threaded, copy the redirection
+ target from the EDGE_INFO structure into the edge's AUX field
+ as required by code to update the CFG and SSA graph for
+ jump threading. */
+
+static void
+free_all_edge_infos (void)
+{
+ basic_block bb;
+ edge_iterator ei;
+ edge e;
+
+ FOR_EACH_BB (bb)
+ {
+ FOR_EACH_EDGE (e, ei, bb->preds)
+ {
+ struct edge_info *edge_info = e->aux;
+
+ if (edge_info)
+ {
+ e->aux = edge_info->redirection_target;
+ if (edge_info->cond_equivalences)
+ free (edge_info->cond_equivalences);
+ free (edge_info);
+ }
+ }
+ }
+}
+
/* Jump threading, redundancy elimination and const/copy propagation.
This pass may expose new symbols that need to be renamed into SSA. For
struct dom_walk_data walk_data;
unsigned int i;
+ memset (&opt_stats, 0, sizeof (opt_stats));
+
for (i = 0; i < num_referenced_vars; i++)
var_ann (referenced_var (i))->current_def = NULL;
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 = cprop_into_phis;
+ 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;
interactions between rewriting of _DECL nodes into SSA form
and rewriting SSA_NAME nodes into SSA form after block
duplication and CFG manipulation. */
- if (bitmap_first_set_bit (vars_to_rename) >= 0)
+ if (!bitmap_empty_p (vars_to_rename))
{
rewrite_into_ssa (false);
bitmap_clear (vars_to_rename);
}
+ free_all_edge_infos ();
+
/* Thread jumps, creating duplicate blocks as needed. */
cfg_altered = thread_through_all_blocks ();
/* Removal of statements may make some EH edges dead. Purge
such edges from the CFG as needed. */
- if (bitmap_first_set_bit (need_eh_cleanup) >= 0)
+ if (!bitmap_empty_p (need_eh_cleanup))
{
cfg_altered |= tree_purge_all_dead_eh_edges (need_eh_cleanup);
bitmap_zero (need_eh_cleanup);
/* And finalize the dominator walker. */
fini_walk_dominator_tree (&walk_data);
- /* Free nonzero_vars. */
+ /* Free nonzero_vars. */
BITMAP_XFREE (nonzero_vars);
BITMAP_XFREE (need_eh_cleanup);
{
tree cond, cached_lhs;
edge e1;
+ edge_iterator ei;
/* Do not forward entry edges into the loop. In the case loop
has multiple entry edges we may end up in constructing irreducible
edges forward to the same destination block. */
if (!e->flags & EDGE_DFS_BACK)
{
- for (e1 = e->dest->pred; e; e = e->pred_next)
+ FOR_EACH_EDGE (e1, ei, e->dest->preds)
if (e1->flags & EDGE_DFS_BACK)
break;
if (e1)
}
else
{
- TREE_SET_CODE (TREE_OPERAND (dummy_cond, 0), cond_code);
- TREE_OPERAND (TREE_OPERAND (dummy_cond, 0), 0) = op0;
- TREE_OPERAND (TREE_OPERAND (dummy_cond, 0), 1) = op1;
+ TREE_SET_CODE (COND_EXPR_COND (dummy_cond), cond_code);
+ TREE_OPERAND (COND_EXPR_COND (dummy_cond), 0) = op0;
+ TREE_OPERAND (COND_EXPR_COND (dummy_cond), 1) = op1;
}
/* If the conditional folds to an invariant, then we are done,
/* If we have a known destination for the conditional, then
we can perform this optimization, which saves at least one
conditional jump each time it applies since we get to
- bypass the conditional at our original destination. */
+ bypass the conditional at our original destination. */
if (dest)
{
+ struct edge_info *edge_info;
+
update_bb_profile_for_threading (e->dest, EDGE_FREQUENCY (e),
e->count, taken_edge);
- e->aux = taken_edge;
+ if (e->aux)
+ edge_info = e->aux;
+ else
+ edge_info = allocate_edge_info (e);
+ edge_info->redirection_target = taken_edge;
bb_ann (e->dest)->incoming_edge_threaded = true;
}
}
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, basic_block bb)
+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);
VARRAY_PUSH_TREE (nonzero_vars_stack, NULL_TREE);
VARRAY_PUSH_TREE (vrp_variables_stack, NULL_TREE);
- record_equivalences_from_incoming_edge (walk_data, bb);
+ record_equivalences_from_incoming_edge (bb);
/* PHI nodes can create equivalences too. */
- record_equivalences_from_phis (walk_data, bb);
+ record_equivalences_from_phis (bb);
}
/* Given an expression EXPR (a relational expression or a statement),
the edge from BB through its successor.
Do this before we remove entries from our equivalence tables. */
- if (bb->succ
- && ! bb->succ->succ_next
- && (bb->succ->flags & EDGE_ABNORMAL) == 0
- && (get_immediate_dominator (CDI_DOMINATORS, bb->succ->dest) != bb
- || phi_nodes (bb->succ->dest)))
+ if (EDGE_COUNT (bb->succs) == 1
+ && (EDGE_SUCC (bb, 0)->flags & EDGE_ABNORMAL) == 0
+ && (get_immediate_dominator (CDI_DOMINATORS, EDGE_SUCC (bb, 0)->dest) != bb
+ || phi_nodes (EDGE_SUCC (bb, 0)->dest)))
{
- thread_across_edge (walk_data, bb->succ);
+ thread_across_edge (walk_data, EDGE_SUCC (bb, 0));
}
else if ((last = last_stmt (bb))
&& TREE_CODE (last) == COND_EXPR
&& (COMPARISON_CLASS_P (COND_EXPR_COND (last))
|| TREE_CODE (COND_EXPR_COND (last)) == SSA_NAME)
- && bb->succ
- && (bb->succ->flags & EDGE_ABNORMAL) == 0
- && bb->succ->succ_next
- && (bb->succ->succ_next->flags & EDGE_ABNORMAL) == 0
- && ! bb->succ->succ_next->succ_next)
+ && 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;
- tree cond, inverted = NULL;
- enum tree_code cond_code;
extract_true_false_edges_from_block (bb, &true_edge, &false_edge);
- cond = COND_EXPR_COND (last);
- cond_code = TREE_CODE (cond);
-
- if (TREE_CODE_CLASS (cond_code) == tcc_comparison)
- inverted = invert_truthvalue (cond);
-
/* If the THEN arm is the end of a dominator tree or has PHI nodes,
then try to thread through its edge. */
if (get_immediate_dominator (CDI_DOMINATORS, true_edge->dest) != bb
|| phi_nodes (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. */
VARRAY_PUSH_TREE (block_defs_stack, NULL_TREE);
VARRAY_PUSH_TREE (const_and_copies_stack, NULL_TREE);
- /* Record any equivalences created by following this edge. */
- if (TREE_CODE_CLASS (cond_code) == tcc_comparison)
+ edge_info = true_edge->aux;
+
+ /* If we have info associated with this edge, record it into
+ our equivalency tables. */
+ if (edge_info)
{
- record_cond (cond, boolean_true_node);
- record_dominating_conditions (cond);
- record_cond (inverted, boolean_false_node);
+ tree *cond_equivalences = edge_info->cond_equivalences;
+ tree lhs = edge_info->lhs;
+ tree rhs = edge_info->rhs;
+
+ /* If we have a simple NAME = VALUE equivalency record it.
+ Until the jump threading selection code improves, only
+ do this if both the name and value are SSA_NAMEs with
+ the same underlying variable to avoid missing threading
+ opportunities. */
+ if (lhs
+ && TREE_CODE (COND_EXPR_COND (last)) == SSA_NAME
+ && TREE_CODE (edge_info->rhs) == SSA_NAME
+ && SSA_NAME_VAR (lhs) == SSA_NAME_VAR (rhs))
+ 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 += 2)
+ {
+ tree expr = cond_equivalences[i];
+ tree value = cond_equivalences[i + 1];
+
+ record_cond (expr, value);
+ }
}
- else if (cond_code == SSA_NAME)
- record_const_or_copy (cond, boolean_true_node);
/* Now thread the edge. */
thread_across_edge (walk_data, true_edge);
if (get_immediate_dominator (CDI_DOMINATORS, false_edge->dest) != bb
|| phi_nodes (false_edge->dest))
{
- /* Record any equivalences created by following this edge. */
- if (TREE_CODE_CLASS (cond_code) == tcc_comparison)
+ struct edge_info *edge_info;
+ unsigned int i;
+
+ edge_info = false_edge->aux;
+
+ /* If we have info associated with this edge, record it into
+ our equivalency tables. */
+ if (edge_info)
{
- record_cond (cond, boolean_false_node);
- record_cond (inverted, boolean_true_node);
- record_dominating_conditions (inverted);
+ tree *cond_equivalences = edge_info->cond_equivalences;
+ tree lhs = edge_info->lhs;
+ tree rhs = edge_info->rhs;
+
+ /* If we have a simple NAME = VALUE equivalency record it.
+ Until the jump threading selection code improves, only
+ do this if both the name and value are SSA_NAMEs with
+ the same underlying variable to avoid missing threading
+ opportunities. */
+ if (lhs
+ && TREE_CODE (COND_EXPR_COND (last)) == 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 += 2)
+ {
+ tree expr = cond_equivalences[i];
+ tree value = cond_equivalences[i + 1];
+
+ record_cond (expr, value);
+ }
}
- else if (cond_code == SSA_NAME)
- record_const_or_copy (cond, boolean_false_node);
thread_across_edge (walk_data, false_edge);
while (VARRAY_ACTIVE_SIZE (vrp_variables_stack) > 0)
{
tree var = VARRAY_TOP_TREE (vrp_variables_stack);
- struct vrp_hash_elt vrp_hash_elt;
+ struct vrp_hash_elt vrp_hash_elt, *vrp_hash_elt_p;
void **slot;
/* Each variable has a stack of value range records. We want to
slot = htab_find_slot (vrp_data, &vrp_hash_elt, NO_INSERT);
- var_vrp_records = (*(struct vrp_hash_elt **)slot)->records;
+ vrp_hash_elt_p = (struct vrp_hash_elt *) *slot;
+ var_vrp_records = vrp_hash_elt_p->records;
+
while (VARRAY_ACTIVE_SIZE (var_vrp_records) > 0)
{
struct vrp_element *element
even if we do not know its exact value. */
static void
-record_equivalences_from_phis (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
- basic_block bb)
+record_equivalences_from_phis (basic_block bb)
{
tree phi;
{
edge retval = NULL;
edge e;
+ edge_iterator ei;
- for (e = bb->pred; e; e = e->pred_next)
+ FOR_EACH_EDGE (e, ei, bb->preds)
{
/* A loop back edge can be identified by the destination of
the edge dominating the source of the edge. */
has more than one incoming edge, then no equivalence is created. */
static void
-record_equivalences_from_incoming_edge (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
- basic_block bb)
+record_equivalences_from_incoming_edge (basic_block bb)
{
- int edge_flags;
+ edge e;
basic_block parent;
- struct eq_expr_value eq_expr_value;
- tree parent_block_last_stmt = NULL;
+ struct edge_info *edge_info;
/* If our parent block ended with a control statment, then we may be
able to record some equivalences based on which outgoing edge from
the parent was followed. */
parent = get_immediate_dominator (CDI_DOMINATORS, bb);
- if (parent)
- {
- parent_block_last_stmt = last_stmt (parent);
- if (parent_block_last_stmt && !is_ctrl_stmt (parent_block_last_stmt))
- parent_block_last_stmt = NULL;
- }
- eq_expr_value.src = NULL;
- eq_expr_value.dst = NULL;
+ e = single_incoming_edge_ignoring_loop_edges (bb);
- /* If we have a single predecessor (ignoring loop backedges), then extract
- EDGE_FLAGS from the single incoming edge. Otherwise just return as
- there is nothing to do. */
- if (bb->pred
- && parent_block_last_stmt)
+ /* If we had a single incoming edge from our parent block, then enter
+ any data associated with the edge into our tables. */
+ if (e && e->src == parent)
{
- edge e = single_incoming_edge_ignoring_loop_edges (bb);
- if (e && bb_for_stmt (parent_block_last_stmt) == e->src)
- edge_flags = e->flags;
- else
- return;
- }
- else
- return;
+ unsigned int i;
- /* If our parent block ended in a COND_EXPR, add any equivalences
- created by the COND_EXPR to the hash table and initialize
- EQ_EXPR_VALUE appropriately.
-
- EQ_EXPR_VALUE is an assignment expression created when BB's immediate
- dominator ends in a COND_EXPR statement whose predicate is of the form
- 'VAR == VALUE', where VALUE may be another variable or a constant.
- This is used to propagate VALUE on the THEN_CLAUSE of that
- conditional. This assignment is inserted in CONST_AND_COPIES so that
- the copy and constant propagator can find more propagation
- opportunities. */
- if (TREE_CODE (parent_block_last_stmt) == COND_EXPR
- && (edge_flags & (EDGE_TRUE_VALUE | EDGE_FALSE_VALUE)))
- eq_expr_value = get_eq_expr_value (parent_block_last_stmt,
- (edge_flags & EDGE_TRUE_VALUE) != 0,
- bb);
- /* Similarly when the parent block ended in a SWITCH_EXPR.
- We can only know the value of the switch's condition if the dominator
- parent is also the only predecessor of this block. */
- else if (bb->pred->src == parent
- && TREE_CODE (parent_block_last_stmt) == SWITCH_EXPR)
- {
- tree switch_cond = SWITCH_COND (parent_block_last_stmt);
+ edge_info = e->aux;
- /* If the switch's condition is an SSA variable, then we may
- know its value at each of the case labels. */
- if (TREE_CODE (switch_cond) == SSA_NAME)
+ if (edge_info)
{
- tree switch_vec = SWITCH_LABELS (parent_block_last_stmt);
- size_t i, n = TREE_VEC_LENGTH (switch_vec);
- int case_count = 0;
- tree match_case = NULL_TREE;
-
- /* Search the case labels for those whose destination is
- the current basic block. */
- for (i = 0; i < n; ++i)
+ tree lhs = edge_info->lhs;
+ tree rhs = edge_info->rhs;
+ tree *cond_equivalences = edge_info->cond_equivalences;
+
+ if (lhs)
+ record_equality (lhs, rhs);
+
+ if (cond_equivalences)
{
- tree elt = TREE_VEC_ELT (switch_vec, i);
- if (label_to_block (CASE_LABEL (elt)) == bb)
+ bool recorded_range = false;
+ for (i = 0; i < edge_info->max_cond_equivalences; i += 2)
{
- if (++case_count > 1 || CASE_HIGH (elt))
- break;
- match_case = elt;
+ tree expr = cond_equivalences[i];
+ tree value = cond_equivalences[i + 1];
+
+ record_cond (expr, value);
+
+ /* For the first true equivalence, record range
+ information. We only do this for the first
+ true equivalence as it should dominate any
+ later true equivalences. */
+ if (! recorded_range
+ && COMPARISON_CLASS_P (expr)
+ && value == boolean_true_node
+ && TREE_CONSTANT (TREE_OPERAND (expr, 1)))
+ {
+ record_range (expr, bb);
+ recorded_range = true;
+ }
}
}
-
- /* If we encountered precisely one CASE_LABEL_EXPR and it
- was not the default case, or a case range, then we know
- the exact value of SWITCH_COND which caused us to get to
- this block. Record that equivalence in EQ_EXPR_VALUE. */
- if (case_count == 1
- && match_case
- && CASE_LOW (match_case)
- && !CASE_HIGH (match_case))
- {
- eq_expr_value.dst = switch_cond;
- eq_expr_value.src = fold_convert (TREE_TYPE (switch_cond),
- CASE_LOW (match_case));
- }
}
}
-
- /* If EQ_EXPR_VALUE (VAR == VALUE) is given, register the VALUE as a
- new value for VAR, so that occurrences of VAR can be replaced with
- VALUE while re-writing the THEN arm of a COND_EXPR. */
- if (eq_expr_value.src && eq_expr_value.dst)
- record_equality (eq_expr_value.dst, eq_expr_value.src);
}
/* Dump SSA statistics on FILE. */
free (element);
}
-/* COND is a condition which is known to be true. Record variants of
- COND which must also be true.
+/* Build a new conditional using NEW_CODE, OP0 and OP1 and store
+ the new conditional into *p, then store a boolean_true_node
+ into the the *(p + 1). */
+
+static void
+build_and_record_new_cond (enum tree_code new_code, tree op0, tree op1, tree *p)
+{
+ *p = build2 (new_code, boolean_type_node, op0, op1);
+ p++;
+ *p = boolean_true_node;
+}
+
+/* Record that COND is true and INVERTED is false into the edge information
+ structure. Also record that any conditions dominated by COND are true
+ as well.
For example, if a < b is true, then a <= b must also be true. */
static void
-record_dominating_conditions (tree cond)
+record_conditions (struct edge_info *edge_info, tree cond, tree inverted)
{
+ tree op0, op1;
+
+ if (!COMPARISON_CLASS_P (cond))
+ return;
+
+ op0 = TREE_OPERAND (cond, 0);
+ op1 = TREE_OPERAND (cond, 1);
+
switch (TREE_CODE (cond))
{
case LT_EXPR:
- record_cond (build2 (LE_EXPR, boolean_type_node,
- TREE_OPERAND (cond, 0),
- TREE_OPERAND (cond, 1)),
- boolean_true_node);
- record_cond (build2 (ORDERED_EXPR, boolean_type_node,
- TREE_OPERAND (cond, 0),
- TREE_OPERAND (cond, 1)),
- boolean_true_node);
- record_cond (build2 (NE_EXPR, boolean_type_node,
- TREE_OPERAND (cond, 0),
- TREE_OPERAND (cond, 1)),
- boolean_true_node);
- record_cond (build2 (LTGT_EXPR, boolean_type_node,
- TREE_OPERAND (cond, 0),
- TREE_OPERAND (cond, 1)),
- boolean_true_node);
- break;
-
case GT_EXPR:
- record_cond (build2 (GE_EXPR, boolean_type_node,
- TREE_OPERAND (cond, 0),
- TREE_OPERAND (cond, 1)),
- boolean_true_node);
- record_cond (build2 (ORDERED_EXPR, boolean_type_node,
- TREE_OPERAND (cond, 0),
- TREE_OPERAND (cond, 1)),
- boolean_true_node);
- record_cond (build2 (NE_EXPR, boolean_type_node,
- TREE_OPERAND (cond, 0),
- TREE_OPERAND (cond, 1)),
- boolean_true_node);
- record_cond (build2 (LTGT_EXPR, boolean_type_node,
- TREE_OPERAND (cond, 0),
- TREE_OPERAND (cond, 1)),
- boolean_true_node);
+ edge_info->max_cond_equivalences = 12;
+ edge_info->cond_equivalences = xmalloc (12 * sizeof (tree));
+ build_and_record_new_cond ((TREE_CODE (cond) == LT_EXPR
+ ? LE_EXPR : GE_EXPR),
+ op0, op1, &edge_info->cond_equivalences[4]);
+ build_and_record_new_cond (ORDERED_EXPR, op0, op1,
+ &edge_info->cond_equivalences[6]);
+ build_and_record_new_cond (NE_EXPR, op0, op1,
+ &edge_info->cond_equivalences[8]);
+ build_and_record_new_cond (LTGT_EXPR, op0, op1,
+ &edge_info->cond_equivalences[10]);
break;
case GE_EXPR:
case LE_EXPR:
- record_cond (build2 (ORDERED_EXPR, boolean_type_node,
- TREE_OPERAND (cond, 0),
- TREE_OPERAND (cond, 1)),
- boolean_true_node);
+ edge_info->max_cond_equivalences = 6;
+ edge_info->cond_equivalences = xmalloc (6 * sizeof (tree));
+ build_and_record_new_cond (ORDERED_EXPR, op0, op1,
+ &edge_info->cond_equivalences[4]);
break;
case EQ_EXPR:
- record_cond (build2 (ORDERED_EXPR, boolean_type_node,
- TREE_OPERAND (cond, 0),
- TREE_OPERAND (cond, 1)),
- boolean_true_node);
- record_cond (build2 (LE_EXPR, boolean_type_node,
- TREE_OPERAND (cond, 0),
- TREE_OPERAND (cond, 1)),
- boolean_true_node);
- record_cond (build2 (GE_EXPR, boolean_type_node,
- TREE_OPERAND (cond, 0),
- TREE_OPERAND (cond, 1)),
- boolean_true_node);
+ edge_info->max_cond_equivalences = 10;
+ edge_info->cond_equivalences = xmalloc (10 * sizeof (tree));
+ build_and_record_new_cond (ORDERED_EXPR, op0, op1,
+ &edge_info->cond_equivalences[4]);
+ build_and_record_new_cond (LE_EXPR, op0, op1,
+ &edge_info->cond_equivalences[6]);
+ build_and_record_new_cond (GE_EXPR, op0, op1,
+ &edge_info->cond_equivalences[8]);
break;
case UNORDERED_EXPR:
- record_cond (build2 (NE_EXPR, boolean_type_node,
- TREE_OPERAND (cond, 0),
- TREE_OPERAND (cond, 1)),
- boolean_true_node);
- record_cond (build2 (UNLE_EXPR, boolean_type_node,
- TREE_OPERAND (cond, 0),
- TREE_OPERAND (cond, 1)),
- boolean_true_node);
- record_cond (build2 (UNGE_EXPR, boolean_type_node,
- TREE_OPERAND (cond, 0),
- TREE_OPERAND (cond, 1)),
- boolean_true_node);
- record_cond (build2 (UNEQ_EXPR, boolean_type_node,
- TREE_OPERAND (cond, 0),
- TREE_OPERAND (cond, 1)),
- boolean_true_node);
- record_cond (build2 (UNLT_EXPR, boolean_type_node,
- TREE_OPERAND (cond, 0),
- TREE_OPERAND (cond, 1)),
- boolean_true_node);
- record_cond (build2 (UNGT_EXPR, boolean_type_node,
- TREE_OPERAND (cond, 0),
- TREE_OPERAND (cond, 1)),
- boolean_true_node);
+ edge_info->max_cond_equivalences = 16;
+ edge_info->cond_equivalences = xmalloc (16 * sizeof (tree));
+ build_and_record_new_cond (NE_EXPR, op0, op1,
+ &edge_info->cond_equivalences[4]);
+ build_and_record_new_cond (UNLE_EXPR, op0, op1,
+ &edge_info->cond_equivalences[6]);
+ build_and_record_new_cond (UNGE_EXPR, op0, op1,
+ &edge_info->cond_equivalences[8]);
+ build_and_record_new_cond (UNEQ_EXPR, op0, op1,
+ &edge_info->cond_equivalences[10]);
+ build_and_record_new_cond (UNLT_EXPR, op0, op1,
+ &edge_info->cond_equivalences[12]);
+ build_and_record_new_cond (UNGT_EXPR, op0, op1,
+ &edge_info->cond_equivalences[14]);
break;
case UNLT_EXPR:
- record_cond (build2 (UNLE_EXPR, boolean_type_node,
- TREE_OPERAND (cond, 0),
- TREE_OPERAND (cond, 1)),
- boolean_true_node);
- record_cond (build2 (NE_EXPR, boolean_type_node,
- TREE_OPERAND (cond, 0),
- TREE_OPERAND (cond, 1)),
- boolean_true_node);
- break;
-
case UNGT_EXPR:
- record_cond (build2 (UNGE_EXPR, boolean_type_node,
- TREE_OPERAND (cond, 0),
- TREE_OPERAND (cond, 1)),
- boolean_true_node);
- record_cond (build2 (NE_EXPR, boolean_type_node,
- TREE_OPERAND (cond, 0),
- TREE_OPERAND (cond, 1)),
- boolean_true_node);
+ edge_info->max_cond_equivalences = 8;
+ edge_info->cond_equivalences = xmalloc (8 * sizeof (tree));
+ build_and_record_new_cond ((TREE_CODE (cond) == UNLT_EXPR
+ ? UNLE_EXPR : UNGE_EXPR),
+ op0, op1, &edge_info->cond_equivalences[4]);
+ build_and_record_new_cond (NE_EXPR, op0, op1,
+ &edge_info->cond_equivalences[6]);
break;
case UNEQ_EXPR:
- record_cond (build2 (UNLE_EXPR, boolean_type_node,
- TREE_OPERAND (cond, 0),
- TREE_OPERAND (cond, 1)),
- boolean_true_node);
- record_cond (build2 (UNGE_EXPR, boolean_type_node,
- TREE_OPERAND (cond, 0),
- TREE_OPERAND (cond, 1)),
- boolean_true_node);
+ edge_info->max_cond_equivalences = 8;
+ edge_info->cond_equivalences = xmalloc (8 * sizeof (tree));
+ build_and_record_new_cond (UNLE_EXPR, op0, op1,
+ &edge_info->cond_equivalences[4]);
+ build_and_record_new_cond (UNGE_EXPR, op0, op1,
+ &edge_info->cond_equivalences[6]);
break;
case LTGT_EXPR:
- record_cond (build2 (NE_EXPR, boolean_type_node,
- TREE_OPERAND (cond, 0),
- TREE_OPERAND (cond, 1)),
- boolean_true_node);
- record_cond (build2 (ORDERED_EXPR, boolean_type_node,
- TREE_OPERAND (cond, 0),
- TREE_OPERAND (cond, 1)),
- boolean_true_node);
+ edge_info->max_cond_equivalences = 8;
+ edge_info->cond_equivalences = xmalloc (8 * sizeof (tree));
+ build_and_record_new_cond (NE_EXPR, op0, op1,
+ &edge_info->cond_equivalences[4]);
+ build_and_record_new_cond (ORDERED_EXPR, op0, op1,
+ &edge_info->cond_equivalences[6]);
+ break;
default:
+ edge_info->max_cond_equivalences = 4;
+ edge_info->cond_equivalences = xmalloc (4 * sizeof (tree));
break;
}
+
+ /* Now store the original true and false conditions into the first
+ two slots. */
+ edge_info->cond_equivalences[0] = cond;
+ edge_info->cond_equivalences[1] = boolean_true_node;
+ edge_info->cond_equivalences[2] = inverted;
+ edge_info->cond_equivalences[3] = boolean_false_node;
}
/* A helper function for record_const_or_copy and record_equality.
VARRAY_PUSH_TREE (const_and_copies_stack, x);
}
+
+/* Return the loop depth of the basic block of the defining statement of X.
+ This number should not be treated as absolutely correct because the loop
+ information may not be completely up-to-date when dom runs. However, it
+ will be relatively correct, and as more passes are taught to keep loop info
+ up to date, the result will become more and more accurate. */
+
+static int
+loop_depth_of_name (tree x)
+{
+ tree defstmt;
+ basic_block defbb;
+
+ /* If it's not an SSA_NAME, we have no clue where the definition is. */
+ if (TREE_CODE (x) != SSA_NAME)
+ return 0;
+
+ /* Otherwise return the loop depth of the defining statement's bb.
+ Note that there may not actually be a bb for this statement, if the
+ ssa_name is live on entry. */
+ defstmt = SSA_NAME_DEF_STMT (x);
+ defbb = bb_for_stmt (defstmt);
+ if (!defbb)
+ return 0;
+
+ return defbb->loop_depth;
+}
+
+
/* Record that X is equal to Y in const_and_copies. Record undo
information in the block-local varray. */
if (TREE_CODE (y) == SSA_NAME)
prev_y = SSA_NAME_VALUE (y);
- /* If one of the previous values is invariant, then use that.
+ /* If one of the previous values is invariant, or invariant in more loops
+ (by depth), then use that.
Otherwise it doesn't matter which value we choose, just so
long as we canonicalize on one value. */
if (TREE_INVARIANT (y))
;
- else if (TREE_INVARIANT (x))
+ else if (TREE_INVARIANT (x) || (loop_depth_of_name (x) <= loop_depth_of_name (y)))
prev_x = x, x = y, y = prev_x, prev_x = prev_y;
else if (prev_x && TREE_INVARIANT (prev_x))
x = y, y = prev_x, prev_x = prev_y;
record_const_or_copy_1 (x, y, prev_x);
}
+/* Return true, if it is ok to do folding of an associative expression.
+ EXP is the tree for the associative expression. */
+
+static inline bool
+unsafe_associative_fp_binop (tree exp)
+{
+ enum tree_code code = TREE_CODE (exp);
+ return !(!flag_unsafe_math_optimizations
+ && (code == MULT_EXPR || code == PLUS_EXPR
+ || code == MINUS_EXPR)
+ && FLOAT_TYPE_P (TREE_TYPE (exp)));
+}
+
/* STMT is a MODIFY_EXPR for which we were unable to find RHS in the
hash tables. Try to simplify the RHS using whatever equivalences
we may have recorded.
tree rhs_def_rhs = TREE_OPERAND (rhs_def_stmt, 1);
enum tree_code rhs_def_code = TREE_CODE (rhs_def_rhs);
- if (rhs_code == rhs_def_code
+ if ((rhs_code == rhs_def_code && unsafe_associative_fp_binop (rhs))
|| (rhs_code == PLUS_EXPR && rhs_def_code == MINUS_EXPR)
|| (rhs_code == MINUS_EXPR && rhs_def_code == PLUS_EXPR))
{
}
else
{
- TREE_SET_CODE (TREE_OPERAND (dummy_cond, 0), GT_EXPR);
- TREE_OPERAND (TREE_OPERAND (dummy_cond, 0), 0) = op;
- TREE_OPERAND (TREE_OPERAND (dummy_cond, 0), 1)
+ TREE_SET_CODE (COND_EXPR_COND (dummy_cond), GT_EXPR);
+ TREE_OPERAND (COND_EXPR_COND (dummy_cond), 0) = op;
+ TREE_OPERAND (COND_EXPR_COND (dummy_cond), 1)
= integer_zero_node;
}
val = simplify_cond_and_lookup_avail_expr (dummy_cond, NULL, false);
}
else
{
- TREE_SET_CODE (TREE_OPERAND (dummy_cond, 0), LE_EXPR);
- TREE_OPERAND (TREE_OPERAND (dummy_cond, 0), 0) = op;
- TREE_OPERAND (TREE_OPERAND (dummy_cond, 0), 1)
+ TREE_SET_CODE (COND_EXPR_COND (dummy_cond), LE_EXPR);
+ TREE_OPERAND (COND_EXPR_COND (dummy_cond), 0) = op;
+ TREE_OPERAND (COND_EXPR_COND (dummy_cond), 1)
= build_int_cst (type, 0);
}
val = simplify_cond_and_lookup_avail_expr (dummy_cond, NULL, false);
if (!val)
{
- TREE_SET_CODE (TREE_OPERAND (dummy_cond, 0), GE_EXPR);
- TREE_OPERAND (TREE_OPERAND (dummy_cond, 0), 0) = op;
- TREE_OPERAND (TREE_OPERAND (dummy_cond, 0), 1)
+ TREE_SET_CODE (COND_EXPR_COND (dummy_cond), GE_EXPR);
+ TREE_OPERAND (COND_EXPR_COND (dummy_cond), 0) = op;
+ TREE_OPERAND (COND_EXPR_COND (dummy_cond), 1)
= build_int_cst (type, 0);
val = simplify_cond_and_lookup_avail_expr (dummy_cond,
int lowequal, highequal, swapped, no_overlap, subset, cond_inverted;
varray_type vrp_records;
struct vrp_element *element;
- struct vrp_hash_elt vrp_hash_elt;
+ struct vrp_hash_elt vrp_hash_elt, *vrp_hash_elt_p;
void **slot;
/* First see if we have test of an SSA_NAME against a constant
if (slot == NULL)
return NULL;
- vrp_records = (*(struct vrp_hash_elt **)slot)->records;
+ vrp_hash_elt_p = (struct vrp_hash_elt *) *slot;
+ vrp_records = vrp_hash_elt_p->records;
if (vrp_records == NULL)
return NULL;
cprop_into_successor_phis (basic_block bb, bitmap nonzero_vars)
{
edge e;
+ edge_iterator ei;
/* This can get rather expensive if the implementation is naive in
how it finds the phi alternative associated with a particular edge. */
- for (e = bb->succ; e; e = e->succ_next)
+ FOR_EACH_EDGE (e, ei, bb->succs)
{
tree phi;
int phi_num_args;
}
}
+/* We have finished optimizing BB, record any information implied by
+ taking a specific outgoing edge from BB. */
+
+static void
+record_edge_info (basic_block bb)
+{
+ block_stmt_iterator bsi = bsi_last (bb);
+ struct edge_info *edge_info;
+
+ if (! bsi_end_p (bsi))
+ {
+ tree stmt = bsi_stmt (bsi);
+
+ if (stmt && TREE_CODE (stmt) == SWITCH_EXPR)
+ {
+ tree cond = SWITCH_COND (stmt);
+
+ if (TREE_CODE (cond) == SSA_NAME)
+ {
+ tree labels = SWITCH_LABELS (stmt);
+ int i, n_labels = TREE_VEC_LENGTH (labels);
+ tree *info = xcalloc (n_basic_blocks, sizeof (tree));
+ edge e;
+ edge_iterator ei;
+
+ for (i = 0; i < n_labels; i++)
+ {
+ tree label = TREE_VEC_ELT (labels, i);
+ basic_block target_bb = label_to_block (CASE_LABEL (label));
+
+ if (CASE_HIGH (label)
+ || !CASE_LOW (label)
+ || info[target_bb->index])
+ info[target_bb->index] = error_mark_node;
+ else
+ info[target_bb->index] = label;
+ }
+
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ {
+ basic_block target_bb = e->dest;
+ tree node = info[target_bb->index];
+
+ if (node != NULL && node != error_mark_node)
+ {
+ tree x = fold_convert (TREE_TYPE (cond), CASE_LOW (node));
+ edge_info = allocate_edge_info (e);
+ edge_info->lhs = cond;
+ edge_info->rhs = x;
+ }
+ }
+ free (info);
+ }
+ }
+
+ /* A COND_EXPR may create equivalences too. */
+ if (stmt && TREE_CODE (stmt) == COND_EXPR)
+ {
+ tree cond = COND_EXPR_COND (stmt);
+ edge true_edge;
+ edge false_edge;
+
+ extract_true_false_edges_from_block (bb, &true_edge, &false_edge);
+
+ /* If the conditional is a single variable 'X', record 'X = 1'
+ for the true edge and 'X = 0' on the false edge. */
+ if (SSA_VAR_P (cond))
+ {
+ struct edge_info *edge_info;
+
+ edge_info = allocate_edge_info (true_edge);
+ edge_info->lhs = cond;
+ edge_info->rhs = constant_boolean_node (1, TREE_TYPE (cond));
+
+ edge_info = allocate_edge_info (false_edge);
+ edge_info->lhs = cond;
+ edge_info->rhs = constant_boolean_node (0, TREE_TYPE (cond));
+ }
+ /* Equality tests may create one or two equivalences. */
+ else if (COMPARISON_CLASS_P (cond))
+ {
+ tree op0 = TREE_OPERAND (cond, 0);
+ tree op1 = TREE_OPERAND (cond, 1);
+
+ /* Special case comparing booleans against a constant as we
+ know the value of OP0 on both arms of the branch. i.e., we
+ can record an equivalence for OP0 rather than COND. */
+ if ((TREE_CODE (cond) == EQ_EXPR || TREE_CODE (cond) == NE_EXPR)
+ && TREE_CODE (op0) == SSA_NAME
+ && TREE_CODE (TREE_TYPE (op0)) == BOOLEAN_TYPE
+ && is_gimple_min_invariant (op1))
+ {
+ if (TREE_CODE (cond) == EQ_EXPR)
+ {
+ edge_info = allocate_edge_info (true_edge);
+ edge_info->lhs = op0;
+ edge_info->rhs = (integer_zerop (op1)
+ ? boolean_false_node
+ : boolean_true_node);
+
+ edge_info = allocate_edge_info (false_edge);
+ edge_info->lhs = op0;
+ edge_info->rhs = (integer_zerop (op1)
+ ? boolean_true_node
+ : boolean_false_node);
+ }
+ else
+ {
+ edge_info = allocate_edge_info (true_edge);
+ edge_info->lhs = op0;
+ edge_info->rhs = (integer_zerop (op1)
+ ? boolean_true_node
+ : boolean_false_node);
+
+ edge_info = allocate_edge_info (false_edge);
+ edge_info->lhs = op0;
+ edge_info->rhs = (integer_zerop (op1)
+ ? boolean_false_node
+ : boolean_true_node);
+ }
+ }
+
+ if (is_gimple_min_invariant (op0)
+ && (TREE_CODE (op1) == SSA_NAME
+ || is_gimple_min_invariant (op1)))
+ {
+ tree inverted = invert_truthvalue (cond);
+ struct edge_info *edge_info;
+
+ edge_info = allocate_edge_info (true_edge);
+ record_conditions (edge_info, cond, inverted);
+
+ if (TREE_CODE (cond) == 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 (cond) == NE_EXPR)
+ {
+ edge_info->lhs = op1;
+ edge_info->rhs = op0;
+ }
+ }
+
+ if (TREE_CODE (op0) == SSA_NAME
+ && (is_gimple_min_invariant (op1)
+ || TREE_CODE (op1) == SSA_NAME))
+ {
+ tree inverted = invert_truthvalue (cond);
+ struct edge_info *edge_info;
+
+ edge_info = allocate_edge_info (true_edge);
+ record_conditions (edge_info, cond, inverted);
+
+ if (TREE_CODE (cond) == 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 (cond) == NE_EXPR)
+ {
+ edge_info->lhs = op0;
+ edge_info->rhs = op1;
+ }
+ }
+ }
+
+ /* ??? TRUTH_NOT_EXPR can create an equivalence too. */
+ }
+ }
+}
+
+/* Propagate information from BB to its outgoing edges.
-/* Propagate known constants/copies into PHI nodes of BB's successor
- blocks. */
+ This can include equivalency information implied by control statements
+ at the end of BB and const/copy propagation into PHIs in BB's
+ successor blocks. */
static void
-cprop_into_phis (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
- basic_block bb)
+propagate_to_outgoing_edges (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
+ basic_block bb)
{
+
+ record_edge_info (bb);
cprop_into_successor_phis (bb, nonzero_vars);
}
def = TREE_OPERAND (stmt, 0);
/* Certain expressions on the RHS can be optimized away, but can not
- themselves be entered into the hash tables. */
+ themselves be entered into the hash tables. */
if (ann->makes_aliased_stores
|| ! def
|| TREE_CODE (def) != SSA_NAME
t = TREE_OPERAND (t, 0);
/* Now see if this is a pointer dereference. */
- if (TREE_CODE (t) == INDIRECT_REF
- || TREE_CODE (t) == ALIGN_INDIRECT_REF
- || TREE_CODE (t) == MISALIGNED_INDIRECT_REF)
+ if (INDIRECT_REF_P (t))
{
tree op = TREE_OPERAND (t, 0);
|| TREE_CODE (val) != SSA_NAME))
return false;
+ /* Do not replace hard register operands in asm statements. */
+ if (TREE_CODE (stmt) == ASM_EXPR
+ && !may_propagate_copy_into_asm (op))
+ return false;
+
/* Get the toplevel type of each operand. */
op_type = TREE_TYPE (op);
val_type = TREE_TYPE (val);
static void
record_range (tree cond, basic_block bb)
{
- /* We explicitly ignore NE_EXPRs. They rarely allow for meaningful
- range optimizations and significantly complicate the implementation. */
- if (COMPARISON_CLASS_P (cond)
- && TREE_CODE (cond) != NE_EXPR
+ enum tree_code code = TREE_CODE (cond);
+
+ /* We explicitly ignore NE_EXPRs and all the unordered comparisons.
+ They rarely allow for meaningful range optimizations and significantly
+ complicate the implementation. */
+ if ((code == LT_EXPR || code == LE_EXPR || code == GT_EXPR
+ || code == GE_EXPR || code == EQ_EXPR)
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (cond, 1))) == INTEGER_TYPE)
{
struct vrp_hash_elt *vrp_hash_elt;
if (*slot == NULL)
*slot = (void *) vrp_hash_elt;
+ else
+ free (vrp_hash_elt);
vrp_hash_elt = (struct vrp_hash_elt *) *slot;
vrp_records_p = &vrp_hash_elt->records;
}
}
-/* Given a conditional statement IF_STMT, return the assignment 'X = Y'
- known to be true depending on which arm of IF_STMT is taken.
-
- Not all conditional statements will result in a useful assignment.
- Return NULL_TREE in that case.
-
- Also enter into the available expression table statements of
- the form:
-
- TRUE ARM FALSE ARM
- 1 = cond 1 = cond'
- 0 = cond' 0 = cond
-
- This allows us to lookup the condition in a dominated block and
- get back a constant indicating if the condition is true. */
-
-static struct eq_expr_value
-get_eq_expr_value (tree if_stmt,
- int true_arm,
- basic_block bb)
-{
- tree cond;
- struct eq_expr_value retval;
-
- cond = COND_EXPR_COND (if_stmt);
- retval.src = NULL;
- retval.dst = NULL;
-
- /* If the conditional is a single variable 'X', return 'X = 1' for
- the true arm and 'X = 0' on the false arm. */
- if (TREE_CODE (cond) == SSA_NAME)
- {
- retval.dst = cond;
- retval.src = constant_boolean_node (true_arm, TREE_TYPE (cond));
- return retval;
- }
-
- /* If we have a comparison expression, then record its result into
- the available expression table. */
- if (COMPARISON_CLASS_P (cond))
- {
- tree op0 = TREE_OPERAND (cond, 0);
- tree op1 = TREE_OPERAND (cond, 1);
-
- /* Special case comparing booleans against a constant as we know
- the value of OP0 on both arms of the branch. i.e., we can record
- an equivalence for OP0 rather than COND. */
- if ((TREE_CODE (cond) == EQ_EXPR || TREE_CODE (cond) == NE_EXPR)
- && TREE_CODE (op0) == SSA_NAME
- && TREE_CODE (TREE_TYPE (op0)) == BOOLEAN_TYPE
- && is_gimple_min_invariant (op1))
- {
- if ((TREE_CODE (cond) == EQ_EXPR && true_arm)
- || (TREE_CODE (cond) == NE_EXPR && ! true_arm))
- {
- retval.src = op1;
- }
- else
- {
- if (integer_zerop (op1))
- retval.src = boolean_true_node;
- else
- retval.src = boolean_false_node;
- }
- retval.dst = op0;
- return retval;
- }
-
- if (TREE_CODE (op0) == SSA_NAME
- && (is_gimple_min_invariant (op1) || TREE_CODE (op1) == SSA_NAME))
- {
- tree inverted = invert_truthvalue (cond);
-
- /* When we find an available expression in the hash table, we replace
- the expression with the LHS of the statement in the hash table.
-
- So, we want to build statements such as "1 = <condition>" on the
- true arm and "0 = <condition>" on the false arm. That way if we
- find the expression in the table, we will replace it with its
- known constant value. Also insert inversions of the result and
- condition into the hash table. */
- if (true_arm)
- {
- record_cond (cond, boolean_true_node);
- record_dominating_conditions (cond);
- record_cond (inverted, boolean_false_node);
-
- if (TREE_CONSTANT (op1))
- record_range (cond, bb);
-
- /* If the conditional is of the form 'X == Y', return 'X = Y'
- for the true arm. */
- if (TREE_CODE (cond) == EQ_EXPR)
- {
- retval.dst = op0;
- retval.src = op1;
- return retval;
- }
- }
- else
- {
-
- record_cond (inverted, boolean_true_node);
- record_dominating_conditions (inverted);
- record_cond (cond, boolean_false_node);
-
- if (TREE_CONSTANT (op1))
- record_range (inverted, bb);
-
- /* If the conditional is of the form 'X != Y', return 'X = Y'
- for the false arm. */
- if (TREE_CODE (cond) == NE_EXPR)
- {
- retval.dst = op0;
- retval.src = op1;
- return retval;
- }
- }
- }
- }
-
- return retval;
-}
-
/* Hashing and equality functions for VRP_DATA.
Since this hash table is addressed by SSA_NAMEs, we can hash on