diff options
author | Jeff Law <law@redhat.com> | 2004-10-29 18:06:22 -0600 |
---|---|---|
committer | Jeff Law <law@gcc.gnu.org> | 2004-10-29 18:06:22 -0600 |
commit | efea75f9a48a3b5571ed974fd48aaf42616f877c (patch) | |
tree | 530ac2f67b6fb4445dfaebac63e5456ff97a9510 /gcc/tree-ssa-dom.c | |
parent | cc92f54fcff028571601312836c427692ae93161 (diff) | |
download | gcc-efea75f9a48a3b5571ed974fd48aaf42616f877c.zip gcc-efea75f9a48a3b5571ed974fd48aaf42616f877c.tar.gz gcc-efea75f9a48a3b5571ed974fd48aaf42616f877c.tar.bz2 |
tree-ssa-dom.c (struct edge_info): New structure holding edge equivalences and edge redirection information.
* tree-ssa-dom.c (struct edge_info): New structure holding
edge equivalences and edge redirection information.
(get_eq_expr_value, record_dominating_conditions): Kill.
(propagate_to_outgoing_edges): Renamed from cprop_into_phis.
Call record_edge_info.
(allocate_edge_info, free_edge_info): New.
(tree_ssa_dominator_optimize): Use propagate_to_outgoing_edges
rather than cprop_into_phis. Free all edge infos before threading
jumps.
(thread_across_edge): Allocate new edge info structures as needed
and store the redirection target into the edge info structure
instead of the edge's AUX field.
(dom_opt_initialize_block): Mark unused argument with ATTRIBUTE_UNUSED.
(record_equivalence_from_incoming_edge): Lose unnecessary argument.
Revamp code which finds and records equivalences associated with
edges to use saved data in the edge_info structure.
(record_equivalencs_from_phis): Similarly.
(dom_opt_finalize_block): Revamp code which finds and records
equivalences associated with edges to use saved data in the
edge_info structure.
(build_and_record_new_cond): New function.
(record_conditions): Use build_and_record_new_cond to record
dominating conditions.
(record_edge_info): New function.
(record_range): Tighten test for conditions which create
useful range records.
From-SVN: r89866
Diffstat (limited to 'gcc/tree-ssa-dom.c')
-rw-r--r-- | gcc/tree-ssa-dom.c | 845 |
1 files changed, 482 insertions, 363 deletions
diff --git a/gcc/tree-ssa-dom.c b/gcc/tree-ssa-dom.c index 41102ea..b50767f 100644 --- a/gcc/tree-ssa-dom.c +++ b/gcc/tree-ssa-dom.c @@ -45,6 +45,40 @@ Boston, MA 02111-1307, USA. */ /* 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 @@ -231,7 +265,6 @@ static void optimize_stmt (struct dom_walk_data *, 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 *); @@ -239,7 +272,6 @@ static hashval_t real_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); @@ -250,16 +282,15 @@ static tree simplify_switch_and_lookup_avail_expr (tree, int); 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); @@ -283,6 +314,50 @@ local_fold (tree t) 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 partciular 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 @@ -323,7 +398,7 @@ tree_ssa_dominator_optimize (void) 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; @@ -362,6 +437,8 @@ tree_ssa_dominator_optimize (void) bitmap_clear (vars_to_rename); } + free_all_edge_infos (); + /* Thread jumps, creating duplicate blocks as needed. */ cfg_altered = thread_through_all_blocks (); @@ -697,9 +774,15 @@ thread_across_edge (struct dom_walk_data *walk_data, edge e) 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; } } @@ -712,7 +795,8 @@ thread_across_edge (struct dom_walk_data *walk_data, edge e) 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); @@ -725,10 +809,10 @@ dom_opt_initialize_block (struct dom_walk_data *walk_data, basic_block bb) 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), @@ -900,22 +984,17 @@ dom_opt_finalize_block (struct dom_walk_data *walk_data, basic_block bb) && (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. */ @@ -923,15 +1002,38 @@ dom_opt_finalize_block (struct dom_walk_data *walk_data, basic_block bb) 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); @@ -947,15 +1049,39 @@ dom_opt_finalize_block (struct dom_walk_data *walk_data, basic_block bb) 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); @@ -1040,8 +1166,7 @@ dom_opt_finalize_block (struct dom_walk_data *walk_data, basic_block bb) 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; @@ -1138,110 +1263,62 @@ single_incoming_edge_ignoring_loop_edges (basic_block bb) 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 (EDGE_COUNT (bb->preds) >= 1 - && 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 (EDGE_PRED (bb, 0)->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. */ @@ -1333,150 +1410,129 @@ record_cond (tree cond, tree value) 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. @@ -2311,14 +2367,198 @@ cprop_into_successor_phis (basic_block bb, bitmap nonzero_vars) } } +/* 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]; -/* Propagate known constants/copies into PHI nodes of BB's successor - blocks. */ + 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 conditinoal 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. + + 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); } @@ -3037,10 +3277,13 @@ extract_range_from_cond (tree cond, tree *hi_p, tree *lo_p, int *inverted_p) 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; @@ -3076,130 +3319,6 @@ record_range (tree cond, basic_block bb) } } -/* 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 |