Mercurial > hg > CbC > CbC_gcc
diff gcc/ipa-cp.c @ 132:d34655255c78
update gcc-8.2
author | mir3636 |
---|---|
date | Thu, 25 Oct 2018 10:21:07 +0900 |
parents | 84e7813d76e9 |
children | 1830386684a0 |
line wrap: on
line diff
--- a/gcc/ipa-cp.c Thu Oct 25 08:08:40 2018 +0900 +++ b/gcc/ipa-cp.c Thu Oct 25 10:21:07 2018 +0900 @@ -1,5 +1,5 @@ /* Interprocedural constant propagation - Copyright (C) 2005-2017 Free Software Foundation, Inc. + Copyright (C) 2005-2018 Free Software Foundation, Inc. Contributed by Razya Ladelsky <RAZYA@il.ibm.com> and Martin Jambor <mjambor@suse.cz> @@ -314,7 +314,7 @@ inline bool set_to_bottom (); bool meet_with (const value_range *p_vr); bool meet_with (const ipcp_vr_lattice &other); - void init () { m_vr.type = VR_UNDEFINED; } + void init () { gcc_assert (m_vr.undefined_p ()); } void print (FILE * f); private: @@ -405,16 +405,6 @@ return &plats->ctxlat; } -/* Return the lattice corresponding to the value range of the Ith formal - parameter of the function described by INFO. */ - -static inline ipcp_vr_lattice * -ipa_get_vr_lat (struct ipa_node_params *info, int i) -{ - struct ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i); - return &plats->m_value_range; -} - /* Return whether LAT is a lattice with a single constant and without an undefined value. */ @@ -497,8 +487,8 @@ fprintf (f, " [from:"); for (s = val->sources; s; s = s->next) - fprintf (f, " %i(%i)", s->cs->caller->order, - s->cs->frequency); + fprintf (f, " %i(%f)", s->cs->caller->order, + s->cs->sreal_frequency ().to_double ()); fprintf (f, "]"); } @@ -630,6 +620,23 @@ reason = "calls comdat-local function"; } + /* Functions calling BUILT_IN_VA_ARG_PACK and BUILT_IN_VA_ARG_PACK_LEN + work only when inlined. Cloning them may still lead to better code + because ipa-cp will not give up on cloning further. If the function is + external this however leads to wrong code because we may end up producing + offline copy of the function. */ + if (DECL_EXTERNAL (node->decl)) + for (cgraph_edge *edge = node->callees; !reason && edge; + edge = edge->next_callee) + if (fndecl_built_in_p (edge->callee->decl, BUILT_IN_NORMAL)) + { + if (DECL_FUNCTION_CODE (edge->callee->decl) == BUILT_IN_VA_ARG_PACK) + reason = "external function which calls va_arg_pack"; + if (DECL_FUNCTION_CODE (edge->callee->decl) + == BUILT_IN_VA_ARG_PACK_LEN) + reason = "external function which calls va_arg_pack_len"; + } + if (reason && dump_file && !node->alias && !node->thunk.thunk_p) fprintf (dump_file, "Function %s is not versionable, reason: %s.\n", node->dump_name (), reason); @@ -677,9 +684,9 @@ for (cs = node->callers; cs; cs = cs->next_caller) if (!cs->caller->thunk.thunk_p) { - if (cs->count.initialized_p ()) - stats->count_sum += cs->count; - stats->freq_sum += cs->frequency; + if (cs->count.ipa ().initialized_p ()) + stats->count_sum += cs->count.ipa (); + stats->freq_sum += cs->frequency (); stats->n_calls++; if (cs->maybe_hot_p ()) stats->n_hot_calls ++; @@ -731,7 +738,7 @@ significantly. */ if (max_count > profile_count::zero ()) { - if (stats.count_sum > node->count.apply_scale (90, 100)) + if (stats.count_sum > node->count.ipa ().apply_scale (90, 100)) { if (dump_file) fprintf (dump_file, "Considering %s for cloning; " @@ -907,28 +914,21 @@ return meet_with_1 (p_vr); } -/* Meet the current value of the lattice with value ranfge described by - OTHER_VR lattice. */ +/* Meet the current value of the lattice with value range described by + OTHER_VR lattice. Return TRUE if anything changed. */ bool ipcp_vr_lattice::meet_with_1 (const value_range *other_vr) { - tree min = m_vr.min, max = m_vr.max; - value_range_type type = m_vr.type; - if (bottom_p ()) return false; - if (other_vr->type == VR_VARYING) + if (other_vr->varying_p ()) return set_to_bottom (); - vrp_meet (&m_vr, other_vr); - if (type != m_vr.type - || min != m_vr.min - || max != m_vr.max) - return true; - else - return false; + value_range save (m_vr); + m_vr.union_ (other_vr); + return !m_vr.ignore_equivs_equal_p (save); } /* Return true if value range information in the lattice is yet unknown. */ @@ -936,7 +936,7 @@ bool ipcp_vr_lattice::top_p () const { - return m_vr.type == VR_UNDEFINED; + return m_vr.undefined_p (); } /* Return true if value range information in the lattice is known to be @@ -945,7 +945,7 @@ bool ipcp_vr_lattice::bottom_p () const { - return m_vr.type == VR_VARYING; + return m_vr.varying_p (); } /* Set value range information in the lattice to bottom. Return true if it @@ -954,9 +954,9 @@ bool ipcp_vr_lattice::set_to_bottom () { - if (m_vr.type == VR_VARYING) + if (m_vr.varying_p ()) return false; - m_vr.type = VR_VARYING; + m_vr.set_varying (); return true; } @@ -1159,7 +1159,7 @@ int i; gcc_checking_assert (node->has_gimple_body_p ()); - if (cgraph_local_p (node)) + if (node->local.local) { int caller_count = 0; node->call_for_symbol_thunks_and_aliases (count_callers, &caller_count, @@ -1220,33 +1220,38 @@ } /* Return the result of a (possibly arithmetic) pass through jump function - JFUNC on the constant value INPUT. Return NULL_TREE if that cannot be + JFUNC on the constant value INPUT. RES_TYPE is the type of the parameter + to which the result is passed. Return NULL_TREE if that cannot be determined or be considered an interprocedural invariant. */ static tree -ipa_get_jf_pass_through_result (struct ipa_jump_func *jfunc, tree input) +ipa_get_jf_pass_through_result (struct ipa_jump_func *jfunc, tree input, + tree res_type) { - tree restype, res; + tree res; if (ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR) return input; if (!is_gimple_ip_invariant (input)) return NULL_TREE; - if (TREE_CODE_CLASS (ipa_get_jf_pass_through_operation (jfunc)) - == tcc_unary) - res = fold_unary (ipa_get_jf_pass_through_operation (jfunc), - TREE_TYPE (input), input); - else + tree_code opcode = ipa_get_jf_pass_through_operation (jfunc); + if (!res_type) { - if (TREE_CODE_CLASS (ipa_get_jf_pass_through_operation (jfunc)) - == tcc_comparison) - restype = boolean_type_node; + if (TREE_CODE_CLASS (opcode) == tcc_comparison) + res_type = boolean_type_node; + else if (expr_type_first_operand_type_p (opcode)) + res_type = TREE_TYPE (input); else - restype = TREE_TYPE (input); - res = fold_binary (ipa_get_jf_pass_through_operation (jfunc), restype, - input, ipa_get_jf_pass_through_operand (jfunc)); + return NULL_TREE; } + + if (TREE_CODE_CLASS (opcode) == tcc_unary) + res = fold_unary (opcode, res_type, input); + else + res = fold_binary (opcode, res_type, input, + ipa_get_jf_pass_through_operand (jfunc)); + if (res && !is_gimple_ip_invariant (res)) return NULL_TREE; @@ -1275,10 +1280,12 @@ /* Determine whether JFUNC evaluates to a single known constant value and if so, return it. Otherwise return NULL. INFO describes the caller node or the one it is inlined to, so that pass-through jump functions can be - evaluated. */ + evaluated. PARM_TYPE is the type of the parameter to which the result is + passed. */ tree -ipa_value_from_jfunc (struct ipa_node_params *info, struct ipa_jump_func *jfunc) +ipa_value_from_jfunc (struct ipa_node_params *info, struct ipa_jump_func *jfunc, + tree parm_type) { if (jfunc->type == IPA_JF_CONST) return ipa_get_jf_constant (jfunc); @@ -1312,7 +1319,7 @@ return NULL_TREE; if (jfunc->type == IPA_JF_PASS_THROUGH) - return ipa_get_jf_pass_through_result (jfunc, input); + return ipa_get_jf_pass_through_result (jfunc, input, parm_type); else return ipa_get_jf_ancestor_result (jfunc, input); } @@ -1562,26 +1569,31 @@ /* Propagate values through a pass-through jump function JFUNC associated with edge CS, taking values from SRC_LAT and putting them into DEST_LAT. SRC_IDX - is the index of the source parameter. */ + is the index of the source parameter. PARM_TYPE is the type of the + parameter to which the result is passed. */ static bool propagate_vals_across_pass_through (cgraph_edge *cs, ipa_jump_func *jfunc, ipcp_lattice<tree> *src_lat, - ipcp_lattice<tree> *dest_lat, int src_idx) + ipcp_lattice<tree> *dest_lat, int src_idx, + tree parm_type) { ipcp_value<tree> *src_val; bool ret = false; /* Do not create new values when propagating within an SCC because if there are arithmetic functions with circular dependencies, there is infinite - number of them and we would just make lattices bottom. */ + number of them and we would just make lattices bottom. If this condition + is ever relaxed we have to detect self-feeding recursive calls in + cgraph_edge_brings_value_p in a smarter way. */ if ((ipa_get_jf_pass_through_operation (jfunc) != NOP_EXPR) && ipa_edge_within_scc (cs)) ret = dest_lat->set_contains_variable (); else for (src_val = src_lat->values; src_val; src_val = src_val->next) { - tree cstval = ipa_get_jf_pass_through_result (jfunc, src_val->value); + tree cstval = ipa_get_jf_pass_through_result (jfunc, src_val->value, + parm_type); if (cstval) ret |= dest_lat->add_value (cstval, cs, src_val, src_idx); @@ -1622,12 +1634,14 @@ } /* Propagate scalar values across jump function JFUNC that is associated with - edge CS and put the values into DEST_LAT. */ + edge CS and put the values into DEST_LAT. PARM_TYPE is the type of the + parameter to which the result is passed. */ static bool propagate_scalar_across_jump_function (struct cgraph_edge *cs, struct ipa_jump_func *jfunc, - ipcp_lattice<tree> *dest_lat) + ipcp_lattice<tree> *dest_lat, + tree param_type) { if (dest_lat->bottom) return false; @@ -1662,7 +1676,7 @@ if (jfunc->type == IPA_JF_PASS_THROUGH) ret = propagate_vals_across_pass_through (cs, jfunc, src_lat, - dest_lat, src_idx); + dest_lat, src_idx, param_type); else ret = propagate_vals_across_ancestor (cs, jfunc, src_lat, dest_lat, src_idx); @@ -1781,14 +1795,16 @@ struct ipa_node_params *callee_info = IPA_NODE_REF (callee); tree parm_type = ipa_get_type (callee_info, idx); - /* For K&R C programs, ipa_get_type() could return NULL_TREE. - Avoid the transform for these cases. */ - if (!parm_type) + /* For K&R C programs, ipa_get_type() could return NULL_TREE. Avoid the + transform for these cases. Similarly, we can have bad type mismatches + with LTO, avoid doing anything with those too. */ + if (!parm_type + || (!INTEGRAL_TYPE_P (parm_type) && !POINTER_TYPE_P (parm_type))) { if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, "Setting dest_lattice to bottom, because" - " param %i type is NULL for %s\n", idx, - cs->callee->name ()); + fprintf (dump_file, "Setting dest_lattice to bottom, because type of " + "param %i of %s is NULL or unsuitable for bits propagation\n", + idx, cs->callee->name ()); return dest_lattice->set_to_bottom (); } @@ -1859,12 +1875,11 @@ enum tree_code operation, tree dst_type, tree src_type) { - memset (dst_vr, 0, sizeof (*dst_vr)); + *dst_vr = value_range (); extract_range_from_unary_expr (dst_vr, operation, dst_type, src_vr, src_type); - if (dst_vr->type == VR_RANGE || dst_vr->type == VR_ANTI_RANGE) - return true; - else + if (dst_vr->varying_p () || dst_vr->undefined_p ()) return false; + return true; } /* Propagate value range across jump function JFUNC that is associated with @@ -1917,11 +1932,7 @@ if (TREE_OVERFLOW_P (val)) val = drop_tree_overflow (val); - value_range tmpvr; - memset (&tmpvr, 0, sizeof (tmpvr)); - tmpvr.type = VR_RANGE; - tmpvr.min = val; - tmpvr.max = val; + value_range tmpvr (VR_RANGE, val, val); return dest_lat->meet_with (&tmpvr); } } @@ -1930,7 +1941,7 @@ if (jfunc->m_vr && ipa_vr_operation_and_type_effects (&vr, jfunc->m_vr, NOP_EXPR, param_type, - TREE_TYPE (jfunc->m_vr->min))) + jfunc->m_vr->type ())) return dest_lat->meet_with (&vr); else return dest_lat->set_to_bottom (); @@ -2237,24 +2248,6 @@ if (parms_count == 0) return false; - /* No propagation through instrumentation thunks is available yet. - It should be possible with proper mapping of call args and - instrumented callee params in the propagation loop below. But - this case mostly occurs when legacy code calls instrumented code - and it is not a primary target for optimizations. - We detect instrumentation thunks in aliases and thunks chain by - checking instrumentation_clone flag for chain source and target. - Going through instrumentation thunks we always have it changed - from 0 to 1 and all other nodes do not change it. */ - if (!cs->callee->instrumentation_clone - && callee->instrumentation_clone) - { - for (i = 0; i < parms_count; i++) - ret |= set_all_contains_variable (ipa_get_parm_lattices (callee_info, - i)); - return ret; - } - /* If this call goes through a thunk we must not propagate to the first (0th) parameter. However, we might need to uncover a thunk from below a series of aliases first. */ @@ -2279,7 +2272,8 @@ else { ret |= propagate_scalar_across_jump_function (cs, jump_func, - &dest_plats->itself); + &dest_plats->itself, + param_type); ret |= propagate_context_across_jump_function (cs, jump_func, i, &dest_plats->ctxlat); ret @@ -2894,7 +2888,7 @@ "known contexts, code not going to grow.\n"); } else if (good_cloning_opportunity_p (node, - MAX ((base_time - time).to_int (), + MIN ((base_time - time).to_int (), 65536), stats.freq_sum, stats.count_sum, size)) @@ -3257,6 +3251,8 @@ if (dump_file) fprintf (dump_file, "\n Propagating constants:\n\n"); + max_count = profile_count::uninitialized (); + FOR_EACH_DEFINED_FUNCTION (node) { struct ipa_node_params *info = IPA_NODE_REF (node); @@ -3268,10 +3264,10 @@ ipa_get_param_count (info)); initialize_node_lattices (node); } - if (node->definition && !node->alias) - overall_size += ipa_fn_summaries->get (node)->self_size; - if (node->count > max_count) - max_count = node->count; + ipa_fn_summary *s = ipa_fn_summaries->get (node); + if (node->definition && !node->alias && s != NULL) + overall_size += s->self_size; + max_count = max_count.max (node->count.ipa ()); } max_new_size = overall_size; @@ -3356,54 +3352,56 @@ ipa_update_overall_fn_summary (node); } -/* Vector of pointers which for linked lists of clones of an original crgaph - edge. */ - -static vec<cgraph_edge *> next_edge_clone; -static vec<cgraph_edge *> prev_edge_clone; - -static inline void -grow_edge_clone_vectors (void) -{ - if (next_edge_clone.length () - <= (unsigned) symtab->edges_max_uid) - next_edge_clone.safe_grow_cleared (symtab->edges_max_uid + 1); - if (prev_edge_clone.length () - <= (unsigned) symtab->edges_max_uid) - prev_edge_clone.safe_grow_cleared (symtab->edges_max_uid + 1); -} - -/* Edge duplication hook to grow the appropriate linked list in - next_edge_clone. */ - -static void -ipcp_edge_duplication_hook (struct cgraph_edge *src, struct cgraph_edge *dst, - void *) +class edge_clone_summary; +static call_summary <edge_clone_summary *> *edge_clone_summaries = NULL; + +/* Edge clone summary. */ + +struct edge_clone_summary { - grow_edge_clone_vectors (); - - struct cgraph_edge *old_next = next_edge_clone[src->uid]; - if (old_next) - prev_edge_clone[old_next->uid] = dst; - prev_edge_clone[dst->uid] = src; - - next_edge_clone[dst->uid] = old_next; - next_edge_clone[src->uid] = dst; -} - -/* Hook that is called by cgraph.c when an edge is removed. */ - -static void -ipcp_edge_removal_hook (struct cgraph_edge *cs, void *) + /* Default constructor. */ + edge_clone_summary (): prev_clone (NULL), next_clone (NULL) {} + + /* Default destructor. */ + ~edge_clone_summary () + { + if (prev_clone) + edge_clone_summaries->get (prev_clone)->next_clone = next_clone; + if (next_clone) + edge_clone_summaries->get (next_clone)->prev_clone = prev_clone; + } + + cgraph_edge *prev_clone; + cgraph_edge *next_clone; +}; + +class edge_clone_summary_t: + public call_summary <edge_clone_summary *> { - grow_edge_clone_vectors (); - - struct cgraph_edge *prev = prev_edge_clone[cs->uid]; - struct cgraph_edge *next = next_edge_clone[cs->uid]; - if (prev) - next_edge_clone[prev->uid] = next; - if (next) - prev_edge_clone[next->uid] = prev; +public: + edge_clone_summary_t (symbol_table *symtab): + call_summary <edge_clone_summary *> (symtab) + { + m_initialize_when_cloning = true; + } + + virtual void duplicate (cgraph_edge *src_edge, cgraph_edge *dst_edge, + edge_clone_summary *src_data, + edge_clone_summary *dst_data); +}; + +/* Edge duplication hook. */ + +void +edge_clone_summary_t::duplicate (cgraph_edge *src_edge, cgraph_edge *dst_edge, + edge_clone_summary *src_data, + edge_clone_summary *dst_data) +{ + if (src_data->next_clone) + edge_clone_summaries->get (src_data->next_clone)->prev_clone = dst_edge; + dst_data->prev_clone = src_edge; + dst_data->next_clone = src_data->next_clone; + src_data->next_clone = dst_edge; } /* See if NODE is a clone with a known aggregate value at a given OFFSET of a @@ -3438,12 +3436,12 @@ return info->is_all_contexts_clone && info->ipcp_orig_node == dest; } -/* Return true if edge CS does bring about the value described by SRC to node - DEST or its clone for all contexts. */ +/* Return true if edge CS does bring about the value described by SRC to + DEST_VAL of node DEST or its clone for all contexts. */ static bool cgraph_edge_brings_value_p (cgraph_edge *cs, ipcp_value_source<tree> *src, - cgraph_node *dest) + cgraph_node *dest, ipcp_value<tree> *dest_val) { struct ipa_node_params *caller_info = IPA_NODE_REF (cs->caller); enum availability availability; @@ -3453,6 +3451,7 @@ || availability <= AVAIL_INTERPOSABLE || caller_info->node_dead) return false; + if (!src->val) return true; @@ -3468,6 +3467,12 @@ } else { + /* At the moment we do not propagate over arithmetic jump functions in + SCCs, so it is safe to detect self-feeding recursive calls in this + way. */ + if (src->val == dest_val) + return true; + struct ipcp_agg_lattice *aglat; struct ipcp_param_lattices *plats = ipa_get_parm_lattices (caller_info, src->index); @@ -3489,13 +3494,14 @@ } } -/* Return true if edge CS does bring about the value described by SRC to node - DEST or its clone for all contexts. */ +/* Return true if edge CS does bring about the value described by SRC to + DST_VAL of node DEST or its clone for all contexts. */ static bool cgraph_edge_brings_value_p (cgraph_edge *cs, ipcp_value_source<ipa_polymorphic_call_context> *src, - cgraph_node *dest) + cgraph_node *dest, + ipcp_value<ipa_polymorphic_call_context> *) { struct ipa_node_params *caller_info = IPA_NODE_REF (cs->caller); cgraph_node *real_dest = cs->callee->function_symbol (); @@ -3523,12 +3529,14 @@ static inline struct cgraph_edge * get_next_cgraph_edge_clone (struct cgraph_edge *cs) { - return next_edge_clone[cs->uid]; + edge_clone_summary *s = edge_clone_summaries->get (cs); + return s != NULL ? s->next_clone : NULL; } -/* Given VAL that is intended for DEST, iterate over all its sources and if - they still hold, add their edge frequency and their number into *FREQUENCY - and *CALLER_COUNT respectively. */ +/* Given VAL that is intended for DEST, iterate over all its sources and if any + of them is viable and hot, return true. In that case, for those that still + hold, add their edge frequency and their number into *FREQUENCY and + *CALLER_COUNT respectively. */ template <typename valtype> static bool @@ -3540,24 +3548,32 @@ int freq = 0, count = 0; profile_count cnt = profile_count::zero (); bool hot = false; + bool non_self_recursive = false; for (src = val->sources; src; src = src->next) { struct cgraph_edge *cs = src->cs; while (cs) { - if (cgraph_edge_brings_value_p (cs, src, dest)) + if (cgraph_edge_brings_value_p (cs, src, dest, val)) { count++; - freq += cs->frequency; - if (cs->count.initialized_p ()) - cnt += cs->count; + freq += cs->frequency (); + if (cs->count.ipa ().initialized_p ()) + cnt += cs->count.ipa (); hot |= cs->maybe_hot_p (); + if (cs->caller != dest) + non_self_recursive = true; } cs = get_next_cgraph_edge_clone (cs); } } + /* If the only edges bringing a value are self-recursive ones, do not bother + evaluating it. */ + if (!non_self_recursive) + return false; + *freq_sum = freq; *count_sum = cnt; *caller_count = count; @@ -3581,7 +3597,7 @@ struct cgraph_edge *cs = src->cs; while (cs) { - if (cgraph_edge_brings_value_p (cs, src, dest)) + if (cgraph_edge_brings_value_p (cs, src, dest, val)) ret.quick_push (cs); cs = get_next_cgraph_edge_clone (cs); } @@ -3661,7 +3677,7 @@ profile_count new_sum, orig_sum; profile_count remainder, orig_node_count = orig_node->count; - if (!(orig_node_count > profile_count::zero ())) + if (!(orig_node_count.ipa () > profile_count::zero ())) return; init_caller_stats (&stats); @@ -3694,16 +3710,13 @@ } } - new_node->count = new_sum; - remainder = orig_node_count - new_sum; + remainder = orig_node_count.combine_with_ipa_count (orig_node_count.ipa () + - new_sum.ipa ()); + new_sum = orig_node_count.combine_with_ipa_count (new_sum); orig_node->count = remainder; for (cs = new_node->callees; cs; cs = cs->next_callee) - /* FIXME: why we care about non-zero frequency here? */ - if (cs->frequency) - cs->count = cs->count.apply_scale (new_sum, orig_node_count); - else - cs->count = profile_count::zero (); + cs->count = cs->count.apply_scale (new_sum, orig_node_count); for (cs = orig_node->callees; cs; cs = cs->next_callee) cs->count = cs->count.apply_scale (remainder, orig_node_count); @@ -3740,10 +3753,7 @@ orig_node->count -= redirected_sum; for (cs = new_node->callees; cs; cs = cs->next_callee) - if (cs->frequency) - cs->count += cs->count.apply_scale (redirected_sum, new_node_count); - else - cs->count = profile_count::zero (); + cs->count += cs->count.apply_scale (redirected_sum, new_node_count); for (cs = orig_node->callees; cs; cs = cs->next_callee) { @@ -3807,9 +3817,39 @@ vec_safe_push (replace_trees, replace_map); } } + auto_vec<cgraph_edge *, 2> self_recursive_calls; + for (i = callers.length () - 1; i >= 0; i--) + { + cgraph_edge *cs = callers[i]; + if (cs->caller == node) + { + self_recursive_calls.safe_push (cs); + callers.unordered_remove (i); + } + } new_node = node->create_virtual_clone (callers, replace_trees, args_to_skip, "constprop"); + + bool have_self_recursive_calls = !self_recursive_calls.is_empty (); + for (unsigned j = 0; j < self_recursive_calls.length (); j++) + { + cgraph_edge *cs = get_next_cgraph_edge_clone (self_recursive_calls[j]); + /* Cloned edges can disappear during cloning as speculation can be + resolved, check that we have one and that it comes from the last + cloning. */ + if (cs && cs->caller == new_node) + cs->redirect_callee_duplicating_thunks (new_node); + /* Any future code that would make more than one clone of an outgoing + edge would confuse this mechanism, so let's check that does not + happen. */ + gcc_checking_assert (!cs + || !get_next_cgraph_edge_clone (cs) + || get_next_cgraph_edge_clone (cs)->caller != new_node); + } + if (have_self_recursive_calls) + new_node->expand_all_artificial_thunks (); + ipa_set_node_agg_value_chain (new_node, aggvals); for (av = aggvals; av; av = av->next) new_node->maybe_create_reference (av->value, NULL); @@ -3842,6 +3882,22 @@ return new_node; } +/* Return true, if JFUNC, which describes a i-th parameter of call CS, is a + simple no-operation pass-through function to itself. */ + +static bool +self_recursive_pass_through_p (cgraph_edge *cs, ipa_jump_func *jfunc, int i) +{ + enum availability availability; + if (cs->caller == cs->callee->function_symbol (&availability) + && availability > AVAIL_INTERPOSABLE + && jfunc->type == IPA_JF_PASS_THROUGH + && ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR + && ipa_get_jf_pass_through_formal_id (jfunc) == i) + return true; + return false; +} + /* Given a NODE, and a subset of its CALLERS, try to populate blanks slots in KNOWN_CSTS with constants that are also known for all of the CALLERS. */ @@ -3859,6 +3915,7 @@ tree newval = NULL_TREE; int j; bool first = true; + tree type = ipa_get_type (info, i); if (ipa_get_scalar_lat (info, i)->bottom || known_csts[i]) continue; @@ -3868,17 +3925,21 @@ struct ipa_jump_func *jump_func; tree t; + if (IPA_NODE_REF (cs->caller)->node_dead) + continue; + if (i >= ipa_get_cs_argument_count (IPA_EDGE_REF (cs)) || (i == 0 - && call_passes_through_thunk_p (cs)) - || (!cs->callee->instrumentation_clone - && cs->callee->function_symbol ()->instrumentation_clone)) + && call_passes_through_thunk_p (cs))) { newval = NULL_TREE; break; } jump_func = ipa_get_ith_jump_func (IPA_EDGE_REF (cs), i); - t = ipa_value_from_jfunc (IPA_NODE_REF (cs->caller), jump_func); + if (self_recursive_pass_through_p (cs, jump_func, i)) + continue; + + t = ipa_value_from_jfunc (IPA_NODE_REF (cs->caller), jump_func, type); if (!t || (newval && !values_equal_for_ipcp_p (t, newval)) @@ -4027,7 +4088,9 @@ if (aglat->offset - offset == item->offset) { gcc_checking_assert (item->value); - if (values_equal_for_ipcp_p (item->value, aglat->values->value)) + if (aglat->is_single_const () + && values_equal_for_ipcp_p (item->value, + aglat->values->value)) found = true; break; } @@ -4180,7 +4243,7 @@ } else { - src_plats = ipa_get_parm_lattices (caller_info, src_idx);; + src_plats = ipa_get_parm_lattices (caller_info, src_idx); /* Currently we do not produce clobber aggregate jump functions, adjust when we do. */ gcc_checking_assert (!src_plats->aggs || !jfunc->agg.items); @@ -4202,7 +4265,7 @@ FOR_EACH_VEC_ELT (inter, k, item) { int l = 0; - bool found = false;; + bool found = false; if (!item->value) continue; @@ -4270,6 +4333,12 @@ FOR_EACH_VEC_ELT (callers, j, cs) { + struct ipa_jump_func *jfunc + = ipa_get_ith_jump_func (IPA_EDGE_REF (cs), i); + if (self_recursive_pass_through_p (cs, jfunc, i) + && (!plats->aggs_by_ref + || ipa_get_jf_pass_through_agg_preserved (jfunc))) + continue; inter = intersect_aggregates_with_edge (cs, i, inter); if (!inter.exists ()) @@ -4300,33 +4369,6 @@ return res; } -/* Turn KNOWN_AGGS into a list of aggregate replacement values. */ - -static struct ipa_agg_replacement_value * -known_aggs_to_agg_replacement_list (vec<ipa_agg_jump_function> known_aggs) -{ - struct ipa_agg_replacement_value *res; - struct ipa_agg_replacement_value **tail = &res; - struct ipa_agg_jump_function *aggjf; - struct ipa_agg_jf_item *item; - int i, j; - - FOR_EACH_VEC_ELT (known_aggs, i, aggjf) - FOR_EACH_VEC_SAFE_ELT (aggjf->items, j, item) - { - struct ipa_agg_replacement_value *v; - v = ggc_alloc<ipa_agg_replacement_value> (); - v->index = i; - v->offset = item->offset; - v->value = item->value; - v->by_ref = aggjf->by_ref; - *tail = v; - tail = &v->next; - } - *tail = NULL; - return res; -} - /* Determine whether CS also brings all scalar values that the NODE is specialized for. */ @@ -4354,7 +4396,8 @@ if (i >= ipa_get_cs_argument_count (args)) return false; jump_func = ipa_get_ith_jump_func (args, i); - t = ipa_value_from_jfunc (caller_info, jump_func); + t = ipa_value_from_jfunc (caller_info, jump_func, + ipa_get_type (dest_info, i)); if (!t || !values_equal_for_ipcp_p (val, t)) return false; } @@ -4451,7 +4494,7 @@ struct cgraph_edge *cs = src->cs; while (cs) { - if (cgraph_edge_brings_value_p (cs, src, node) + if (cgraph_edge_brings_value_p (cs, src, node, val) && cgraph_edge_brings_all_scalars_for_node (cs, val->spec_node) && cgraph_edge_brings_all_agg_vals_for_node (cs, val->spec_node)) { @@ -4462,14 +4505,14 @@ cs->redirect_callee_duplicating_thunks (val->spec_node); val->spec_node->expand_all_artificial_thunks (); - if (cs->count.initialized_p ()) - redirected_sum = redirected_sum + cs->count; + if (cs->count.ipa ().initialized_p ()) + redirected_sum = redirected_sum + cs->count.ipa (); } cs = get_next_cgraph_edge_clone (cs); } } - if (redirected_sum > profile_count::zero ()) + if (redirected_sum.nonzero_p ()) update_specialized_profile (val->spec_node, node, redirected_sum); } @@ -4716,6 +4759,10 @@ "for all known contexts.\n", node->dump_name ()); callers = node->collect_callers (); + 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 + = find_aggregate_values_for_callers_subset (node, callers); if (!known_contexts_useful_p (known_contexts)) { @@ -4723,8 +4770,7 @@ known_contexts = vNULL; } clone = create_specialized_node (node, known_csts, known_contexts, - known_aggs_to_agg_replacement_list (known_aggs), - callers); + aggvals, callers); info = IPA_NODE_REF (node); info->do_clone_for_all_contexts = false; IPA_NODE_REF (clone)->is_all_contexts_clone = true; @@ -4884,8 +4930,8 @@ if (!found_useful_result) continue; - ipcp_grow_transformations_if_necessary (); - ipcp_transformation_summary *ts = ipcp_get_transformation_summary (node); + ipcp_transformation_initialize (); + ipcp_transformation *ts = ipcp_transformation_sum->get_create (node); vec_safe_reserve_exact (ts->bits, count); for (unsigned i = 0; i < count; i++) @@ -4957,8 +5003,8 @@ if (!found_useful_result) continue; - ipcp_grow_transformations_if_necessary (); - ipcp_transformation_summary *ts = ipcp_get_transformation_summary (node); + ipcp_transformation_initialize (); + ipcp_transformation *ts = ipcp_transformation_sum->get_create (node); vec_safe_reserve_exact (ts->m_vr, count); for (unsigned i = 0; i < count; i++) @@ -4970,9 +5016,9 @@ && !plats->m_value_range.top_p ()) { vr.known = true; - vr.type = plats->m_value_range.m_vr.type; - vr.min = wi::to_wide (plats->m_value_range.m_vr.min); - vr.max = wi::to_wide (plats->m_value_range.m_vr.max); + vr.type = plats->m_value_range.m_vr.kind (); + vr.min = wi::to_wide (plats->m_value_range.m_vr.min ()); + vr.max = wi::to_wide (plats->m_value_range.m_vr.max ()); } else { @@ -4990,17 +5036,13 @@ static unsigned int ipcp_driver (void) { - struct cgraph_2edge_hook_list *edge_duplication_hook_holder; - struct cgraph_edge_hook_list *edge_removal_hook_holder; struct ipa_topo_info topo; + if (edge_clone_summaries == NULL) + edge_clone_summaries = new edge_clone_summary_t (symtab); + ipa_check_create_node_params (); ipa_check_create_edge_args (); - grow_edge_clone_vectors (); - edge_duplication_hook_holder - = symtab->add_edge_duplication_hook (&ipcp_edge_duplication_hook, NULL); - edge_removal_hook_holder - = symtab->add_edge_removal_hook (&ipcp_edge_removal_hook, NULL); if (dump_file) { @@ -5023,10 +5065,8 @@ /* Free all IPCP structures. */ free_toporder_info (&topo); - next_edge_clone.release (); - prev_edge_clone.release (); - symtab->remove_edge_removal_hook (edge_removal_hook_holder); - symtab->remove_edge_duplication_hook (edge_duplication_hook_holder); + delete edge_clone_summaries; + edge_clone_summaries = NULL; ipa_free_all_structures_after_ipa_cp (); if (dump_file) fprintf (dump_file, "\nIPA constant propagation end\n"); @@ -5125,7 +5165,7 @@ void ipa_cp_c_finalize (void) { - max_count = profile_count::zero (); + max_count = profile_count::uninitialized (); overall_size = 0; max_new_size = 0; }