diff options
-rw-r--r-- | gcc/ipa-cp.c | 245 | ||||
-rw-r--r-- | gcc/ipa-fnsummary.c | 440 | ||||
-rw-r--r-- | gcc/ipa-fnsummary.h | 27 | ||||
-rw-r--r-- | gcc/ipa-inline-analysis.c | 41 | ||||
-rw-r--r-- | gcc/ipa-prop.c | 10 | ||||
-rw-r--r-- | gcc/ipa-prop.h | 112 |
6 files changed, 449 insertions, 426 deletions
diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c index b3e7d41..292dd7e 100644 --- a/gcc/ipa-cp.c +++ b/gcc/ipa-cp.c @@ -3117,30 +3117,40 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie, return target; } +/* If an indirect edge IE can be turned into a direct one based on data in + AVALS, return the destination. Store into *SPECULATIVE a boolean determinig + whether the discovered target is only speculative guess. */ -/* If an indirect edge IE can be turned into a direct one based on KNOWN_CSTS, - KNOWN_CONTEXTS (which can be vNULL) or KNOWN_AGGS (which also can be vNULL) - return the destination. */ +tree +ipa_get_indirect_edge_target (struct cgraph_edge *ie, + ipa_call_arg_values *avals, + bool *speculative) +{ + return ipa_get_indirect_edge_target_1 (ie, avals->m_known_vals, + avals->m_known_contexts, + avals->m_known_aggs, + NULL, speculative); +} + +/* The same functionality as above overloaded for ipa_auto_call_arg_values. */ tree ipa_get_indirect_edge_target (struct cgraph_edge *ie, - vec<tree> known_csts, - vec<ipa_polymorphic_call_context> known_contexts, - vec<ipa_agg_value_set> known_aggs, + ipa_auto_call_arg_values *avals, bool *speculative) { - return ipa_get_indirect_edge_target_1 (ie, known_csts, known_contexts, - known_aggs, NULL, speculative); + return ipa_get_indirect_edge_target_1 (ie, avals->m_known_vals, + avals->m_known_contexts, + avals->m_known_aggs, + NULL, speculative); } -/* Calculate devirtualization time bonus for NODE, assuming we know KNOWN_CSTS - and KNOWN_CONTEXTS. */ +/* Calculate devirtualization time bonus for NODE, assuming we know information + about arguments stored in AVALS. */ static int devirtualization_time_bonus (struct cgraph_node *node, - vec<tree> known_csts, - vec<ipa_polymorphic_call_context> known_contexts, - vec<ipa_agg_value_set> known_aggs) + ipa_auto_call_arg_values *avals) { struct cgraph_edge *ie; int res = 0; @@ -3153,8 +3163,7 @@ devirtualization_time_bonus (struct cgraph_node *node, tree target; bool speculative; - target = ipa_get_indirect_edge_target (ie, known_csts, known_contexts, - known_aggs, &speculative); + target = ipa_get_indirect_edge_target (ie, avals, &speculative); if (!target) continue; @@ -3306,32 +3315,27 @@ context_independent_aggregate_values (class ipcp_param_lattices *plats) return res; } -/* Allocate KNOWN_CSTS, KNOWN_CONTEXTS and, if non-NULL, KNOWN_AGGS and - populate them with values of parameters that are known independent of the - context. INFO describes the function. If REMOVABLE_PARAMS_COST is - non-NULL, the movement cost of all removable parameters will be stored in - it. */ +/* Grow vectors in AVALS and fill them with information about values of + parameters that are known to be independent of the context. Only calculate + m_known_aggs if CALCULATE_AGGS is true. INFO describes the function. If + REMOVABLE_PARAMS_COST is non-NULL, the movement cost of all removable + parameters will be stored in it. + + TODO: Also grow context independent value range vectors. */ static bool gather_context_independent_values (class ipa_node_params *info, - vec<tree> *known_csts, - vec<ipa_polymorphic_call_context> - *known_contexts, - vec<ipa_agg_value_set> *known_aggs, + ipa_auto_call_arg_values *avals, + bool calculate_aggs, int *removable_params_cost) { int i, count = ipa_get_param_count (info); bool ret = false; - known_csts->create (0); - known_contexts->create (0); - known_csts->safe_grow_cleared (count, true); - known_contexts->safe_grow_cleared (count, true); - if (known_aggs) - { - known_aggs->create (0); - known_aggs->safe_grow_cleared (count, true); - } + avals->m_known_vals.safe_grow_cleared (count, true); + avals->m_known_contexts.safe_grow_cleared (count, true); + if (calculate_aggs) + avals->m_known_aggs.safe_grow_cleared (count, true); if (removable_params_cost) *removable_params_cost = 0; @@ -3345,7 +3349,7 @@ gather_context_independent_values (class ipa_node_params *info, { ipcp_value<tree> *val = lat->values; gcc_checking_assert (TREE_CODE (val->value) != TREE_BINFO); - (*known_csts)[i] = val->value; + avals->m_known_vals[i] = val->value; if (removable_params_cost) *removable_params_cost += estimate_move_cost (TREE_TYPE (val->value), false); @@ -3363,15 +3367,15 @@ gather_context_independent_values (class ipa_node_params *info, /* Do not account known context as reason for cloning. We can see if it permits devirtualization. */ if (ctxlat->is_single_const ()) - (*known_contexts)[i] = ctxlat->values->value; + avals->m_known_contexts[i] = ctxlat->values->value; - if (known_aggs) + if (calculate_aggs) { vec<ipa_agg_value> agg_items; struct ipa_agg_value_set *agg; agg_items = context_independent_aggregate_values (plats); - agg = &(*known_aggs)[i]; + agg = &avals->m_known_aggs[i]; agg->items = agg_items; agg->by_ref = plats->aggs_by_ref; ret |= !agg_items.is_empty (); @@ -3381,25 +3385,23 @@ gather_context_independent_values (class ipa_node_params *info, return ret; } -/* Perform time and size measurement of NODE with the context given in - KNOWN_CSTS, KNOWN_CONTEXTS and KNOWN_AGGS, calculate the benefit and cost - given BASE_TIME of the node without specialization, REMOVABLE_PARAMS_COST of - all context-independent removable parameters and EST_MOVE_COST of estimated - movement of the considered parameter and store it into VAL. */ +/* Perform time and size measurement of NODE with the context given in AVALS, + calculate the benefit compared to the node without specialization and store + it into VAL. Take into account REMOVABLE_PARAMS_COST of all + context-independent or unused removable parameters and EST_MOVE_COST, the + estimated movement of the considered parameter. */ static void -perform_estimation_of_a_value (cgraph_node *node, vec<tree> known_csts, - vec<ipa_polymorphic_call_context> known_contexts, - vec<ipa_agg_value_set> known_aggs, - int removable_params_cost, - int est_move_cost, ipcp_value_base *val) +perform_estimation_of_a_value (cgraph_node *node, + ipa_auto_call_arg_values *avals, + int removable_params_cost, int est_move_cost, + ipcp_value_base *val) { int size, time_benefit; sreal time, base_time; ipa_hints hints; - estimate_ipcp_clone_size_and_time (node, known_csts, known_contexts, - known_aggs, &size, &time, + estimate_ipcp_clone_size_and_time (node, avals, &size, &time, &base_time, &hints); base_time -= time; if (base_time > 65535) @@ -3412,8 +3414,7 @@ perform_estimation_of_a_value (cgraph_node *node, vec<tree> known_csts, time_benefit = 0; else time_benefit = base_time.to_int () - + devirtualization_time_bonus (node, known_csts, known_contexts, - known_aggs) + + devirtualization_time_bonus (node, avals) + hint_time_bonus (node, hints) + removable_params_cost + est_move_cost; @@ -3454,9 +3455,6 @@ estimate_local_effects (struct cgraph_node *node) { class ipa_node_params *info = IPA_NODE_REF (node); int i, count = ipa_get_param_count (info); - vec<tree> known_csts; - vec<ipa_polymorphic_call_context> known_contexts; - vec<ipa_agg_value_set> known_aggs; bool always_const; int removable_params_cost; @@ -3466,11 +3464,10 @@ estimate_local_effects (struct cgraph_node *node) if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, "\nEstimating effects for %s.\n", node->dump_name ()); - always_const = gather_context_independent_values (info, &known_csts, - &known_contexts, &known_aggs, + ipa_auto_call_arg_values avals; + always_const = gather_context_independent_values (info, &avals, true, &removable_params_cost); - int devirt_bonus = devirtualization_time_bonus (node, known_csts, - known_contexts, known_aggs); + int devirt_bonus = devirtualization_time_bonus (node, &avals); if (always_const || devirt_bonus || (removable_params_cost && node->can_change_signature)) { @@ -3482,8 +3479,7 @@ estimate_local_effects (struct cgraph_node *node) init_caller_stats (&stats); node->call_for_symbol_thunks_and_aliases (gather_caller_stats, &stats, false); - estimate_ipcp_clone_size_and_time (node, known_csts, known_contexts, - known_aggs, &size, &time, + estimate_ipcp_clone_size_and_time (node, &avals, &size, &time, &base_time, &hints); time -= devirt_bonus; time -= hint_time_bonus (node, hints); @@ -3536,18 +3532,17 @@ estimate_local_effects (struct cgraph_node *node) if (lat->bottom || !lat->values - || known_csts[i]) + || avals.m_known_vals[i]) continue; for (val = lat->values; val; val = val->next) { gcc_checking_assert (TREE_CODE (val->value) != TREE_BINFO); - known_csts[i] = val->value; + avals.m_known_vals[i] = val->value; int emc = estimate_move_cost (TREE_TYPE (val->value), true); - perform_estimation_of_a_value (node, known_csts, known_contexts, - known_aggs, - removable_params_cost, emc, val); + perform_estimation_of_a_value (node, &avals, removable_params_cost, + emc, val); if (dump_file && (dump_flags & TDF_DETAILS)) { @@ -3559,7 +3554,7 @@ estimate_local_effects (struct cgraph_node *node) val->local_time_benefit, val->local_size_cost); } } - known_csts[i] = NULL_TREE; + avals.m_known_vals[i] = NULL_TREE; } for (i = 0; i < count; i++) @@ -3574,15 +3569,14 @@ estimate_local_effects (struct cgraph_node *node) if (ctxlat->bottom || !ctxlat->values - || !known_contexts[i].useless_p ()) + || !avals.m_known_contexts[i].useless_p ()) continue; for (val = ctxlat->values; val; val = val->next) { - known_contexts[i] = val->value; - perform_estimation_of_a_value (node, known_csts, known_contexts, - known_aggs, - removable_params_cost, 0, val); + avals.m_known_contexts[i] = val->value; + perform_estimation_of_a_value (node, &avals, removable_params_cost, + 0, val); if (dump_file && (dump_flags & TDF_DETAILS)) { @@ -3594,20 +3588,18 @@ estimate_local_effects (struct cgraph_node *node) val->local_time_benefit, val->local_size_cost); } } - known_contexts[i] = ipa_polymorphic_call_context (); + avals.m_known_contexts[i] = ipa_polymorphic_call_context (); } for (i = 0; i < count; i++) { class ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i); - struct ipa_agg_value_set *agg; - struct ipcp_agg_lattice *aglat; if (plats->aggs_bottom || !plats->aggs) continue; - agg = &known_aggs[i]; - for (aglat = plats->aggs; aglat; aglat = aglat->next) + ipa_agg_value_set *agg = &avals.m_known_aggs[i]; + for (ipcp_agg_lattice *aglat = plats->aggs; aglat; aglat = aglat->next) { ipcp_value<tree> *val; if (aglat->bottom || !aglat->values @@ -3624,8 +3616,7 @@ estimate_local_effects (struct cgraph_node *node) item.value = val->value; agg->items.safe_push (item); - perform_estimation_of_a_value (node, known_csts, known_contexts, - known_aggs, + perform_estimation_of_a_value (node, &avals, removable_params_cost, 0, val); if (dump_file && (dump_flags & TDF_DETAILS)) @@ -3645,10 +3636,6 @@ estimate_local_effects (struct cgraph_node *node) } } } - - known_csts.release (); - known_contexts.release (); - ipa_release_agg_values (known_aggs); } @@ -5372,31 +5359,34 @@ copy_useful_known_contexts (vec<ipa_polymorphic_call_context> known_contexts) return vNULL; } -/* Copy KNOWN_CSTS and modify the copy according to VAL and INDEX. If - non-empty, replace KNOWN_CONTEXTS with its copy too. */ +/* Copy known scalar values from AVALS into KNOWN_CSTS and modify the copy + according to VAL and INDEX. If non-empty, replace KNOWN_CONTEXTS with its + copy too. */ static void -modify_known_vectors_with_val (vec<tree> *known_csts, - vec<ipa_polymorphic_call_context> *known_contexts, - ipcp_value<tree> *val, - int index) +copy_known_vectors_add_val (ipa_auto_call_arg_values *avals, + vec<tree> *known_csts, + vec<ipa_polymorphic_call_context> *known_contexts, + ipcp_value<tree> *val, int index) { - *known_csts = known_csts->copy (); - *known_contexts = copy_useful_known_contexts (*known_contexts); + *known_csts = avals->m_known_vals.copy (); + *known_contexts = copy_useful_known_contexts (avals->m_known_contexts); (*known_csts)[index] = val->value; } -/* Replace KNOWN_CSTS with its copy. Also copy KNOWN_CONTEXTS and modify the - copy according to VAL and INDEX. */ +/* Copy known scalar values from AVALS into KNOWN_CSTS. Similarly, copy + contexts to KNOWN_CONTEXTS and modify the copy according to VAL and + INDEX. */ static void -modify_known_vectors_with_val (vec<tree> *known_csts, - vec<ipa_polymorphic_call_context> *known_contexts, - ipcp_value<ipa_polymorphic_call_context> *val, - int index) -{ - *known_csts = known_csts->copy (); - *known_contexts = known_contexts->copy (); +copy_known_vectors_add_val (ipa_auto_call_arg_values *avals, + vec<tree> *known_csts, + vec<ipa_polymorphic_call_context> *known_contexts, + ipcp_value<ipa_polymorphic_call_context> *val, + int index) +{ + *known_csts = avals->m_known_vals.copy (); + *known_contexts = avals->m_known_contexts.copy (); (*known_contexts)[index] = val->value; } @@ -5433,16 +5423,15 @@ ipcp_val_agg_replacement_ok_p (ipa_agg_replacement_value *, return offset == -1; } -/* Decide whether to create a special version of NODE for value VAL of parameter - at the given INDEX. If OFFSET is -1, the value is for the parameter itself, - otherwise it is stored at the given OFFSET of the parameter. KNOWN_CSTS, - KNOWN_CONTEXTS and KNOWN_AGGS describe the other already known values. */ +/* Decide whether to create a special version of NODE for value VAL of + parameter at the given INDEX. If OFFSET is -1, the value is for the + parameter itself, otherwise it is stored at the given OFFSET of the + parameter. AVALS describes the other already known values. */ template <typename valtype> static bool decide_about_value (struct cgraph_node *node, int index, HOST_WIDE_INT offset, - ipcp_value<valtype> *val, vec<tree> known_csts, - vec<ipa_polymorphic_call_context> known_contexts) + ipcp_value<valtype> *val, ipa_auto_call_arg_values *avals) { struct ipa_agg_replacement_value *aggvals; int freq_sum, caller_count; @@ -5492,13 +5481,16 @@ decide_about_value (struct cgraph_node *node, int index, HOST_WIDE_INT offset, fprintf (dump_file, " Creating a specialized node of %s.\n", node->dump_name ()); + vec<tree> known_csts; + vec<ipa_polymorphic_call_context> known_contexts; + callers = gather_edges_for_value (val, node, caller_count); if (offset == -1) - modify_known_vectors_with_val (&known_csts, &known_contexts, val, index); + copy_known_vectors_add_val (avals, &known_csts, &known_contexts, val, index); else { - known_csts = known_csts.copy (); - known_contexts = copy_useful_known_contexts (known_contexts); + known_csts = avals->m_known_vals.copy (); + known_contexts = copy_useful_known_contexts (avals->m_known_contexts); } find_more_scalar_values_for_callers_subset (node, known_csts, callers); find_more_contexts_for_caller_subset (node, &known_contexts, callers); @@ -5522,8 +5514,6 @@ decide_whether_version_node (struct cgraph_node *node) { class ipa_node_params *info = IPA_NODE_REF (node); int i, count = ipa_get_param_count (info); - vec<tree> known_csts; - vec<ipa_polymorphic_call_context> known_contexts; bool ret = false; if (count == 0) @@ -5533,8 +5523,8 @@ decide_whether_version_node (struct cgraph_node *node) fprintf (dump_file, "\nEvaluating opportunities for %s.\n", node->dump_name ()); - gather_context_independent_values (info, &known_csts, &known_contexts, - NULL, NULL); + ipa_auto_call_arg_values avals; + gather_context_independent_values (info, &avals, false, NULL); for (i = 0; i < count;i++) { @@ -5543,12 +5533,11 @@ decide_whether_version_node (struct cgraph_node *node) ipcp_lattice<ipa_polymorphic_call_context> *ctxlat = &plats->ctxlat; if (!lat->bottom - && !known_csts[i]) + && !avals.m_known_vals[i]) { ipcp_value<tree> *val; for (val = lat->values; val; val = val->next) - ret |= decide_about_value (node, i, -1, val, known_csts, - known_contexts); + ret |= decide_about_value (node, i, -1, val, &avals); } if (!plats->aggs_bottom) @@ -5557,22 +5546,20 @@ decide_whether_version_node (struct cgraph_node *node) ipcp_value<tree> *val; for (aglat = plats->aggs; aglat; aglat = aglat->next) if (!aglat->bottom && aglat->values - /* If the following is false, the one value is in - known_aggs. */ + /* If the following is false, the one value has been considered + for cloning for all contexts. */ && (plats->aggs_contain_variable || !aglat->is_single_const ())) for (val = aglat->values; val; val = val->next) - ret |= decide_about_value (node, i, aglat->offset, val, - known_csts, known_contexts); + ret |= decide_about_value (node, i, aglat->offset, val, &avals); } if (!ctxlat->bottom - && known_contexts[i].useless_p ()) + && avals.m_known_contexts[i].useless_p ()) { ipcp_value<ipa_polymorphic_call_context> *val; for (val = ctxlat->values; val; val = val->next) - ret |= decide_about_value (node, i, -1, val, known_csts, - known_contexts); + ret |= decide_about_value (node, i, -1, val, &avals); } info = IPA_NODE_REF (node); @@ -5595,11 +5582,9 @@ decide_whether_version_node (struct cgraph_node *node) if (!adjust_callers_for_value_intersection (callers, node)) { /* If node is not called by anyone, or all its caller edges are - self-recursive, the node is not really be in use, no need to - do cloning. */ + self-recursive, the node is not really in use, no need to do + cloning. */ callers.release (); - known_csts.release (); - known_contexts.release (); info->do_clone_for_all_contexts = false; return ret; } @@ -5608,6 +5593,9 @@ decide_whether_version_node (struct cgraph_node *node) fprintf (dump_file, " - Creating a specialized node of %s " "for all known contexts.\n", node->dump_name ()); + vec<tree> known_csts = avals.m_known_vals.copy (); + vec<ipa_polymorphic_call_context> known_contexts + = copy_useful_known_contexts (avals.m_known_contexts); find_more_scalar_values_for_callers_subset (node, known_csts, callers); find_more_contexts_for_caller_subset (node, &known_contexts, callers); ipa_agg_replacement_value *aggvals @@ -5625,11 +5613,6 @@ decide_whether_version_node (struct cgraph_node *node) IPA_NODE_REF (clone)->is_all_contexts_clone = true; ret = true; } - else - { - known_csts.release (); - known_contexts.release (); - } return ret; } diff --git a/gcc/ipa-fnsummary.c b/gcc/ipa-fnsummary.c index 8285cc0..b525cfd 100644 --- a/gcc/ipa-fnsummary.c +++ b/gcc/ipa-fnsummary.c @@ -320,19 +320,18 @@ set_hint_predicate (predicate **p, predicate new_predicate) is always false in the second and also builtin_constant_p tests cannot use the fact that parameter is indeed a constant. - KNOWN_VALS is partial mapping of parameters of NODE to constant values. - KNOWN_AGGS is a vector of aggregate known offset/value set for each - parameter. Return clause of possible truths. When INLINE_P is true, assume - that we are inlining. + When INLINE_P is true, assume that we are inlining. AVAL contains known + information about argument values. The function does not modify its content + and so AVALs could also be of type ipa_call_arg_values but so far all + callers work with the auto version and so we avoid the conversion for + convenience. - ERROR_MARK means compile time invariant. */ + ERROR_MARK value of an argument means compile time invariant. */ static void evaluate_conditions_for_known_args (struct cgraph_node *node, bool inline_p, - vec<tree> known_vals, - vec<value_range> known_value_ranges, - vec<ipa_agg_value_set> known_aggs, + ipa_auto_call_arg_values *avals, clause_t *ret_clause, clause_t *ret_nonspec_clause) { @@ -351,38 +350,33 @@ evaluate_conditions_for_known_args (struct cgraph_node *node, /* We allow call stmt to have fewer arguments than the callee function (especially for K&R style programs). So bound check here (we assume - known_aggs vector, if non-NULL, has the same length as - known_vals). */ - gcc_checking_assert (!known_aggs.length () || !known_vals.length () - || (known_vals.length () == known_aggs.length ())); + m_known_aggs vector is either empty or has the same length as + m_known_vals). */ + gcc_checking_assert (!avals->m_known_aggs.length () + || !avals->m_known_vals.length () + || (avals->m_known_vals.length () + == avals->m_known_aggs.length ())); if (c->agg_contents) { - struct ipa_agg_value_set *agg; - if (c->code == predicate::changed && !c->by_ref - && c->operand_num < (int)known_vals.length () - && (known_vals[c->operand_num] == error_mark_node)) + && (avals->safe_sval_at(c->operand_num) == error_mark_node)) continue; - if (c->operand_num < (int)known_aggs.length ()) + if (ipa_agg_value_set *agg = avals->safe_aggval_at (c->operand_num)) { - agg = &known_aggs[c->operand_num]; - val = ipa_find_agg_cst_for_param (agg, - c->operand_num - < (int) known_vals.length () - ? known_vals[c->operand_num] - : NULL, - c->offset, c->by_ref); + tree sval = avals->safe_sval_at (c->operand_num); + val = ipa_find_agg_cst_for_param (agg, sval, c->offset, + c->by_ref); } else val = NULL_TREE; } - else if (c->operand_num < (int) known_vals.length ()) + else { - val = known_vals[c->operand_num]; - if (val == error_mark_node && c->code != predicate::changed) + val = avals->safe_sval_at (c->operand_num); + if (val && val == error_mark_node && c->code != predicate::changed) val = NULL_TREE; } @@ -446,53 +440,54 @@ evaluate_conditions_for_known_args (struct cgraph_node *node, continue; } } - if (c->operand_num < (int) known_value_ranges.length () + if (c->operand_num < (int) avals->m_known_value_ranges.length () && !c->agg_contents - && !known_value_ranges[c->operand_num].undefined_p () - && !known_value_ranges[c->operand_num].varying_p () - && TYPE_SIZE (c->type) - == TYPE_SIZE (known_value_ranges[c->operand_num].type ()) && (!val || TREE_CODE (val) != INTEGER_CST)) { - value_range vr = known_value_ranges[c->operand_num]; - if (!useless_type_conversion_p (c->type, vr.type ())) + value_range vr = avals->m_known_value_ranges[c->operand_num]; + if (!vr.undefined_p () + && !vr.varying_p () + && (TYPE_SIZE (c->type) == TYPE_SIZE (vr.type ()))) { - value_range res; - range_fold_unary_expr (&res, NOP_EXPR, + if (!useless_type_conversion_p (c->type, vr.type ())) + { + value_range res; + range_fold_unary_expr (&res, NOP_EXPR, c->type, &vr, vr.type ()); - vr = res; - } - tree type = c->type; + vr = res; + } + tree type = c->type; - for (j = 0; vec_safe_iterate (c->param_ops, j, &op); j++) - { - if (vr.varying_p () || vr.undefined_p ()) - break; + for (j = 0; vec_safe_iterate (c->param_ops, j, &op); j++) + { + if (vr.varying_p () || vr.undefined_p ()) + break; - value_range res; - if (!op->val[0]) - range_fold_unary_expr (&res, op->code, op->type, &vr, type); - else if (!op->val[1]) + value_range res; + if (!op->val[0]) + range_fold_unary_expr (&res, op->code, op->type, &vr, type); + else if (!op->val[1]) + { + value_range op0 (op->val[0], op->val[0]); + range_fold_binary_expr (&res, op->code, op->type, + op->index ? &op0 : &vr, + op->index ? &vr : &op0); + } + else + gcc_unreachable (); + type = op->type; + vr = res; + } + if (!vr.varying_p () && !vr.undefined_p ()) { - value_range op0 (op->val[0], op->val[0]); - range_fold_binary_expr (&res, op->code, op->type, - op->index ? &op0 : &vr, - op->index ? &vr : &op0); + value_range res; + value_range val_vr (c->val, c->val); + range_fold_binary_expr (&res, c->code, boolean_type_node, + &vr, + &val_vr); + if (res.zero_p ()) + continue; } - else - gcc_unreachable (); - type = op->type; - vr = res; - } - if (!vr.varying_p () && !vr.undefined_p ()) - { - value_range res; - value_range val_vr (c->val, c->val); - range_fold_binary_expr (&res, c->code, boolean_type_node, - &vr, - &val_vr); - if (res.zero_p ()) - continue; } } @@ -538,24 +533,20 @@ fre_will_run_p (struct cgraph_node *node) (if non-NULL) conditions evaluated for nonspecialized clone called in a given context. - KNOWN_VALS_PTR and KNOWN_AGGS_PTR must be non-NULL and will be filled by - known constant and aggregate values of parameters. - - KNOWN_CONTEXT_PTR, if non-NULL, will be filled by polymorphic call contexts - of parameter used by a polymorphic call. */ + Vectors in AVALS will be populated with useful known information about + argument values - information not known to have any uses will be omitted - + except for m_known_contexts which will only be calculated if + COMPUTE_CONTEXTS is true. */ void evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p, clause_t *clause_ptr, clause_t *nonspec_clause_ptr, - vec<tree> *known_vals_ptr, - vec<ipa_polymorphic_call_context> - *known_contexts_ptr, - vec<ipa_agg_value_set> *known_aggs_ptr) + ipa_auto_call_arg_values *avals, + bool compute_contexts) { struct cgraph_node *callee = e->callee->ultimate_alias_target (); class ipa_fn_summary *info = ipa_fn_summaries->get (callee); - auto_vec<value_range, 32> known_value_ranges; class ipa_edge_args *args; if (clause_ptr) @@ -563,7 +554,7 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p, if (ipa_node_params_sum && !e->call_stmt_cannot_inline_p - && (info->conds || known_contexts_ptr) + && (info->conds || compute_contexts) && (args = IPA_EDGE_REF (e)) != NULL) { struct cgraph_node *caller; @@ -608,15 +599,15 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p, if (cst) { gcc_checking_assert (TREE_CODE (cst) != TREE_BINFO); - if (!known_vals_ptr->length ()) - vec_safe_grow_cleared (known_vals_ptr, count, true); - (*known_vals_ptr)[i] = cst; + if (!avals->m_known_vals.length ()) + avals->m_known_vals.safe_grow_cleared (count, true); + avals->m_known_vals[i] = cst; } else if (inline_p && !es->param[i].change_prob) { - if (!known_vals_ptr->length ()) - vec_safe_grow_cleared (known_vals_ptr, count, true); - (*known_vals_ptr)[i] = error_mark_node; + if (!avals->m_known_vals.length ()) + avals->m_known_vals.safe_grow_cleared (count, true); + avals->m_known_vals[i] = error_mark_node; } /* If we failed to get simple constant, try value range. */ @@ -624,19 +615,20 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p, && vrp_will_run_p (caller) && ipa_is_param_used_by_ipa_predicates (callee_pi, i)) { - value_range vr + value_range vr = ipa_value_range_from_jfunc (caller_parms_info, e, jf, ipa_get_type (callee_pi, i)); if (!vr.undefined_p () && !vr.varying_p ()) { - if (!known_value_ranges.length ()) + if (!avals->m_known_value_ranges.length ()) { - known_value_ranges.safe_grow (count, true); + avals->m_known_value_ranges.safe_grow (count, true); for (int i = 0; i < count; ++i) - new (&known_value_ranges[i]) value_range (); + new (&avals->m_known_value_ranges[i]) + value_range (); } - known_value_ranges[i] = vr; + avals->m_known_value_ranges[i] = vr; } } @@ -648,25 +640,25 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p, caller, &jf->agg); if (agg.items.length ()) { - if (!known_aggs_ptr->length ()) - vec_safe_grow_cleared (known_aggs_ptr, count, true); - (*known_aggs_ptr)[i] = agg; + if (!avals->m_known_aggs.length ()) + avals->m_known_aggs.safe_grow_cleared (count, true); + avals->m_known_aggs[i] = agg; } } } /* For calls used in polymorphic calls we further determine polymorphic call context. */ - if (known_contexts_ptr + if (compute_contexts && ipa_is_param_used_by_polymorphic_call (callee_pi, i)) { ipa_polymorphic_call_context ctx = ipa_context_from_jfunc (caller_parms_info, e, i, jf); if (!ctx.useless_p ()) { - if (!known_contexts_ptr->length ()) - known_contexts_ptr->safe_grow_cleared (count, true); - (*known_contexts_ptr)[i] + if (!avals->m_known_contexts.length ()) + avals->m_known_contexts.safe_grow_cleared (count, true); + avals->m_known_contexts[i] = ipa_context_from_jfunc (caller_parms_info, e, i, jf); } } @@ -685,18 +677,14 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p, cst = NULL; if (cst) { - if (!known_vals_ptr->length ()) - vec_safe_grow_cleared (known_vals_ptr, count, true); - (*known_vals_ptr)[i] = cst; + if (!avals->m_known_vals.length ()) + avals->m_known_vals.safe_grow_cleared (count, true); + avals->m_known_vals[i] = cst; } } } - evaluate_conditions_for_known_args (callee, inline_p, - *known_vals_ptr, - known_value_ranges, - *known_aggs_ptr, - clause_ptr, + evaluate_conditions_for_known_args (callee, inline_p, avals, clause_ptr, nonspec_clause_ptr); } @@ -781,7 +769,7 @@ ipa_fn_summary_t::duplicate (cgraph_node *src, vec<size_time_entry, va_gc> *entry = info->size_time_table; /* Use SRC parm info since it may not be copied yet. */ class ipa_node_params *parms_info = IPA_NODE_REF (src); - vec<tree> known_vals = vNULL; + ipa_auto_call_arg_values avals; int count = ipa_get_param_count (parms_info); int i, j; clause_t possible_truths; @@ -792,7 +780,7 @@ ipa_fn_summary_t::duplicate (cgraph_node *src, struct cgraph_edge *edge, *next; info->size_time_table = 0; - known_vals.safe_grow_cleared (count, true); + avals.m_known_vals.safe_grow_cleared (count, true); for (i = 0; i < count; i++) { struct ipa_replace_map *r; @@ -801,20 +789,17 @@ ipa_fn_summary_t::duplicate (cgraph_node *src, { if (r->parm_num == i) { - known_vals[i] = r->new_tree; + avals.m_known_vals[i] = r->new_tree; break; } } } evaluate_conditions_for_known_args (dst, false, - known_vals, - vNULL, - vNULL, + &avals, &possible_truths, /* We are going to specialize, so ignore nonspec truths. */ NULL); - known_vals.release (); info->account_size_time (0, 0, true_pred, true_pred); @@ -3054,15 +3039,14 @@ compute_fn_summary_for_current (void) return 0; } -/* Estimate benefit devirtualizing indirect edge IE, provided KNOWN_VALS, - KNOWN_CONTEXTS and KNOWN_AGGS. */ +/* Estimate benefit devirtualizing indirect edge IE and return true if it can + be devirtualized and inlined, provided m_known_vals, m_known_contexts and + m_known_aggs in AVALS. Return false straight away if AVALS is NULL. */ static bool estimate_edge_devirt_benefit (struct cgraph_edge *ie, int *size, int *time, - vec<tree> known_vals, - vec<ipa_polymorphic_call_context> known_contexts, - vec<ipa_agg_value_set> known_aggs) + ipa_call_arg_values *avals) { tree target; struct cgraph_node *callee; @@ -3070,13 +3054,13 @@ estimate_edge_devirt_benefit (struct cgraph_edge *ie, enum availability avail; bool speculative; - if (!known_vals.length () && !known_contexts.length ()) + if (!avals + || (!avals->m_known_vals.length() && !avals->m_known_contexts.length ())) return false; if (!opt_for_fn (ie->caller->decl, flag_indirect_inlining)) return false; - target = ipa_get_indirect_edge_target (ie, known_vals, known_contexts, - known_aggs, &speculative); + target = ipa_get_indirect_edge_target (ie, avals, &speculative); if (!target || speculative) return false; @@ -3100,17 +3084,13 @@ estimate_edge_devirt_benefit (struct cgraph_edge *ie, } /* Increase SIZE, MIN_SIZE (if non-NULL) and TIME for size and time needed to - handle edge E with probability PROB. - Set HINTS if edge may be devirtualized. - KNOWN_VALS, KNOWN_AGGS and KNOWN_CONTEXTS describe context of the call - site. */ + handle edge E with probability PROB. Set HINTS accordingly if edge may be + devirtualized. AVALS, if non-NULL, describes the context of the call site + as far as values of parameters are concerened. */ static inline void estimate_edge_size_and_time (struct cgraph_edge *e, int *size, int *min_size, - sreal *time, - vec<tree> known_vals, - vec<ipa_polymorphic_call_context> known_contexts, - vec<ipa_agg_value_set> known_aggs, + sreal *time, ipa_call_arg_values *avals, ipa_hints *hints) { class ipa_call_summary *es = ipa_call_summaries->get (e); @@ -3119,8 +3099,7 @@ estimate_edge_size_and_time (struct cgraph_edge *e, int *size, int *min_size, int cur_size; if (!e->callee && hints && e->maybe_hot_p () - && estimate_edge_devirt_benefit (e, &call_size, &call_time, - known_vals, known_contexts, known_aggs)) + && estimate_edge_devirt_benefit (e, &call_size, &call_time, avals)) *hints |= INLINE_HINT_indirect_call; cur_size = call_size * ipa_fn_summary::size_scale; *size += cur_size; @@ -3132,9 +3111,9 @@ estimate_edge_size_and_time (struct cgraph_edge *e, int *size, int *min_size, /* Increase SIZE, MIN_SIZE and TIME for size and time needed to handle all - calls in NODE. POSSIBLE_TRUTHS, KNOWN_VALS, KNOWN_AGGS and KNOWN_CONTEXTS - describe context of the call site. - + calls in NODE. POSSIBLE_TRUTHS and AVALS describe the context of the call + site. + Helper for estimate_calls_size_and_time which does the same but (in most cases) faster. */ @@ -3143,9 +3122,7 @@ estimate_calls_size_and_time_1 (struct cgraph_node *node, int *size, int *min_size, sreal *time, ipa_hints *hints, clause_t possible_truths, - vec<tree> known_vals, - vec<ipa_polymorphic_call_context> known_contexts, - vec<ipa_agg_value_set> known_aggs) + ipa_call_arg_values *avals) { struct cgraph_edge *e; for (e = node->callees; e; e = e->next_callee) @@ -3154,10 +3131,8 @@ estimate_calls_size_and_time_1 (struct cgraph_node *node, int *size, { gcc_checking_assert (!ipa_call_summaries->get (e)); estimate_calls_size_and_time_1 (e->callee, size, min_size, time, - hints, - possible_truths, - known_vals, known_contexts, - known_aggs); + hints, possible_truths, avals); + continue; } class ipa_call_summary *es = ipa_call_summaries->get (e); @@ -3175,9 +3150,7 @@ estimate_calls_size_and_time_1 (struct cgraph_node *node, int *size, so we do not need to compute probabilities. */ estimate_edge_size_and_time (e, size, es->predicate ? NULL : min_size, - time, - known_vals, known_contexts, - known_aggs, hints); + time, avals, hints); } } for (e = node->indirect_calls; e; e = e->next_callee) @@ -3187,9 +3160,7 @@ estimate_calls_size_and_time_1 (struct cgraph_node *node, int *size, || es->predicate->evaluate (possible_truths)) estimate_edge_size_and_time (e, size, es->predicate ? NULL : min_size, - time, - known_vals, known_contexts, known_aggs, - hints); + time, avals, hints); } } @@ -3211,8 +3182,7 @@ summarize_calls_size_and_time (struct cgraph_node *node, int size = 0; sreal time = 0; - estimate_edge_size_and_time (e, &size, NULL, &time, - vNULL, vNULL, vNULL, NULL); + estimate_edge_size_and_time (e, &size, NULL, &time, NULL, NULL); struct predicate pred = true; class ipa_call_summary *es = ipa_call_summaries->get (e); @@ -3226,8 +3196,7 @@ summarize_calls_size_and_time (struct cgraph_node *node, int size = 0; sreal time = 0; - estimate_edge_size_and_time (e, &size, NULL, &time, - vNULL, vNULL, vNULL, NULL); + estimate_edge_size_and_time (e, &size, NULL, &time, NULL, NULL); struct predicate pred = true; class ipa_call_summary *es = ipa_call_summaries->get (e); @@ -3238,17 +3207,15 @@ summarize_calls_size_and_time (struct cgraph_node *node, } /* Increase SIZE, MIN_SIZE and TIME for size and time needed to handle all - calls in NODE. POSSIBLE_TRUTHS, KNOWN_VALS, KNOWN_AGGS and KNOWN_CONTEXTS - describe context of the call site. */ + calls in NODE. POSSIBLE_TRUTHS and AVALS (the latter if non-NULL) describe + context of the call site. */ static void estimate_calls_size_and_time (struct cgraph_node *node, int *size, int *min_size, sreal *time, ipa_hints *hints, clause_t possible_truths, - vec<tree> known_vals, - vec<ipa_polymorphic_call_context> known_contexts, - vec<ipa_agg_value_set> known_aggs) + ipa_call_arg_values *avals) { class ipa_fn_summary *sum = ipa_fn_summaries->get (node); bool use_table = true; @@ -3267,9 +3234,10 @@ estimate_calls_size_and_time (struct cgraph_node *node, int *size, use_table = false; /* If there is an indirect edge that may be optimized, we need to go the slow way. */ - else if ((known_vals.length () - || known_contexts.length () - || known_aggs.length ()) && hints) + else if (avals && hints + && (avals->m_known_vals.length () + || avals->m_known_contexts.length () + || avals->m_known_aggs.length ())) { class ipa_node_params *params_summary = IPA_NODE_REF (node); unsigned int nargs = params_summary @@ -3278,13 +3246,13 @@ estimate_calls_size_and_time (struct cgraph_node *node, int *size, for (unsigned int i = 0; i < nargs && use_table; i++) { if (ipa_is_param_used_by_indirect_call (params_summary, i) - && ((known_vals.length () > i && known_vals[i]) - || (known_aggs.length () > i - && known_aggs[i].items.length ()))) + && (avals->safe_sval_at (i) + || (avals->m_known_aggs.length () > i + && avals->m_known_aggs[i].items.length ()))) use_table = false; else if (ipa_is_param_used_by_polymorphic_call (params_summary, i) - && (known_contexts.length () > i - && !known_contexts[i].useless_p ())) + && (avals->m_known_contexts.length () > i + && !avals->m_known_contexts[i].useless_p ())) use_table = false; } } @@ -3327,8 +3295,7 @@ estimate_calls_size_and_time (struct cgraph_node *node, int *size, < ipa_fn_summary::max_size_time_table_size) { estimate_calls_size_and_time_1 (node, &old_size, NULL, &old_time, NULL, - possible_truths, known_vals, - known_contexts, known_aggs); + possible_truths, avals); gcc_assert (*size == old_size); if (time && (*time - old_time > 1 || *time - old_time < -1) && dump_file) @@ -3340,31 +3307,22 @@ estimate_calls_size_and_time (struct cgraph_node *node, int *size, /* Slow path by walking all edges. */ else estimate_calls_size_and_time_1 (node, size, min_size, time, hints, - possible_truths, known_vals, known_contexts, - known_aggs); + possible_truths, avals); } -/* Default constructor for ipa call context. - Memory allocation of known_vals, known_contexts - and known_aggs vectors is owned by the caller, but can - be release by ipa_call_context::release. - - inline_param_summary is owned by the caller. */ -ipa_call_context::ipa_call_context (cgraph_node *node, - clause_t possible_truths, +/* Main constructor for ipa call context. Memory allocation of ARG_VALUES + is owned by the caller. INLINE_PARAM_SUMMARY is also owned by the + caller. */ + +ipa_call_context::ipa_call_context (cgraph_node *node, clause_t possible_truths, clause_t nonspec_possible_truths, - vec<tree> known_vals, - vec<ipa_polymorphic_call_context> - known_contexts, - vec<ipa_agg_value_set> known_aggs, vec<inline_param_summary> - inline_param_summary) + inline_param_summary, + ipa_auto_call_arg_values *arg_values) : m_node (node), m_possible_truths (possible_truths), m_nonspec_possible_truths (nonspec_possible_truths), m_inline_param_summary (inline_param_summary), - m_known_vals (known_vals), - m_known_contexts (known_contexts), - m_known_aggs (known_aggs) + m_avals (arg_values) { } @@ -3395,47 +3353,50 @@ ipa_call_context::duplicate_from (const ipa_call_context &ctx) break; } } - m_known_vals = vNULL; - if (ctx.m_known_vals.exists ()) + m_avals.m_known_vals = vNULL; + if (ctx.m_avals.m_known_vals.exists ()) { - unsigned int n = MIN (ctx.m_known_vals.length (), nargs); + unsigned int n = MIN (ctx.m_avals.m_known_vals.length (), nargs); for (unsigned int i = 0; i < n; i++) if (ipa_is_param_used_by_indirect_call (params_summary, i) - && ctx.m_known_vals[i]) + && ctx.m_avals.m_known_vals[i]) { - m_known_vals = ctx.m_known_vals.copy (); + m_avals.m_known_vals = ctx.m_avals.m_known_vals.copy (); break; } } - m_known_contexts = vNULL; - if (ctx.m_known_contexts.exists ()) + m_avals.m_known_contexts = vNULL; + if (ctx.m_avals.m_known_contexts.exists ()) { - unsigned int n = MIN (ctx.m_known_contexts.length (), nargs); + unsigned int n = MIN (ctx.m_avals.m_known_contexts.length (), nargs); for (unsigned int i = 0; i < n; i++) if (ipa_is_param_used_by_polymorphic_call (params_summary, i) - && !ctx.m_known_contexts[i].useless_p ()) + && !ctx.m_avals.m_known_contexts[i].useless_p ()) { - m_known_contexts = ctx.m_known_contexts.copy (); + m_avals.m_known_contexts = ctx.m_avals.m_known_contexts.copy (); break; } } - m_known_aggs = vNULL; - if (ctx.m_known_aggs.exists ()) + m_avals.m_known_aggs = vNULL; + if (ctx.m_avals.m_known_aggs.exists ()) { - unsigned int n = MIN (ctx.m_known_aggs.length (), nargs); + unsigned int n = MIN (ctx.m_avals.m_known_aggs.length (), nargs); for (unsigned int i = 0; i < n; i++) if (ipa_is_param_used_by_indirect_call (params_summary, i) - && !ctx.m_known_aggs[i].is_empty ()) + && !ctx.m_avals.m_known_aggs[i].is_empty ()) { - m_known_aggs = ipa_copy_agg_values (ctx.m_known_aggs); + m_avals.m_known_aggs + = ipa_copy_agg_values (ctx.m_avals.m_known_aggs); break; } } + + m_avals.m_known_value_ranges = vNULL; } /* Release memory used by known_vals/contexts/aggs vectors. @@ -3449,11 +3410,11 @@ ipa_call_context::release (bool all) /* See if context is initialized at first place. */ if (!m_node) return; - ipa_release_agg_values (m_known_aggs, all); + ipa_release_agg_values (m_avals.m_known_aggs, all); if (all) { - m_known_vals.release (); - m_known_contexts.release (); + m_avals.m_known_vals.release (); + m_avals.m_known_contexts.release (); m_inline_param_summary.release (); } } @@ -3499,77 +3460,81 @@ ipa_call_context::equal_to (const ipa_call_context &ctx) return false; } } - if (m_known_vals.exists () || ctx.m_known_vals.exists ()) + if (m_avals.m_known_vals.exists () || ctx.m_avals.m_known_vals.exists ()) { for (unsigned int i = 0; i < nargs; i++) { if (!ipa_is_param_used_by_indirect_call (params_summary, i)) continue; - if (i >= m_known_vals.length () || !m_known_vals[i]) + if (i >= m_avals.m_known_vals.length () || !m_avals.m_known_vals[i]) { - if (i < ctx.m_known_vals.length () && ctx.m_known_vals[i]) + if (i < ctx.m_avals.m_known_vals.length () + && ctx.m_avals.m_known_vals[i]) return false; continue; } - if (i >= ctx.m_known_vals.length () || !ctx.m_known_vals[i]) + if (i >= ctx.m_avals.m_known_vals.length () + || !ctx.m_avals.m_known_vals[i]) { - if (i < m_known_vals.length () && m_known_vals[i]) + if (i < m_avals.m_known_vals.length () && m_avals.m_known_vals[i]) return false; continue; } - if (m_known_vals[i] != ctx.m_known_vals[i]) + if (m_avals.m_known_vals[i] != ctx.m_avals.m_known_vals[i]) return false; } } - if (m_known_contexts.exists () || ctx.m_known_contexts.exists ()) + if (m_avals.m_known_contexts.exists () + || ctx.m_avals.m_known_contexts.exists ()) { for (unsigned int i = 0; i < nargs; i++) { if (!ipa_is_param_used_by_polymorphic_call (params_summary, i)) continue; - if (i >= m_known_contexts.length () - || m_known_contexts[i].useless_p ()) + if (i >= m_avals.m_known_contexts.length () + || m_avals.m_known_contexts[i].useless_p ()) { - if (i < ctx.m_known_contexts.length () - && !ctx.m_known_contexts[i].useless_p ()) + if (i < ctx.m_avals.m_known_contexts.length () + && !ctx.m_avals.m_known_contexts[i].useless_p ()) return false; continue; } - if (i >= ctx.m_known_contexts.length () - || ctx.m_known_contexts[i].useless_p ()) + if (i >= ctx.m_avals.m_known_contexts.length () + || ctx.m_avals.m_known_contexts[i].useless_p ()) { - if (i < m_known_contexts.length () - && !m_known_contexts[i].useless_p ()) + if (i < m_avals.m_known_contexts.length () + && !m_avals.m_known_contexts[i].useless_p ()) return false; continue; } - if (!m_known_contexts[i].equal_to - (ctx.m_known_contexts[i])) + if (!m_avals.m_known_contexts[i].equal_to + (ctx.m_avals.m_known_contexts[i])) return false; } } - if (m_known_aggs.exists () || ctx.m_known_aggs.exists ()) + if (m_avals.m_known_aggs.exists () || ctx.m_avals.m_known_aggs.exists ()) { for (unsigned int i = 0; i < nargs; i++) { if (!ipa_is_param_used_by_indirect_call (params_summary, i)) continue; - if (i >= m_known_aggs.length () || m_known_aggs[i].is_empty ()) + if (i >= m_avals.m_known_aggs.length () + || m_avals.m_known_aggs[i].is_empty ()) { - if (i < ctx.m_known_aggs.length () - && !ctx.m_known_aggs[i].is_empty ()) + if (i < ctx.m_avals.m_known_aggs.length () + && !ctx.m_avals.m_known_aggs[i].is_empty ()) return false; continue; } - if (i >= ctx.m_known_aggs.length () - || ctx.m_known_aggs[i].is_empty ()) + if (i >= ctx.m_avals.m_known_aggs.length () + || ctx.m_avals.m_known_aggs[i].is_empty ()) { - if (i < m_known_aggs.length () - && !m_known_aggs[i].is_empty ()) + if (i < m_avals.m_known_aggs.length () + && !m_avals.m_known_aggs[i].is_empty ()) return false; continue; } - if (!m_known_aggs[i].equal_to (ctx.m_known_aggs[i])) + if (!m_avals.m_known_aggs[i].equal_to (ctx.m_avals.m_known_aggs[i])) return false; } } @@ -3619,7 +3584,7 @@ ipa_call_context::estimate_size_and_time (int *ret_size, estimate_calls_size_and_time (m_node, &size, &min_size, ret_time ? &time : NULL, ret_hints ? &hints : NULL, m_possible_truths, - m_known_vals, m_known_contexts, m_known_aggs); + &m_avals); sreal nonspecialized_time = time; @@ -3726,22 +3691,16 @@ ipa_call_context::estimate_size_and_time (int *ret_size, void estimate_ipcp_clone_size_and_time (struct cgraph_node *node, - vec<tree> known_vals, - vec<ipa_polymorphic_call_context> - known_contexts, - vec<ipa_agg_value_set> known_aggs, + ipa_auto_call_arg_values *avals, int *ret_size, sreal *ret_time, sreal *ret_nonspec_time, ipa_hints *hints) { clause_t clause, nonspec_clause; - /* TODO: Also pass known value ranges. */ - evaluate_conditions_for_known_args (node, false, known_vals, vNULL, - known_aggs, &clause, &nonspec_clause); - ipa_call_context ctx (node, clause, nonspec_clause, - known_vals, known_contexts, - known_aggs, vNULL); + evaluate_conditions_for_known_args (node, false, avals, &clause, + &nonspec_clause); + ipa_call_context ctx (node, clause, nonspec_clause, vNULL, avals); ctx.estimate_size_and_time (ret_size, NULL, ret_time, ret_nonspec_time, hints); } @@ -3970,10 +3929,8 @@ ipa_merge_fn_summary_after_inlining (struct cgraph_edge *edge) if (callee_info->conds) { - auto_vec<tree, 32> known_vals; - auto_vec<ipa_agg_value_set, 32> known_aggs; - evaluate_properties_for_edge (edge, true, &clause, NULL, - &known_vals, NULL, &known_aggs); + ipa_auto_call_arg_values avals; + evaluate_properties_for_edge (edge, true, &clause, NULL, &avals, false); } if (ipa_node_params_sum && callee_info->conds) { @@ -4067,8 +4024,7 @@ ipa_merge_fn_summary_after_inlining (struct cgraph_edge *edge) int edge_size = 0; sreal edge_time = 0; - estimate_edge_size_and_time (edge, &edge_size, NULL, &edge_time, vNULL, - vNULL, vNULL, 0); + estimate_edge_size_and_time (edge, &edge_size, NULL, &edge_time, NULL, 0); /* Unaccount size and time of the optimized out call. */ info->account_size_time (-edge_size, -edge_time, es->predicate ? *es->predicate : true, @@ -4110,7 +4066,7 @@ ipa_update_overall_fn_summary (struct cgraph_node *node, bool reset) estimate_calls_size_and_time (node, &size_info->size, &info->min_size, &info->time, NULL, ~(clause_t) (1 << predicate::false_condition), - vNULL, vNULL, vNULL); + NULL); size_info->size = RDIV (size_info->size, ipa_fn_summary::size_scale); info->min_size = RDIV (info->min_size, ipa_fn_summary::size_scale); } diff --git a/gcc/ipa-fnsummary.h b/gcc/ipa-fnsummary.h index 4e1f841..6893858 100644 --- a/gcc/ipa-fnsummary.h +++ b/gcc/ipa-fnsummary.h @@ -297,10 +297,8 @@ public: ipa_call_context (cgraph_node *node, clause_t possible_truths, clause_t nonspec_possible_truths, - vec<tree> known_vals, - vec<ipa_polymorphic_call_context> known_contexts, - vec<ipa_agg_value_set> known_aggs, - vec<inline_param_summary> m_inline_param_summary); + vec<inline_param_summary> inline_param_summary, + ipa_auto_call_arg_values *arg_values); ipa_call_context () : m_node(NULL) { @@ -328,14 +326,9 @@ private: /* Inline summary maintains info about change probabilities. */ vec<inline_param_summary> m_inline_param_summary; - /* The following is used only to resolve indirect calls. */ - - /* Vector describing known values of parameters. */ - vec<tree> m_known_vals; - /* Vector describing known polymorphic call contexts. */ - vec<ipa_polymorphic_call_context> m_known_contexts; - /* Vector describing known aggregate values. */ - vec<ipa_agg_value_set> m_known_aggs; + /* Even after having calculated clauses, the information about argument + values is used to resolve indirect calls. */ + ipa_call_arg_values m_avals; }; extern fast_call_summary <ipa_call_summary *, va_heap> *ipa_call_summaries; @@ -349,9 +342,7 @@ void ipa_free_fn_summary (void); void ipa_free_size_summary (void); void inline_analyze_function (struct cgraph_node *node); void estimate_ipcp_clone_size_and_time (struct cgraph_node *, - vec<tree>, - vec<ipa_polymorphic_call_context>, - vec<ipa_agg_value_set>, + ipa_auto_call_arg_values *, int *, sreal *, sreal *, ipa_hints *); void ipa_merge_fn_summary_after_inlining (struct cgraph_edge *edge); @@ -365,10 +356,8 @@ void evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p, clause_t *clause_ptr, clause_t *nonspec_clause_ptr, - vec<tree> *known_vals_ptr, - vec<ipa_polymorphic_call_context> - *known_contexts_ptr, - vec<ipa_agg_value_set> *); + ipa_auto_call_arg_values *avals, + bool compute_contexts); void ipa_fnsummary_c_finalize (void); HOST_WIDE_INT ipa_get_stack_frame_offset (struct cgraph_node *node); diff --git a/gcc/ipa-inline-analysis.c b/gcc/ipa-inline-analysis.c index 148efbc..d2ae819 100644 --- a/gcc/ipa-inline-analysis.c +++ b/gcc/ipa-inline-analysis.c @@ -184,20 +184,16 @@ do_estimate_edge_time (struct cgraph_edge *edge, sreal *ret_nonspec_time) ipa_hints hints; struct cgraph_node *callee; clause_t clause, nonspec_clause; - auto_vec<tree, 32> known_vals; - auto_vec<ipa_polymorphic_call_context, 32> known_contexts; - auto_vec<ipa_agg_value_set, 32> known_aggs; + ipa_auto_call_arg_values avals; class ipa_call_summary *es = ipa_call_summaries->get (edge); int min_size = -1; callee = edge->callee->ultimate_alias_target (); gcc_checking_assert (edge->inline_failed); - evaluate_properties_for_edge (edge, true, - &clause, &nonspec_clause, &known_vals, - &known_contexts, &known_aggs); - ipa_call_context ctx (callee, clause, nonspec_clause, known_vals, - known_contexts, known_aggs, es->param); + evaluate_properties_for_edge (edge, true, &clause, &nonspec_clause, + &avals, true); + ipa_call_context ctx (callee, clause, nonspec_clause, es->param, &avals); if (node_context_cache != NULL) { node_context_summary *e = node_context_cache->get_create (callee); @@ -255,7 +251,6 @@ do_estimate_edge_time (struct cgraph_edge *edge, sreal *ret_nonspec_time) : edge->caller->count.ipa ()))) hints |= INLINE_HINT_known_hot; - ctx.release (); gcc_checking_assert (size >= 0); gcc_checking_assert (time >= 0); @@ -307,9 +302,6 @@ do_estimate_edge_size (struct cgraph_edge *edge) int size; struct cgraph_node *callee; clause_t clause, nonspec_clause; - auto_vec<tree, 32> known_vals; - auto_vec<ipa_polymorphic_call_context, 32> known_contexts; - auto_vec<ipa_agg_value_set, 32> known_aggs; /* When we do caching, use do_estimate_edge_time to populate the entry. */ @@ -325,14 +317,11 @@ do_estimate_edge_size (struct cgraph_edge *edge) /* Early inliner runs without caching, go ahead and do the dirty work. */ gcc_checking_assert (edge->inline_failed); - evaluate_properties_for_edge (edge, true, - &clause, &nonspec_clause, - &known_vals, &known_contexts, - &known_aggs); - ipa_call_context ctx (callee, clause, nonspec_clause, known_vals, - known_contexts, known_aggs, vNULL); + ipa_auto_call_arg_values avals; + evaluate_properties_for_edge (edge, true, &clause, &nonspec_clause, + &avals, true); + ipa_call_context ctx (callee, clause, nonspec_clause, vNULL, &avals); ctx.estimate_size_and_time (&size, NULL, NULL, NULL, NULL); - ctx.release (); return size; } @@ -346,9 +335,6 @@ do_estimate_edge_hints (struct cgraph_edge *edge) ipa_hints hints; struct cgraph_node *callee; clause_t clause, nonspec_clause; - auto_vec<tree, 32> known_vals; - auto_vec<ipa_polymorphic_call_context, 32> known_contexts; - auto_vec<ipa_agg_value_set, 32> known_aggs; /* When we do caching, use do_estimate_edge_time to populate the entry. */ @@ -364,14 +350,11 @@ do_estimate_edge_hints (struct cgraph_edge *edge) /* Early inliner runs without caching, go ahead and do the dirty work. */ gcc_checking_assert (edge->inline_failed); - evaluate_properties_for_edge (edge, true, - &clause, &nonspec_clause, - &known_vals, &known_contexts, - &known_aggs); - ipa_call_context ctx (callee, clause, nonspec_clause, known_vals, - known_contexts, known_aggs, vNULL); + ipa_auto_call_arg_values avals; + evaluate_properties_for_edge (edge, true, &clause, &nonspec_clause, + &avals, true); + ipa_call_context ctx (callee, clause, nonspec_clause, vNULL, &avals); ctx.estimate_size_and_time (NULL, NULL, NULL, NULL, &hints); - ctx.release (); hints |= simple_edge_hints (edge); return hints; } diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c index ea88fd3..dec6c73 100644 --- a/gcc/ipa-prop.c +++ b/gcc/ipa-prop.c @@ -5797,4 +5797,14 @@ ipa_agg_value::equal_to (const ipa_agg_value &other) return offset == other.offset && operand_equal_p (value, other.value, 0); } + +/* Destructor also removing individual aggregate values. */ + +ipa_auto_call_arg_values::~ipa_auto_call_arg_values () +{ + ipa_release_agg_values (m_known_aggs, false); +} + + + #include "gt-ipa-prop.h" diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h index 23fcf90..8b2edf6 100644 --- a/gcc/ipa-prop.h +++ b/gcc/ipa-prop.h @@ -433,6 +433,107 @@ ipa_get_jf_ancestor_type_preserved (struct ipa_jump_func *jfunc) return jfunc->value.ancestor.agg_preserved; } +/* Class for allocating a bundle of various potentially known properties about + actual arguments of a particular call on stack for the usual case and on + heap only if there are unusually many arguments. The data is deallocated + when the instance of this class goes out of scope or is otherwise + destructed. */ + +class ipa_auto_call_arg_values +{ +public: + ~ipa_auto_call_arg_values (); + + /* If m_known_vals (vector of known "scalar" values) is sufficiantly long, + return its element at INDEX, otherwise return NULL. */ + tree safe_sval_at (int index) + { + /* TODO: Assert non-negative index here and test. */ + if ((unsigned) index < m_known_vals.length ()) + return m_known_vals[index]; + return NULL; + } + + /* If m_known_aggs is sufficiantly long, return the pointer rto its element + at INDEX, otherwise return NULL. */ + ipa_agg_value_set *safe_aggval_at (int index) + { + /* TODO: Assert non-negative index here and test. */ + if ((unsigned) index < m_known_aggs.length ()) + return &m_known_aggs[index]; + return NULL; + } + + /* Vector describing known values of parameters. */ + auto_vec<tree, 32> m_known_vals; + + /* Vector describing known polymorphic call contexts. */ + auto_vec<ipa_polymorphic_call_context, 32> m_known_contexts; + + /* Vector describing known aggregate values. */ + auto_vec<ipa_agg_value_set, 32> m_known_aggs; + + /* Vector describing known value ranges of arguments. */ + auto_vec<value_range, 32> m_known_value_ranges; +}; + +/* Class bundling the various potentially known properties about actual + arguments of a particular call. This variant does not deallocate the + bundled data in any way. */ + +class ipa_call_arg_values +{ +public: + /* Default constructor, setting the vectors to empty ones. */ + ipa_call_arg_values () + {} + + /* Construct this general variant of the bundle from the variant which uses + auto_vecs to hold the vectors. This means that vectors of objects + constructed with this constructor should not be changed because if they + get reallocated, the member vectors and the underlying auto_vecs would get + out of sync. */ + ipa_call_arg_values (ipa_auto_call_arg_values *aavals) + : m_known_vals (aavals->m_known_vals), + m_known_contexts (aavals->m_known_contexts), + m_known_aggs (aavals->m_known_aggs), + m_known_value_ranges (aavals->m_known_value_ranges) + {} + + /* If m_known_vals (vector of known "scalar" values) is sufficiantly long, + return its element at INDEX, otherwise return NULL. */ + tree safe_sval_at (int index) + { + /* TODO: Assert non-negative index here and test. */ + if ((unsigned) index < m_known_vals.length ()) + return m_known_vals[index]; + return NULL; + } + + /* If m_known_aggs is sufficiantly long, return the pointer rto its element + at INDEX, otherwise return NULL. */ + ipa_agg_value_set *safe_aggval_at (int index) + { + /* TODO: Assert non-negative index here and test. */ + if ((unsigned) index < m_known_aggs.length ()) + return &m_known_aggs[index]; + return NULL; + } + + /* Vector describing known values of parameters. */ + vec<tree> m_known_vals = vNULL; + + /* Vector describing known polymorphic call contexts. */ + vec<ipa_polymorphic_call_context> m_known_contexts = vNULL; + + /* Vector describing known aggregate values. */ + vec<ipa_agg_value_set> m_known_aggs = vNULL; + + /* Vector describing known value ranges of arguments. */ + vec<value_range> m_known_value_ranges = vNULL; +}; + + /* Summary describing a single formal parameter. */ struct GTY(()) ipa_param_descriptor @@ -970,12 +1071,13 @@ void ipa_initialize_node_params (struct cgraph_node *node); bool ipa_propagate_indirect_call_infos (struct cgraph_edge *cs, vec<cgraph_edge *> *new_edges); -/* Indirect edge and binfo processing. */ +/* Indirect edge processing and target discovery. */ +tree ipa_get_indirect_edge_target (struct cgraph_edge *ie, + ipa_call_arg_values *avals, + bool *speculative); tree ipa_get_indirect_edge_target (struct cgraph_edge *ie, - vec<tree>, - vec<ipa_polymorphic_call_context>, - vec<ipa_agg_value_set>, - bool *); + ipa_auto_call_arg_values *avals, + bool *speculative); struct cgraph_edge *ipa_make_edge_direct_to_target (struct cgraph_edge *, tree, bool speculative = false); tree ipa_impossible_devirt_target (struct cgraph_edge *, tree); |