From a3d514f231af029090ba40ebcdae4226b739433c Mon Sep 17 00:00:00 2001 From: Jeff Law Date: Wed, 15 Mar 2017 21:19:35 -0600 Subject: [PATCH] re PR tree-optimization/71437 (Performance regression after r235817) PR tree-optimization/71437 * tree-ssa-dom.c (struct cond_equivalence): Moved from here into tree-ssa-scopedtables. (lookup_avail_expr, build_and_record_new_cond): Likewise. (record_conditions, record_cond, vuse_eq): Likewise. (record_edge_info): Adjust to API tweak of record_conditions. (simplify_stmt_for_jump_threading): Similarly for lookup_avail_expr. (record_temporary_equivalences, optimize_stmt): Likewise. (eliminate_redundant_computations): Likewise. (record_equivalences_from_stmt): Likewise. * tree-ssa-scopedtables.c: Include options.h and params.h. (vuse_eq): New function, moved from tree-ssa-dom.c (build_and_record_new_cond): Likewise. (record_conditions): Likewise. Accept vector of conditions rather than edge_equivalence structure for first argument. for the first argument. (avail_exprs_stack::lookup_avail_expr): New member function, moved from tree-ssa-dom.c. (avail_exprs_stack::record_cond): Likewise. * tree-ssa-scopedtables.h (struct cond_equivalence): Moved here from tree-ssa-dom.c. (avail_exprs_stack): Add new member functions lookup_avail_expr and record_cond. (record_conditions): Declare. From-SVN: r246186 --- gcc/ChangeLog | 27 +++ gcc/tree-ssa-dom.c | 319 ++---------------------------------- gcc/tree-ssa-scopedtables.c | 271 ++++++++++++++++++++++++++++++ gcc/tree-ssa-scopedtables.h | 21 +++ 4 files changed, 329 insertions(+), 309 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 88f60073d99..23a611236b9 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,30 @@ +2017-03-15 Jeff Law + + PR tree-optimization/71437 + * tree-ssa-dom.c (struct cond_equivalence): Moved from here into + tree-ssa-scopedtables. + (lookup_avail_expr, build_and_record_new_cond): Likewise. + (record_conditions, record_cond, vuse_eq): Likewise. + (record_edge_info): Adjust to API tweak of record_conditions. + (simplify_stmt_for_jump_threading): Similarly for lookup_avail_expr. + (record_temporary_equivalences, optimize_stmt): Likewise. + (eliminate_redundant_computations): Likewise. + (record_equivalences_from_stmt): Likewise. + * tree-ssa-scopedtables.c: Include options.h and params.h. + (vuse_eq): New function, moved from tree-ssa-dom.c + (build_and_record_new_cond): Likewise. + (record_conditions): Likewise. Accept vector of conditions rather + than edge_equivalence structure for first argument. + for the first argument. + (avail_exprs_stack::lookup_avail_expr): New member function, moved + from tree-ssa-dom.c. + (avail_exprs_stack::record_cond): Likewise. + * tree-ssa-scopedtables.h (struct cond_equivalence): Moved here + from tree-ssa-dom.c. + (avail_exprs_stack): Add new member functions lookup_avail_expr + and record_cond. + (record_conditions): Declare. + 2017-03-15 Vladimir Makarov PR target/80017 diff --git a/gcc/tree-ssa-dom.c b/gcc/tree-ssa-dom.c index 2ec3f97e6d4..ad71269ce3d 100644 --- a/gcc/tree-ssa-dom.c +++ b/gcc/tree-ssa-dom.c @@ -48,15 +48,6 @@ along with GCC; see the file COPYING3. If not see /* This file implements optimizations on the dominator tree. */ -/* Structure for recording known values of a conditional expression - at the exits from its block. */ - -struct cond_equivalence -{ - struct hashable_expr cond; - tree value; -}; - /* Structure for recording edge equivalences. Computing and storing the edge equivalences instead of creating @@ -103,9 +94,6 @@ static struct opt_stats_d opt_stats; static edge optimize_stmt (basic_block, gimple_stmt_iterator, class const_and_copies *, class avail_exprs_stack *); -static tree lookup_avail_expr (gimple *, bool, class avail_exprs_stack *, - bool = true); -static void record_cond (cond_equivalence *, class avail_exprs_stack *); static void record_equality (tree, tree, class const_and_copies *); static void record_equivalences_from_phis (basic_block); static void record_equivalences_from_incoming_edge (basic_block, @@ -175,148 +163,6 @@ free_all_edge_infos (void) } } -/* Build a cond_equivalence record indicating that the comparison - CODE holds between operands OP0 and OP1 and push it to **P. */ - -static void -build_and_record_new_cond (enum tree_code code, - tree op0, tree op1, - vec *p, - bool val = true) -{ - cond_equivalence c; - struct hashable_expr *cond = &c.cond; - - gcc_assert (TREE_CODE_CLASS (code) == tcc_comparison); - - cond->type = boolean_type_node; - cond->kind = EXPR_BINARY; - cond->ops.binary.op = code; - cond->ops.binary.opnd0 = op0; - cond->ops.binary.opnd1 = op1; - - c.value = val ? boolean_true_node : boolean_false_node; - p->safe_push (c); -} - -/* 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_conditions (struct edge_info *edge_info, tree cond, tree inverted) -{ - tree op0, op1; - cond_equivalence c; - - if (!COMPARISON_CLASS_P (cond)) - return; - - op0 = TREE_OPERAND (cond, 0); - op1 = TREE_OPERAND (cond, 1); - - switch (TREE_CODE (cond)) - { - case LT_EXPR: - case GT_EXPR: - if (FLOAT_TYPE_P (TREE_TYPE (op0))) - { - build_and_record_new_cond (ORDERED_EXPR, op0, op1, - &edge_info->cond_equivalences); - build_and_record_new_cond (LTGT_EXPR, op0, op1, - &edge_info->cond_equivalences); - } - - build_and_record_new_cond ((TREE_CODE (cond) == LT_EXPR - ? LE_EXPR : GE_EXPR), - op0, op1, &edge_info->cond_equivalences); - build_and_record_new_cond (NE_EXPR, op0, op1, - &edge_info->cond_equivalences); - build_and_record_new_cond (EQ_EXPR, op0, op1, - &edge_info->cond_equivalences, false); - break; - - case GE_EXPR: - case LE_EXPR: - if (FLOAT_TYPE_P (TREE_TYPE (op0))) - { - build_and_record_new_cond (ORDERED_EXPR, op0, op1, - &edge_info->cond_equivalences); - } - break; - - case EQ_EXPR: - if (FLOAT_TYPE_P (TREE_TYPE (op0))) - { - build_and_record_new_cond (ORDERED_EXPR, op0, op1, - &edge_info->cond_equivalences); - } - build_and_record_new_cond (LE_EXPR, op0, op1, - &edge_info->cond_equivalences); - build_and_record_new_cond (GE_EXPR, op0, op1, - &edge_info->cond_equivalences); - break; - - case UNORDERED_EXPR: - build_and_record_new_cond (NE_EXPR, op0, op1, - &edge_info->cond_equivalences); - build_and_record_new_cond (UNLE_EXPR, op0, op1, - &edge_info->cond_equivalences); - build_and_record_new_cond (UNGE_EXPR, op0, op1, - &edge_info->cond_equivalences); - build_and_record_new_cond (UNEQ_EXPR, op0, op1, - &edge_info->cond_equivalences); - build_and_record_new_cond (UNLT_EXPR, op0, op1, - &edge_info->cond_equivalences); - build_and_record_new_cond (UNGT_EXPR, op0, op1, - &edge_info->cond_equivalences); - break; - - case UNLT_EXPR: - case UNGT_EXPR: - build_and_record_new_cond ((TREE_CODE (cond) == UNLT_EXPR - ? UNLE_EXPR : UNGE_EXPR), - op0, op1, &edge_info->cond_equivalences); - build_and_record_new_cond (NE_EXPR, op0, op1, - &edge_info->cond_equivalences); - break; - - case UNEQ_EXPR: - build_and_record_new_cond (UNLE_EXPR, op0, op1, - &edge_info->cond_equivalences); - build_and_record_new_cond (UNGE_EXPR, op0, op1, - &edge_info->cond_equivalences); - break; - - case LTGT_EXPR: - build_and_record_new_cond (NE_EXPR, op0, op1, - &edge_info->cond_equivalences); - build_and_record_new_cond (ORDERED_EXPR, op0, op1, - &edge_info->cond_equivalences); - break; - - default: - break; - } - - /* Now store the original true and false conditions into the first - two slots. */ - initialize_expr_from_cond (cond, &c.cond); - c.value = boolean_true_node; - edge_info->cond_equivalences.safe_push (c); - - /* It is possible for INVERTED to be the negation of a comparison, - and not a valid RHS or GIMPLE_COND condition. This happens because - invert_truthvalue may return such an expression when asked to invert - a floating-point comparison. These comparisons are not assumed to - obey the trichotomy law. */ - initialize_expr_from_cond (inverted, &c.cond); - c.value = boolean_false_node; - edge_info->cond_equivalences.safe_push (c); -} - /* We have finished optimizing BB, record any information implied by taking a specific outgoing edge from BB. */ @@ -435,7 +281,7 @@ record_edge_info (basic_block bb) struct edge_info *edge_info; edge_info = allocate_edge_info (true_edge); - record_conditions (edge_info, cond, inverted); + record_conditions (&edge_info->cond_equivalences, cond, inverted); if (can_infer_simple_equiv && code == EQ_EXPR) { @@ -444,7 +290,7 @@ record_edge_info (basic_block bb) } edge_info = allocate_edge_info (false_edge); - record_conditions (edge_info, inverted, cond); + record_conditions (&edge_info->cond_equivalences, inverted, cond); if (can_infer_simple_equiv && TREE_CODE (inverted) == EQ_EXPR) { @@ -465,7 +311,7 @@ record_edge_info (basic_block bb) struct edge_info *edge_info; edge_info = allocate_edge_info (true_edge); - record_conditions (edge_info, cond, inverted); + record_conditions (&edge_info->cond_equivalences, cond, inverted); if (can_infer_simple_equiv && code == EQ_EXPR) { @@ -474,7 +320,7 @@ record_edge_info (basic_block bb) } edge_info = allocate_edge_info (false_edge); - record_conditions (edge_info, inverted, cond); + record_conditions (&edge_info->cond_equivalences, inverted, cond); if (can_infer_simple_equiv && TREE_CODE (inverted) == EQ_EXPR) { @@ -760,7 +606,7 @@ simplify_stmt_for_jump_threading (gimple *stmt, gimple *within_stmt ATTRIBUTE_UNUSED, class avail_exprs_stack *avail_exprs_stack) { - return lookup_avail_expr (stmt, false, avail_exprs_stack); + return avail_exprs_stack->lookup_avail_expr (stmt, false, true); } /* Valueize hook for gimple_fold_stmt_to_constant_1. */ @@ -865,7 +711,7 @@ record_temporary_equivalences (edge e, /* If we have 0 = COND or 1 = COND equivalences, record them into our expression hash tables. */ for (i = 0; edge_info->cond_equivalences.iterate (i, &eq); ++i) - record_cond (eq, avail_exprs_stack); + avail_exprs_stack->record_cond (eq); tree lhs = edge_info->lhs; if (!lhs || TREE_CODE (lhs) != SSA_NAME) @@ -1105,29 +951,6 @@ dump_dominator_optimization_stats (FILE *file, } -/* Enter condition equivalence P into AVAIL_EXPRS_HASH. - - This indicates that a conditional expression has a known - boolean value. */ - -static void -record_cond (cond_equivalence *p, - class avail_exprs_stack *avail_exprs_stack) -{ - class expr_hash_elt *element = new expr_hash_elt (&p->cond, p->value); - expr_hash_elt **slot; - - hash_table *avail_exprs = avail_exprs_stack->avail_exprs (); - slot = avail_exprs->find_slot_with_hash (element, element->hash (), INSERT); - if (*slot == NULL) - { - *slot = element; - avail_exprs_stack->record_expr (element, NULL, '1'); - } - else - delete element; -} - /* Similarly, but assume that X and Y are the two operands of an EQ_EXPR. This constrains the cases in which we may treat this as assignment. */ @@ -1426,7 +1249,7 @@ eliminate_redundant_computations (gimple_stmt_iterator* gsi, insert = false; /* Check if the expression has been computed before. */ - cached_lhs = lookup_avail_expr (stmt, insert, avail_exprs_stack); + cached_lhs = avail_exprs_stack->lookup_avail_expr (stmt, insert, true); opt_stats.num_exprs_considered++; @@ -1611,7 +1434,7 @@ record_equivalences_from_stmt (gimple *stmt, int may_optimize_p, /* Finally enter the statement into the available expression table. */ - lookup_avail_expr (new_stmt, true, avail_exprs_stack); + avail_exprs_stack->lookup_avail_expr (new_stmt, true, true); } } @@ -1865,8 +1688,8 @@ optimize_stmt (basic_block bb, gimple_stmt_iterator si, else new_stmt = gimple_build_assign (rhs, lhs); gimple_set_vuse (new_stmt, gimple_vuse (stmt)); - cached_lhs = lookup_avail_expr (new_stmt, false, avail_exprs_stack, - false); + cached_lhs = avail_exprs_stack->lookup_avail_expr (new_stmt, false, + false); if (cached_lhs && rhs == cached_lhs) { @@ -1942,125 +1765,3 @@ optimize_stmt (basic_block bb, gimple_stmt_iterator si, } return retval; } - -/* Helper for walk_non_aliased_vuses. Determine if we arrived at - the desired memory state. */ - -static void * -vuse_eq (ao_ref *, tree vuse1, unsigned int cnt, void *data) -{ - tree vuse2 = (tree) data; - if (vuse1 == vuse2) - return data; - - /* This bounds the stmt walks we perform on reference lookups - to O(1) instead of O(N) where N is the number of dominating - stores leading to a candidate. We re-use the SCCVN param - for this as it is basically the same complexity. */ - if (cnt > (unsigned) PARAM_VALUE (PARAM_SCCVN_MAX_ALIAS_QUERIES_PER_ACCESS)) - return (void *)-1; - - return NULL; -} - -/* Search for an existing instance of STMT in the AVAIL_EXPRS_STACK table. - If found, return its LHS. Otherwise insert STMT in the table and - return NULL_TREE. - - Also, when an expression is first inserted in the table, it is also - is also added to AVAIL_EXPRS_STACK, so that it can be removed when - we finish processing this block and its children. */ - -static tree -lookup_avail_expr (gimple *stmt, bool insert, - class avail_exprs_stack *avail_exprs_stack, bool tbaa_p) -{ - expr_hash_elt **slot; - tree lhs; - - /* Get LHS of phi, assignment, or call; else NULL_TREE. */ - if (gimple_code (stmt) == GIMPLE_PHI) - lhs = gimple_phi_result (stmt); - else - lhs = gimple_get_lhs (stmt); - - class expr_hash_elt element (stmt, lhs); - - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, "LKUP "); - element.print (dump_file); - } - - /* 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))) - return NULL_TREE; - - /* Finally try to find the expression in the main expression hash table. */ - hash_table *avail_exprs = avail_exprs_stack->avail_exprs (); - slot = avail_exprs->find_slot (&element, (insert ? INSERT : NO_INSERT)); - if (slot == NULL) - { - return NULL_TREE; - } - else if (*slot == NULL) - { - class expr_hash_elt *element2 = new expr_hash_elt (element); - *slot = element2; - - avail_exprs_stack->record_expr (element2, NULL, '2'); - return NULL_TREE; - } - - /* If we found a redundant memory operation do an alias walk to - check if we can re-use it. */ - if (gimple_vuse (stmt) != (*slot)->vop ()) - { - tree vuse1 = (*slot)->vop (); - tree vuse2 = gimple_vuse (stmt); - /* If we have a load of a register and a candidate in the - hash with vuse1 then try to reach its stmt by walking - up the virtual use-def chain using walk_non_aliased_vuses. - But don't do this when removing expressions from the hash. */ - ao_ref ref; - if (!(vuse1 && vuse2 - && gimple_assign_single_p (stmt) - && TREE_CODE (gimple_assign_lhs (stmt)) == SSA_NAME - && (ao_ref_init (&ref, gimple_assign_rhs1 (stmt)), - ref.base_alias_set = ref.ref_alias_set = tbaa_p ? -1 : 0, true) - && walk_non_aliased_vuses (&ref, vuse2, - vuse_eq, NULL, NULL, vuse1) != NULL)) - { - if (insert) - { - class expr_hash_elt *element2 = new expr_hash_elt (element); - - /* Insert the expr into the hash by replacing the current - entry and recording the value to restore in the - avail_exprs_stack. */ - avail_exprs_stack->record_expr (element2, *slot, '2'); - *slot = element2; - } - return NULL_TREE; - } - } - - /* Extract the LHS of the assignment so that it can be used as the current - definition of another variable. */ - lhs = (*slot)->lhs (); - - lhs = dom_valueize (lhs); - - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, "FIND: "); - print_generic_expr (dump_file, lhs, 0); - fprintf (dump_file, "\n"); - } - - return lhs; -} diff --git a/gcc/tree-ssa-scopedtables.c b/gcc/tree-ssa-scopedtables.c index e5de6a54369..3e7233376cb 100644 --- a/gcc/tree-ssa-scopedtables.c +++ b/gcc/tree-ssa-scopedtables.c @@ -33,6 +33,8 @@ along with GCC; see the file COPYING3. If not see #include "tree-eh.h" #include "internal-fn.h" #include "tree-dfa.h" +#include "options.h" +#include "params.h" static bool hashable_expr_equal_p (const struct hashable_expr *, const struct hashable_expr *); @@ -94,6 +96,153 @@ avail_exprs_stack::record_expr (class expr_hash_elt *elt1, m_stack.safe_push (std::pair (elt1, elt2)); } +/* Helper for walk_non_aliased_vuses. Determine if we arrived at + the desired memory state. */ + +static void * +vuse_eq (ao_ref *, tree vuse1, unsigned int cnt, void *data) +{ + tree vuse2 = (tree) data; + if (vuse1 == vuse2) + return data; + + /* This bounds the stmt walks we perform on reference lookups + to O(1) instead of O(N) where N is the number of dominating + stores leading to a candidate. We re-use the SCCVN param + for this as it is basically the same complexity. */ + if (cnt > (unsigned) PARAM_VALUE (PARAM_SCCVN_MAX_ALIAS_QUERIES_PER_ACCESS)) + return (void *)-1; + + return NULL; +} + +/* Search for an existing instance of STMT in the AVAIL_EXPRS_STACK table. + If found, return its LHS. Otherwise insert STMT in the table and + return NULL_TREE. + + Also, when an expression is first inserted in the table, it is also + is also added to AVAIL_EXPRS_STACK, so that it can be removed when + we finish processing this block and its children. */ + +tree +avail_exprs_stack::lookup_avail_expr (gimple *stmt, bool insert, bool tbaa_p) +{ + expr_hash_elt **slot; + tree lhs; + + /* Get LHS of phi, assignment, or call; else NULL_TREE. */ + if (gimple_code (stmt) == GIMPLE_PHI) + lhs = gimple_phi_result (stmt); + else + lhs = gimple_get_lhs (stmt); + + class expr_hash_elt element (stmt, lhs); + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "LKUP "); + element.print (dump_file); + } + + /* 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))) + return NULL_TREE; + + /* Finally try to find the expression in the main expression hash table. */ + slot = m_avail_exprs->find_slot (&element, (insert ? INSERT : NO_INSERT)); + if (slot == NULL) + { + return NULL_TREE; + } + else if (*slot == NULL) + { + class expr_hash_elt *element2 = new expr_hash_elt (element); + *slot = element2; + + record_expr (element2, NULL, '2'); + return NULL_TREE; + } + + /* If we found a redundant memory operation do an alias walk to + check if we can re-use it. */ + if (gimple_vuse (stmt) != (*slot)->vop ()) + { + tree vuse1 = (*slot)->vop (); + tree vuse2 = gimple_vuse (stmt); + /* If we have a load of a register and a candidate in the + hash with vuse1 then try to reach its stmt by walking + up the virtual use-def chain using walk_non_aliased_vuses. + But don't do this when removing expressions from the hash. */ + ao_ref ref; + if (!(vuse1 && vuse2 + && gimple_assign_single_p (stmt) + && TREE_CODE (gimple_assign_lhs (stmt)) == SSA_NAME + && (ao_ref_init (&ref, gimple_assign_rhs1 (stmt)), + ref.base_alias_set = ref.ref_alias_set = tbaa_p ? -1 : 0, true) + && walk_non_aliased_vuses (&ref, vuse2, + vuse_eq, NULL, NULL, vuse1) != NULL)) + { + if (insert) + { + class expr_hash_elt *element2 = new expr_hash_elt (element); + + /* Insert the expr into the hash by replacing the current + entry and recording the value to restore in the + avail_exprs_stack. */ + record_expr (element2, *slot, '2'); + *slot = element2; + } + return NULL_TREE; + } + } + + /* Extract the LHS of the assignment so that it can be used as the current + definition of another variable. */ + lhs = (*slot)->lhs (); + + /* Valueize the result. */ + if (TREE_CODE (lhs) == SSA_NAME) + { + tree tem = SSA_NAME_VALUE (lhs); + if (tem) + lhs = tem; + } + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "FIND: "); + print_generic_expr (dump_file, lhs, 0); + fprintf (dump_file, "\n"); + } + + return lhs; +} + +/* Enter condition equivalence P into the hash table. + + This indicates that a conditional expression has a known + boolean value. */ + +void +avail_exprs_stack::record_cond (cond_equivalence *p) +{ + class expr_hash_elt *element = new expr_hash_elt (&p->cond, p->value); + expr_hash_elt **slot; + + slot = m_avail_exprs->find_slot_with_hash (element, element->hash (), INSERT); + if (*slot == NULL) + { + *slot = element; + record_expr (element, NULL, '1'); + } + else + delete element; +} + /* Generate a hash value for a pair of expressions. This can be used iteratively by passing a previous result in HSTATE. @@ -798,3 +947,125 @@ initialize_expr_from_cond (tree cond, struct hashable_expr *expr) gcc_unreachable (); } +/* Build a cond_equivalence record indicating that the comparison + CODE holds between operands OP0 and OP1 and push it to **P. */ + +static void +build_and_record_new_cond (enum tree_code code, + tree op0, tree op1, + vec *p, + bool val = true) +{ + cond_equivalence c; + struct hashable_expr *cond = &c.cond; + + gcc_assert (TREE_CODE_CLASS (code) == tcc_comparison); + + cond->type = boolean_type_node; + cond->kind = EXPR_BINARY; + cond->ops.binary.op = code; + cond->ops.binary.opnd0 = op0; + cond->ops.binary.opnd1 = op1; + + c.value = val ? boolean_true_node : boolean_false_node; + p->safe_push (c); +} + +/* 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. */ + +void +record_conditions (vec *p, tree cond, tree inverted) +{ + tree op0, op1; + cond_equivalence c; + + if (!COMPARISON_CLASS_P (cond)) + return; + + op0 = TREE_OPERAND (cond, 0); + op1 = TREE_OPERAND (cond, 1); + + switch (TREE_CODE (cond)) + { + case LT_EXPR: + case GT_EXPR: + if (FLOAT_TYPE_P (TREE_TYPE (op0))) + { + build_and_record_new_cond (ORDERED_EXPR, op0, op1, p); + build_and_record_new_cond (LTGT_EXPR, op0, op1, p); + } + + build_and_record_new_cond ((TREE_CODE (cond) == LT_EXPR + ? LE_EXPR : GE_EXPR), + op0, op1, p); + build_and_record_new_cond (NE_EXPR, op0, op1, p); + build_and_record_new_cond (EQ_EXPR, op0, op1, p, false); + break; + + case GE_EXPR: + case LE_EXPR: + if (FLOAT_TYPE_P (TREE_TYPE (op0))) + { + build_and_record_new_cond (ORDERED_EXPR, op0, op1, p); + } + break; + + case EQ_EXPR: + if (FLOAT_TYPE_P (TREE_TYPE (op0))) + { + build_and_record_new_cond (ORDERED_EXPR, op0, op1, p); + } + build_and_record_new_cond (LE_EXPR, op0, op1, p); + build_and_record_new_cond (GE_EXPR, op0, op1, p); + break; + + case UNORDERED_EXPR: + build_and_record_new_cond (NE_EXPR, op0, op1, p); + build_and_record_new_cond (UNLE_EXPR, op0, op1, p); + build_and_record_new_cond (UNGE_EXPR, op0, op1, p); + build_and_record_new_cond (UNEQ_EXPR, op0, op1, p); + build_and_record_new_cond (UNLT_EXPR, op0, op1, p); + build_and_record_new_cond (UNGT_EXPR, op0, op1, p); + break; + + case UNLT_EXPR: + case UNGT_EXPR: + build_and_record_new_cond ((TREE_CODE (cond) == UNLT_EXPR + ? UNLE_EXPR : UNGE_EXPR), + op0, op1, p); + build_and_record_new_cond (NE_EXPR, op0, op1, p); + break; + + case UNEQ_EXPR: + build_and_record_new_cond (UNLE_EXPR, op0, op1, p); + build_and_record_new_cond (UNGE_EXPR, op0, op1, p); + break; + + case LTGT_EXPR: + build_and_record_new_cond (NE_EXPR, op0, op1, p); + build_and_record_new_cond (ORDERED_EXPR, op0, op1, p); + break; + + default: + break; + } + + /* Now store the original true and false conditions into the first + two slots. */ + initialize_expr_from_cond (cond, &c.cond); + c.value = boolean_true_node; + p->safe_push (c); + + /* It is possible for INVERTED to be the negation of a comparison, + and not a valid RHS or GIMPLE_COND condition. This happens because + invert_truthvalue may return such an expression when asked to invert + a floating-point comparison. These comparisons are not assumed to + obey the trichotomy law. */ + initialize_expr_from_cond (inverted, &c.cond); + c.value = boolean_false_node; + p->safe_push (c); +} diff --git a/gcc/tree-ssa-scopedtables.h b/gcc/tree-ssa-scopedtables.h index 3e6798a1982..df304aedbf4 100644 --- a/gcc/tree-ssa-scopedtables.h +++ b/gcc/tree-ssa-scopedtables.h @@ -47,6 +47,20 @@ struct hashable_expr } ops; }; +/* Structure for recording known value of a conditional expression. + + Clients build vectors of these objects to record known values + that occur on edges. */ + +struct cond_equivalence +{ + /* The condition, in a HASHABLE_EXPR form. */ + struct hashable_expr cond; + + /* The result of the condition (true or false. */ + tree value; +}; + /* Structure for entries in the expression hash table. */ typedef class expr_hash_elt * expr_hash_elt_t; @@ -132,6 +146,12 @@ class avail_exprs_stack hash_table *avail_exprs (void) { return m_avail_exprs; } + /* Lookup and conditionally insert an expression into the table, + recording enough information to unwind as needed. */ + tree lookup_avail_expr (gimple *, bool, bool); + + void record_cond (cond_equivalence *); + private: vec > m_stack; hash_table *m_avail_exprs; @@ -182,5 +202,6 @@ class const_and_copies }; void initialize_expr_from_cond (tree cond, struct hashable_expr *expr); +void record_conditions (vec *p, tree, tree); #endif /* GCC_TREE_SSA_SCOPED_TABLES_H */ -- 2.30.2