The following restricts the number of locations we register a predicate as valid which avoids the expensive linear search for cases like
if (a) A; if (a) B; if (a) C; ... where we register a != 0 as true for locations A, B, C ... in an unlimited way. The patch simply choses 8 as limit. The underlying issue for this case is the data structure which does not allow for easy "forgetting" or more optimal searching when locations become no longer relevant (the whole point of the location list is to represent where predicates are relevant). The patch also splits the search/copy loop into two to avoid copying stuff that we'll not need when finding an existing better entry or, new now, when we figure we run over the limit. Bootstrapped and tested on x86_64-unknown-linux-gnu, pushed. PR tree-optimization/87615 * tree-ssa-sccvn.cc (vn_nary_op_insert_into): When inserting a new predicate or location into an existing predicate list make sure to not exceed 8 locations. Avoid copying things when we later eventually throw them away. (vn_nary_op_insert_pieces_predicated): Avoid expensive check when not checking. (dominated_by_p_w_unex): Apply the limit on a single successors predecessor count consistently. --- gcc/tree-ssa-sccvn.cc | 68 ++++++++++++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 23 deletions(-) diff --git a/gcc/tree-ssa-sccvn.cc b/gcc/tree-ssa-sccvn.cc index 3212063ad74..8ec0a199705 100644 --- a/gcc/tree-ssa-sccvn.cc +++ b/gcc/tree-ssa-sccvn.cc @@ -4699,12 +4699,17 @@ vn_nary_op_insert_into (vn_nary_op_t vno, vn_nary_op_table_type *table) = BASIC_BLOCK_FOR_FN (cfun, vno->u.values->valid_dominated_by_p[0]); vn_pval *nval = vno->u.values; vn_pval **next = &vno->u.values; - bool found = false; + vn_pval *ins = NULL; + vn_pval *ins_at = NULL; + /* Find an existing value to append to. */ for (vn_pval *val = (*slot)->u.values; val; val = val->next) { if (expressions_equal_p (val->result, nval->result)) { - found = true; + /* Limit the number of places we register a predicate + as valid. */ + if (val->n > 8) + return *slot; for (unsigned i = 0; i < val->n; ++i) { basic_block val_bb @@ -4718,33 +4723,45 @@ vn_nary_op_insert_into (vn_nary_op_t vno, vn_nary_op_table_type *table) gcc_assert (!dominated_by_p (CDI_DOMINATORS, val_bb, vno_bb)); } - /* Append value. */ - *next = (vn_pval *) obstack_alloc (&vn_tables_obstack, - sizeof (vn_pval) - + val->n * sizeof (int)); - (*next)->next = NULL; - (*next)->result = val->result; - (*next)->n = val->n + 1; - memcpy ((*next)->valid_dominated_by_p, + /* Append the location. */ + ins_at = val; + ins = (vn_pval *) obstack_alloc (&vn_tables_obstack, + sizeof (vn_pval) + + val->n * sizeof (int)); + ins->next = NULL; + ins->result = val->result; + ins->n = val->n + 1; + memcpy (ins->valid_dominated_by_p, val->valid_dominated_by_p, val->n * sizeof (int)); - (*next)->valid_dominated_by_p[val->n] = vno_bb->index; - next = &(*next)->next; + ins->valid_dominated_by_p[val->n] = vno_bb->index; if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, "Appending predicate to value.\n"); - continue; + break; + } + } + /* Copy the rest of the value chain. */ + for (vn_pval *val = (*slot)->u.values; val; val = val->next) + { + if (val == ins_at) + /* Replace the node we appended to. */ + *next = ins; + else + { + /* Copy other predicated values. */ + *next = (vn_pval *) obstack_alloc (&vn_tables_obstack, + sizeof (vn_pval) + + ((val->n-1) + * sizeof (int))); + memcpy (*next, val, + sizeof (vn_pval) + (val->n-1) * sizeof (int)); + (*next)->next = NULL; } - /* Copy other predicated values. */ - *next = (vn_pval *) obstack_alloc (&vn_tables_obstack, - sizeof (vn_pval) - + (val->n-1) * sizeof (int)); - memcpy (*next, val, sizeof (vn_pval) + (val->n-1) * sizeof (int)); - (*next)->next = NULL; next = &(*next)->next; } - if (!found) + /* Append the value if we didn't find it. */ + if (!ins_at) *next = nval; - *slot = vno; vno->next = last_inserted_nary; last_inserted_nary = vno; @@ -4819,7 +4836,8 @@ vn_nary_op_insert_pieces_predicated (unsigned int length, enum tree_code code, tree result, unsigned int value_id, edge pred_e) { - gcc_assert (can_track_predicate_on_edge (pred_e)); + if (flag_checking) + gcc_assert (can_track_predicate_on_edge (pred_e)); if (dump_file && (dump_flags & TDF_DETAILS) /* ??? Fix dumping, but currently we only get comparisons. */ @@ -5258,7 +5276,11 @@ dominated_by_p_w_unex (basic_block bb1, basic_block bb2, bool allow_back) } succe = e; } - if (succe) + if (succe + /* Limit the number of edges we check, we should bring in + context from the iteration and compute the single + executable incoming edge when visiting a block. */ + && EDGE_COUNT (succe->dest->preds) < 8) { /* Verify the reached block is only reached through succe. If there is only one edge we can spare us the dominator -- 2.43.0