On Wed, Feb 22, 2017 at 11:11 AM, Martin Jambor <mjam...@suse.cz> wrote: > Hello, > > this is a fix for PR 78140 which is about LTO WPA of Firefox taking > 1GB memory more than gcc 6. > > It works by reusing the ipa_bits and value_range that we previously > had directly in jump functions and which are just too big to be > allocated for each actual argument in all of Firefox. Reusing is > achieved by two hash table traits derived from ggc_cache_remove which > apparently has been created just for this purpose and once I > understood them they made my life a lot easier. In future, I will > have a look at applying this method to other parts of jump functions > as well. > > According to my measurements, the patch saves about 1.2 GB of memory. > The problem is that some change last week (between revision 245382 and > 245595) has more than invalidated this: > > | compiler | WPA mem (GB) | > |---------------------+--------------| > | gcc 6 branch | 3.86 | > | trunk rev. 245382 | 5.21 | > | patched rev. 245382 | 4.06 | > | trunk rev. 245595 | 6.59 | > | patched rev. 245595 | 5.25 | > > (I have verified this by Martin's way of measuring things.) I will > try to bisect what commit has caused the increase. Still, the patch > helps a lot. > > There is one thing in the patch that intrigues me, I do not understand > why I had to mark value_range with GTY((for_user)) - as opposed to > just GTY(()) that was there before - whereas ipa_bits does not need > it. If anyone could enlighten me, that would be great. But I suppose > this is not an indication of anything being wrong under the hood. > > I have bootstrapped and LTO-bootstrapped the patch on x86_64-linux and > also bootstrapped (C, C++ and Fortran) on an aarch64 and i686 cfarm > machine. I have also LTO-built Firefox with the patch and used it to > browse for a while and it seemed fine. > > OK for trunk?
The idea looks good to me. I wonder what a statistic over ranges would look like (do they mostly look useful?). Thanks, Richard. > Thanks, > > Martin > > > 2017-02-20 Martin Jambor <mjam...@suse.cz> > > PR lto/78140 > * ipa-prop.h (ipa_bits): Removed field known. > (ipa_jump_func): Removed field vr_known. Changed fields bits and m_vr > to pointers. Adjusted their comments to warn about their sharing. > (ipcp_transformation_summary): Change bits to a vector of pointers. > (ipa_check_create_edge_args): Moved to ipa-prop.c, declare. > (ipa_get_ipa_bits_for_value): Declare. > * tree-vrp.h (value_range): Mark as GTY((for_user)). > * ipa-prop.c (ipa_bit_ggc_hash_traits): New. > (ipa_bits_hash_table): Likewise. > (ipa_vr_ggc_hash_traits): Likewise. > (ipa_vr_hash_table): Likewise. > (ipa_print_node_jump_functions_for_edge): Adjust for bits and m_vr > being pointers and vr_known being removed. > (ipa_set_jf_unknown): Likewise. > (ipa_get_ipa_bits_for_value): New function. > (ipa_set_jfunc_bits): Likewise. > (ipa_get_value_range): New overloaded functions. > (ipa_set_jfunc_vr): Likewise. > (ipa_compute_jump_functions_for_edge): Use the above functions to > construct bits and vr parts of jump functions. > (ipa_check_create_edge_args): Move here from ipa-prop.h, also allocate > ipa_bits_hash_table and ipa_vr_hash_table if they do not already > exist. > (ipcp_grow_transformations_if_necessary): Also allocate > ipa_bits_hash_table and ipa_vr_hash_table if they do not already > exist. > (ipa_node_params_t::duplicate): Do not copy bits, just pointers to > them. Fix too long lines. > (ipa_write_jump_function): Adjust for bits and m_vr being pointers and > vr_known being removed. > (ipa_read_jump_function): Use new setter functions to construct bits > and vr parts of jump functions or set them to NULL. > (write_ipcp_transformation_info): Adjust for bits being pointers. > (read_ipcp_transformation_info): Likewise. > (ipcp_update_bits): Likewise. Fix excessively long lines a trailing > space. > Include gt-ipa-prop.h. > * ipa-cp.c (propagate_bits_across_jump_function): Adjust for bits > being pointers. > (ipcp_store_bits_results): Likewise. > (propagate_vr_across_jump_function): Adjust for m_vr being a pointer. > Do not write to existing jump functions but use a temporary instead. > --- > gcc/ipa-cp.c | 49 ++++---- > gcc/ipa-prop.c | 381 > ++++++++++++++++++++++++++++++++++++++++++--------------- > gcc/ipa-prop.h | 32 ++--- > gcc/tree-vrp.h | 2 +- > 4 files changed, 319 insertions(+), 145 deletions(-) > > diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c > index aa3c9973a66..16e7e2216ab 100644 > --- a/gcc/ipa-cp.c > +++ b/gcc/ipa-cp.c > @@ -1819,8 +1819,8 @@ propagate_bits_across_jump_function (cgraph_edge *cs, > int idx, > and we store it in jump function during analysis stage. */ > > if (src_lats->bits_lattice.bottom_p () > - && jfunc->bits.known) > - return dest_lattice->meet_with (jfunc->bits.value, jfunc->bits.mask, > + && jfunc->bits) > + return dest_lattice->meet_with (jfunc->bits->value, jfunc->bits->mask, > precision); > else > return dest_lattice->meet_with (src_lats->bits_lattice, precision, > sgn, > @@ -1829,10 +1829,9 @@ propagate_bits_across_jump_function (cgraph_edge *cs, > int idx, > > else if (jfunc->type == IPA_JF_ANCESTOR) > return dest_lattice->set_to_bottom (); > - > - else if (jfunc->bits.known) > - return dest_lattice->meet_with (jfunc->bits.value, jfunc->bits.mask, > precision); > - > + else if (jfunc->bits) > + return dest_lattice->meet_with (jfunc->bits->value, jfunc->bits->mask, > + precision); > else > return dest_lattice->set_to_bottom (); > } > @@ -1903,19 +1902,21 @@ propagate_vr_across_jump_function (cgraph_edge *cs, > ipa_jump_func *jfunc, > val = fold_convert (param_type, val); > if (TREE_OVERFLOW_P (val)) > val = drop_tree_overflow (val); > - jfunc->vr_known = true; > - jfunc->m_vr.type = VR_RANGE; > - jfunc->m_vr.min = val; > - jfunc->m_vr.max = val; > - return dest_lat->meet_with (&jfunc->m_vr); > + > + value_range tmpvr; > + memset (&tmpvr, 0, sizeof (tmpvr)); > + tmpvr.type = VR_RANGE; > + tmpvr.min = val; > + tmpvr.max = val; > + return dest_lat->meet_with (&tmpvr); > } > } > > value_range vr; > - if (jfunc->vr_known > - && ipa_vr_operation_and_type_effects (&vr, &jfunc->m_vr, NOP_EXPR, > + if (jfunc->m_vr > + && ipa_vr_operation_and_type_effects (&vr, jfunc->m_vr, NOP_EXPR, > param_type, > - TREE_TYPE (jfunc->m_vr.min))) > + TREE_TYPE (jfunc->m_vr->min))) > return dest_lat->meet_with (&vr); > else > return dest_lat->set_to_bottom (); > @@ -4870,19 +4871,17 @@ ipcp_store_bits_results (void) > for (unsigned i = 0; i < count; i++) > { > ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i); > - ipa_bits bits_jfunc; > + ipa_bits *jfbits; > > if (plats->bits_lattice.constant_p ()) > - { > - bits_jfunc.known = true; > - bits_jfunc.value = plats->bits_lattice.get_value (); > - bits_jfunc.mask = plats->bits_lattice.get_mask (); > - } > + jfbits > + = ipa_get_ipa_bits_for_value (plats->bits_lattice.get_value (), > + plats->bits_lattice.get_mask ()); > else > - bits_jfunc.known = false; > + jfbits = NULL; > > - ts->bits->quick_push (bits_jfunc); > - if (!dump_file || !bits_jfunc.known) > + ts->bits->quick_push (jfbits); > + if (!dump_file || !jfbits) > continue; > if (!dumped_sth) > { > @@ -4891,9 +4890,9 @@ ipcp_store_bits_results (void) > dumped_sth = true; > } > fprintf (dump_file, " param %i: value = ", i); > - print_hex (bits_jfunc.value, dump_file); > + print_hex (jfbits->value, dump_file); > fprintf (dump_file, ", mask = "); > - print_hex (bits_jfunc.mask, dump_file); > + print_hex (jfbits->mask, dump_file); > fprintf (dump_file, "\n"); > } > } > diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c > index e4e44ce20c6..358e439f51b 100644 > --- a/gcc/ipa-prop.c > +++ b/gcc/ipa-prop.c > @@ -60,6 +60,93 @@ vec<ipcp_transformation_summary, va_gc> > *ipcp_transformations; > /* Vector where the parameter infos are actually stored. */ > vec<ipa_edge_args, va_gc> *ipa_edge_args_vector; > > +/* Traits for a hash table for reusing already existing ipa_bits. */ > + > +struct ipa_bit_ggc_hash_traits : public ggc_cache_remove <ipa_bits *> > +{ > + typedef ipa_bits *value_type; > + typedef ipa_bits *compare_type; > + static hashval_t > + hash (const ipa_bits *p) > + { > + hashval_t t = (hashval_t) p->value.to_shwi (); > + return iterative_hash_host_wide_int (p->mask.to_shwi (), t); > + } > + static bool > + equal (const ipa_bits *a, const ipa_bits *b) > + { > + return a->value == b->value && a->mask == b->mask; > + } > + static void > + mark_empty (ipa_bits *&p) > + { > + p = NULL; > + } > + static bool > + is_empty (const ipa_bits *p) > + { > + return p == NULL; > + } > + static bool > + is_deleted (const ipa_bits *p) > + { > + return p == reinterpret_cast<const ipa_bits *> (1); > + } > + static void > + mark_deleted (ipa_bits *&p) > + { > + p = reinterpret_cast<ipa_bits *> (1); > + } > +}; > + > +/* Hash table for avoid repeated allocations of equal ipa_bits. */ > +static GTY ((cache)) hash_table<ipa_bit_ggc_hash_traits> > *ipa_bits_hash_table; > + > +/* Traits for a hash table for reusing value_ranges used for IPA. Note that > + the equiv bitmap is not hashed and is expected to be NULL. */ > + > +struct ipa_vr_ggc_hash_traits : public ggc_cache_remove <value_range *> > +{ > + typedef value_range *value_type; > + typedef value_range *compare_type; > + static hashval_t > + hash (const value_range *p) > + { > + gcc_checking_assert (!p->equiv); > + hashval_t t = (hashval_t) p->type; > + t = iterative_hash_expr (p->min, t); > + return iterative_hash_expr (p->max, t); > + } > + static bool > + equal (const value_range *a, const value_range *b) > + { > + return a->type == b->type && a->min == b->min && a->max == b->max; > + } > + static void > + mark_empty (value_range *&p) > + { > + p = NULL; > + } > + static bool > + is_empty (const value_range *p) > + { > + return p == NULL; > + } > + static bool > + is_deleted (const value_range *p) > + { > + return p == reinterpret_cast<const value_range *> (1); > + } > + static void > + mark_deleted (value_range *&p) > + { > + p = reinterpret_cast<value_range *> (1); > + } > +}; > + > +/* Hash table for avoid repeated allocations of equal value_ranges. */ > +static GTY ((cache)) hash_table<ipa_vr_ggc_hash_traits> *ipa_vr_hash_table; > + > /* Holders of ipa cgraph hooks: */ > static struct cgraph_edge_hook_list *edge_removal_hook_holder; > static struct cgraph_2edge_hook_list *edge_duplication_hook_holder; > @@ -298,23 +385,25 @@ ipa_print_node_jump_functions_for_edge (FILE *f, struct > cgraph_edge *cs) > ctx->dump (dump_file); > } > > - if (jump_func->bits.known) > + if (jump_func->bits) > { > - fprintf (f, " value: "); print_hex (jump_func->bits.value, > f); > - fprintf (f, ", mask: "); print_hex (jump_func->bits.mask, f); > + fprintf (f, " value: "); > + print_hex (jump_func->bits->value, f); > + fprintf (f, ", mask: "); > + print_hex (jump_func->bits->mask, f); > fprintf (f, "\n"); > } > else > fprintf (f, " Unknown bits\n"); > > - if (jump_func->vr_known) > + if (jump_func->m_vr) > { > fprintf (f, " VR "); > fprintf (f, "%s[", > - (jump_func->m_vr.type == VR_ANTI_RANGE) ? "~" : ""); > - print_decs (jump_func->m_vr.min, f); > + (jump_func->m_vr->type == VR_ANTI_RANGE) ? "~" : ""); > + print_decs (jump_func->m_vr->min, f); > fprintf (f, ", "); > - print_decs (jump_func->m_vr.max, f); > + print_decs (jump_func->m_vr->max, f); > fprintf (f, "]\n"); > } > else > @@ -397,8 +486,8 @@ static void > ipa_set_jf_unknown (struct ipa_jump_func *jfunc) > { > jfunc->type = IPA_JF_UNKNOWN; > - jfunc->bits.known = false; > - jfunc->vr_known = false; > + jfunc->bits = NULL; > + jfunc->m_vr = NULL; > } > > /* Set JFUNC to be a copy of another jmp (to be used by jump function > @@ -1658,6 +1747,91 @@ ipa_get_callee_param_type (struct cgraph_edge *e, int > i) > return NULL; > } > > +/* Return ipa_bits with VALUE and MASK values, which can be either a newly > + allocated structure or a previously existing one shared with other jump > + functions and/or transformation summaries. */ > + > +ipa_bits * > +ipa_get_ipa_bits_for_value (const widest_int &value, const widest_int &mask) > +{ > + ipa_bits tmp; > + tmp.value = value; > + tmp.mask = mask; > + > + ipa_bits **slot = ipa_bits_hash_table->find_slot (&tmp, INSERT); > + if (*slot) > + return *slot; > + > + ipa_bits *res = ggc_alloc<ipa_bits> (); > + res->value = value; > + res->mask = mask; > + *slot = res; > + > + return res; > +} > + > +/* Assign to JF a pointer to ipa_bits structure with VALUE and MASK. Use > hash > + table in order to avoid creating multiple same ipa_bits structures. */ > + > +static void > +ipa_set_jfunc_bits (ipa_jump_func *jf, const widest_int &value, > + const widest_int &mask) > +{ > + jf->bits = ipa_get_ipa_bits_for_value (value, mask); > +} > + > +/* Return a pointer to a value_range just like *TMP, but either find it in > + ipa_vr_hash_table or allocate it in GC memory. TMP->equiv must be NULL. > */ > + > +static value_range * > +ipa_get_value_range (value_range *tmp) > +{ > + value_range **slot = ipa_vr_hash_table->find_slot (tmp, INSERT); > + if (*slot) > + return *slot; > + > + value_range *vr = ggc_alloc<value_range> (); > + *vr = *tmp; > + *slot = vr; > + > + return vr; > +} > + > +/* Return a pointer to a value range consisting of TYPE, MIN, MAX and an > empty > + equiv set. Use hash table in order to avoid creating multiple same copies > of > + value_ranges. */ > + > +static value_range * > +ipa_get_value_range (enum value_range_type type, tree min, tree max) > +{ > + value_range tmp; > + tmp.type = type; > + tmp.min = min; > + tmp.max = max; > + tmp.equiv = NULL; > + return ipa_get_value_range (&tmp); > +} > + > +/* Assign to JF a pointer to a value_range structure with TYPE, MIN and MAX > and > + a NULL equiv bitmap. Use hash table in order to avoid creating multiple > + same value_range structures. */ > + > +static void > +ipa_set_jfunc_vr (ipa_jump_func *jf, enum value_range_type type, > + tree min, tree max) > +{ > + jf->m_vr = ipa_get_value_range (type, min, max); > +} > + > +/* Assign to JF a pointer to a value_range just liek TMP but either fetch a > + copy from ipa_vr_hash_table or allocate a new on in GC memory. */ > + > +static void > +ipa_set_jfunc_vr (ipa_jump_func *jf, value_range *tmp) > +{ > + jf->m_vr = ipa_get_value_range (tmp); > +} > + > /* Compute jump function for all arguments of callsite CS and insert the > information in the jump_functions array in the ipa_edge_args corresponding > to this callsite. */ > @@ -1714,14 +1888,11 @@ ipa_compute_jump_functions_for_edge (struct > ipa_func_body_info *fbi, > > if (addr_nonzero) > { > - jfunc->vr_known = true; > - jfunc->m_vr.type = VR_ANTI_RANGE; > - jfunc->m_vr.min = build_int_cst (TREE_TYPE (arg), 0); > - jfunc->m_vr.max = build_int_cst (TREE_TYPE (arg), 0); > - jfunc->m_vr.equiv = NULL; > + tree z = build_int_cst (TREE_TYPE (arg), 0); > + ipa_set_jfunc_vr (jfunc, VR_ANTI_RANGE, z, z); > } > else > - gcc_assert (!jfunc->vr_known); > + gcc_assert (!jfunc->m_vr); > } > else > { > @@ -1732,56 +1903,48 @@ ipa_compute_jump_functions_for_edge (struct > ipa_func_body_info *fbi, > && (type = get_range_info (arg, &min, &max)) > && (type == VR_RANGE || type == VR_ANTI_RANGE)) > { > - value_range vr; > - > - vr.type = type; > - vr.min = wide_int_to_tree (TREE_TYPE (arg), min); > - vr.max = wide_int_to_tree (TREE_TYPE (arg), max); > - vr.equiv = NULL; > - extract_range_from_unary_expr (&jfunc->m_vr, > - NOP_EXPR, > - param_type, > - &vr, TREE_TYPE (arg)); > - if (jfunc->m_vr.type == VR_RANGE > - || jfunc->m_vr.type == VR_ANTI_RANGE) > - jfunc->vr_known = true; > + value_range tmpvr,resvr; > + > + tmpvr.type = type; > + tmpvr.min = wide_int_to_tree (TREE_TYPE (arg), min); > + tmpvr.max = wide_int_to_tree (TREE_TYPE (arg), max); > + tmpvr.equiv = NULL; > + memset (&resvr, 0, sizeof (resvr)); > + extract_range_from_unary_expr (&resvr, NOP_EXPR, param_type, > + &tmpvr, TREE_TYPE (arg)); > + if (resvr.type == VR_RANGE || resvr.type == VR_ANTI_RANGE) > + ipa_set_jfunc_vr (jfunc, &resvr); > else > - jfunc->vr_known = false; > + gcc_assert (!jfunc->m_vr); > } > else > - gcc_assert (!jfunc->vr_known); > + gcc_assert (!jfunc->m_vr); > } > > if (INTEGRAL_TYPE_P (TREE_TYPE (arg)) > && (TREE_CODE (arg) == SSA_NAME || TREE_CODE (arg) == INTEGER_CST)) > { > - jfunc->bits.known = true; > - > if (TREE_CODE (arg) == SSA_NAME) > - { > - jfunc->bits.value = 0; > - jfunc->bits.mask = widest_int::from (get_nonzero_bits (arg), > - TYPE_SIGN (TREE_TYPE > (arg))); > - } > + ipa_set_jfunc_bits (jfunc, 0, > + widest_int::from (get_nonzero_bits (arg), > + TYPE_SIGN (TREE_TYPE > (arg)))); > else > - { > - jfunc->bits.value = wi::to_widest (arg); > - jfunc->bits.mask = 0; > - } > + ipa_set_jfunc_bits (jfunc, wi::to_widest (arg), 0); > } > else if (POINTER_TYPE_P (TREE_TYPE (arg))) > { > unsigned HOST_WIDE_INT bitpos; > unsigned align; > > - jfunc->bits.known = true; > get_pointer_alignment_1 (arg, &align, &bitpos); > - jfunc->bits.mask = wi::mask<widest_int>(TYPE_PRECISION (TREE_TYPE > (arg)), false) > - .and_not (align / BITS_PER_UNIT - 1); > - jfunc->bits.value = bitpos / BITS_PER_UNIT; > + widest_int mask > + = wi::mask<widest_int>(TYPE_PRECISION (TREE_TYPE (arg)), false) > + .and_not (align / BITS_PER_UNIT - 1); > + widest_int value = bitpos / BITS_PER_UNIT; > + ipa_set_jfunc_bits (jfunc, value, mask); > } > else > - gcc_assert (!jfunc->bits.known); > + gcc_assert (!jfunc->bits); > > if (is_gimple_ip_invariant (arg) > || (VAR_P (arg) > @@ -3545,6 +3708,22 @@ ipa_propagate_indirect_call_infos (struct cgraph_edge > *cs, > return changed; > } > > +/* Ensure that array of edge arguments infos is big enough to accommodate a > + structure for all edges and reallocates it if not. Also, allocate > + associated hash tables is they do not already exist. */ > + > +void > +ipa_check_create_edge_args (void) > +{ > + if (vec_safe_length (ipa_edge_args_vector) > + <= (unsigned) symtab->edges_max_uid) > + vec_safe_grow_cleared (ipa_edge_args_vector, symtab->edges_max_uid + 1); > + if (!ipa_bits_hash_table) > + ipa_bits_hash_table = hash_table<ipa_bit_ggc_hash_traits>::create_ggc > (37); > + if (!ipa_vr_hash_table) > + ipa_vr_hash_table = hash_table<ipa_vr_ggc_hash_traits>::create_ggc (37); > +} > + > /* Frees all dynamically allocated structures that the argument info points > to. */ > > @@ -3581,7 +3760,8 @@ ipa_free_all_node_params (void) > ipa_node_params_sum = NULL; > } > > -/* Grow ipcp_transformations if necessary. */ > +/* Grow ipcp_transformations if necessary. Also allocate any necessary hash > + tables if they do not already exist. */ > > void > ipcp_grow_transformations_if_necessary (void) > @@ -3589,6 +3769,10 @@ ipcp_grow_transformations_if_necessary (void) > if (vec_safe_length (ipcp_transformations) > <= (unsigned) symtab->cgraph_max_uid) > vec_safe_grow_cleared (ipcp_transformations, symtab->cgraph_max_uid + 1); > + if (!ipa_bits_hash_table) > + ipa_bits_hash_table = hash_table<ipa_bit_ggc_hash_traits>::create_ggc > (37); > + if (!ipa_vr_hash_table) > + ipa_vr_hash_table = hash_table<ipa_vr_ggc_hash_traits>::create_ggc (37); > } > > /* Set the aggregate replacements of NODE to be AGGVALS. */ > @@ -3775,12 +3959,18 @@ ipa_node_params_t::duplicate(cgraph_node *src, > cgraph_node *dst, > ipa_set_node_agg_value_chain (dst, new_av); > } > > - ipcp_transformation_summary *src_trans = ipcp_get_transformation_summary > (src); > + ipcp_transformation_summary *src_trans > + = ipcp_get_transformation_summary (src); > > if (src_trans) > { > ipcp_grow_transformations_if_necessary (); > src_trans = ipcp_get_transformation_summary (src); > + ipcp_transformation_summary *dst_trans > + = ipcp_get_transformation_summary (dst); > + > + dst_trans->bits = vec_safe_copy (src_trans->bits); > + > const vec<ipa_vr, va_gc> *src_vr = src_trans->m_vr; > vec<ipa_vr, va_gc> *&dst_vr > = ipcp_get_transformation_summary (dst)->m_vr; > @@ -3791,18 +3981,6 @@ ipa_node_params_t::duplicate(cgraph_node *src, > cgraph_node *dst, > dst_vr->quick_push ((*src_vr)[i]); > } > } > - > - if (src_trans && vec_safe_length (src_trans->bits) > 0) > - { > - ipcp_grow_transformations_if_necessary (); > - src_trans = ipcp_get_transformation_summary (src); > - const vec<ipa_bits, va_gc> *src_bits = src_trans->bits; > - vec<ipa_bits, va_gc> *&dst_bits > - = ipcp_get_transformation_summary (dst)->bits; > - vec_safe_reserve_exact (dst_bits, src_bits->length ()); > - for (unsigned i = 0; i < src_bits->length (); ++i) > - dst_bits->quick_push ((*src_bits)[i]); > - } > } > > /* Register our cgraph hooks if they are not already there. */ > @@ -4718,21 +4896,21 @@ ipa_write_jump_function (struct output_block *ob, > } > > bp = bitpack_create (ob->main_stream); > - bp_pack_value (&bp, jump_func->bits.known, 1); > + bp_pack_value (&bp, !!jump_func->bits, 1); > streamer_write_bitpack (&bp); > - if (jump_func->bits.known) > + if (jump_func->bits) > { > - streamer_write_widest_int (ob, jump_func->bits.value); > - streamer_write_widest_int (ob, jump_func->bits.mask); > + streamer_write_widest_int (ob, jump_func->bits->value); > + streamer_write_widest_int (ob, jump_func->bits->mask); > } > - bp_pack_value (&bp, jump_func->vr_known, 1); > + bp_pack_value (&bp, !!jump_func->m_vr, 1); > streamer_write_bitpack (&bp); > - if (jump_func->vr_known) > + if (jump_func->m_vr) > { > streamer_write_enum (ob->main_stream, value_rang_type, > - VR_LAST, jump_func->m_vr.type); > - stream_write_tree (ob, jump_func->m_vr.min, true); > - stream_write_tree (ob, jump_func->m_vr.max, true); > + VR_LAST, jump_func->m_vr->type); > + stream_write_tree (ob, jump_func->m_vr->min, true); > + stream_write_tree (ob, jump_func->m_vr->max, true); > } > } > > @@ -4809,26 +4987,25 @@ ipa_read_jump_function (struct lto_input_block *ib, > bool bits_known = bp_unpack_value (&bp, 1); > if (bits_known) > { > - jump_func->bits.known = true; > - jump_func->bits.value = streamer_read_widest_int (ib); > - jump_func->bits.mask = streamer_read_widest_int (ib); > + widest_int value = streamer_read_widest_int (ib); > + widest_int mask = streamer_read_widest_int (ib); > + ipa_set_jfunc_bits (jump_func, value, mask); > } > else > - jump_func->bits.known = false; > + jump_func->bits = NULL; > > struct bitpack_d vr_bp = streamer_read_bitpack (ib); > bool vr_known = bp_unpack_value (&vr_bp, 1); > if (vr_known) > { > - jump_func->vr_known = true; > - jump_func->m_vr.type = streamer_read_enum (ib, > - value_range_type, > - VR_LAST); > - jump_func->m_vr.min = stream_read_tree (ib, data_in); > - jump_func->m_vr.max = stream_read_tree (ib, data_in); > + enum value_range_type type = streamer_read_enum (ib, value_range_type, > + VR_LAST); > + tree min = stream_read_tree (ib, data_in); > + tree max = stream_read_tree (ib, data_in); > + ipa_set_jfunc_vr (jump_func, type, min, max); > } > else > - jump_func->vr_known = false; > + jump_func->m_vr = NULL; > } > > /* Stream out parts of cgraph_indirect_call_info corresponding to CS that are > @@ -5207,14 +5384,14 @@ write_ipcp_transformation_info (output_block *ob, > cgraph_node *node) > > for (unsigned i = 0; i < count; ++i) > { > - const ipa_bits& bits_jfunc = (*ts->bits)[i]; > + const ipa_bits *bits_jfunc = (*ts->bits)[i]; > struct bitpack_d bp = bitpack_create (ob->main_stream); > - bp_pack_value (&bp, bits_jfunc.known, 1); > + bp_pack_value (&bp, !!bits_jfunc, 1); > streamer_write_bitpack (&bp); > - if (bits_jfunc.known) > + if (bits_jfunc) > { > - streamer_write_widest_int (ob, bits_jfunc.value); > - streamer_write_widest_int (ob, bits_jfunc.mask); > + streamer_write_widest_int (ob, bits_jfunc->value); > + streamer_write_widest_int (ob, bits_jfunc->mask); > } > } > } > @@ -5281,13 +5458,14 @@ read_ipcp_transformation_info (lto_input_block *ib, > cgraph_node *node, > > for (i = 0; i < count; i++) > { > - ipa_bits& bits_jfunc = (*ts->bits)[i]; > struct bitpack_d bp = streamer_read_bitpack (ib); > - bits_jfunc.known = bp_unpack_value (&bp, 1); > - if (bits_jfunc.known) > + bool known = bp_unpack_value (&bp, 1); > + if (known) > { > - bits_jfunc.value = streamer_read_widest_int (ib); > - bits_jfunc.mask = streamer_read_widest_int (ib); > + ipa_bits *bits > + = ipa_get_ipa_bits_for_value (streamer_read_widest_int (ib), > + streamer_read_widest_int (ib)); > + (*ts->bits)[i] = bits; > } > } > } > @@ -5554,7 +5732,7 @@ ipcp_update_bits (struct cgraph_node *node) > if (!ts || vec_safe_length (ts->bits) == 0) > return; > > - vec<ipa_bits, va_gc> &bits = *ts->bits; > + vec<ipa_bits *, va_gc> &bits = *ts->bits; > unsigned count = bits.length (); > > for (unsigned i = 0; i < count; ++i, parm = next_parm) > @@ -5566,10 +5744,11 @@ ipcp_update_bits (struct cgraph_node *node) > gcc_checking_assert (parm); > next_parm = DECL_CHAIN (parm); > > - if (!bits[i].known > - || !(INTEGRAL_TYPE_P (TREE_TYPE (parm)) || POINTER_TYPE_P > (TREE_TYPE (parm))) > + if (!bits[i] > + || !(INTEGRAL_TYPE_P (TREE_TYPE (parm)) > + || POINTER_TYPE_P (TREE_TYPE (parm))) > || !is_gimple_reg (parm)) > - continue; > + continue; > > tree ddef = ssa_default_def (DECL_STRUCT_FUNCTION (node->decl), parm); > if (!ddef) > @@ -5577,8 +5756,8 @@ ipcp_update_bits (struct cgraph_node *node) > > if (dump_file) > { > - fprintf (dump_file, "Adjusting mask for param %u to ", i); > - print_hex (bits[i].mask, dump_file); > + fprintf (dump_file, "Adjusting mask for param %u to ", i); > + print_hex (bits[i]->mask, dump_file); > fprintf (dump_file, "\n"); > } > > @@ -5587,14 +5766,14 @@ ipcp_update_bits (struct cgraph_node *node) > unsigned prec = TYPE_PRECISION (TREE_TYPE (ddef)); > signop sgn = TYPE_SIGN (TREE_TYPE (ddef)); > > - wide_int nonzero_bits = wide_int::from (bits[i].mask, prec, > UNSIGNED) > - | wide_int::from (bits[i].value, prec, sgn); > + wide_int nonzero_bits = wide_int::from (bits[i]->mask, prec, > UNSIGNED) > + | wide_int::from (bits[i]->value, prec, > sgn); > set_nonzero_bits (ddef, nonzero_bits); > } > else > { > - unsigned tem = bits[i].mask.to_uhwi (); > - unsigned HOST_WIDE_INT bitpos = bits[i].value.to_uhwi (); > + unsigned tem = bits[i]->mask.to_uhwi (); > + unsigned HOST_WIDE_INT bitpos = bits[i]->value.to_uhwi (); > unsigned align = tem & -tem; > unsigned misalign = bitpos & (align - 1); > > @@ -5757,3 +5936,5 @@ ipcp_transform_function (struct cgraph_node *node) > else > return TODO_update_ssa_only_virtuals; > } > + > +#include "gt-ipa-prop.h" > diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h > index 8f7eb088813..74234eb470d 100644 > --- a/gcc/ipa-prop.h > +++ b/gcc/ipa-prop.h > @@ -152,11 +152,10 @@ struct GTY(()) ipa_bits > Similar to ccp_lattice_t, if xth bit of mask is 0, > implies xth bit of value is constant. */ > widest_int mask; > - /* True if jump function is known. */ > - bool known; > }; > > /* Info about value ranges. */ > + > struct GTY(()) ipa_vr > { > /* The data fields below are valid only if known is true. */ > @@ -175,13 +174,15 @@ struct GTY (()) ipa_jump_func > description. */ > struct ipa_agg_jump_function agg; > > - /* Information about zero/non-zero bits. */ > - struct ipa_bits bits; > + /* Information about zero/non-zero bits. The pointed to structure is > shared > + betweed different jump functions. Use ipa_set_jfunc_bits to set this > + field. */ > + struct ipa_bits *bits; > > /* Information about value range, containing valid data only when vr_known > is > - true. */ > - value_range m_vr; > - bool vr_known; > + true. The pointed to structure is shared betweed different jump > + functions. Use ipa_set_jfunc_vr to set this field. */ > + struct value_range *m_vr; > > enum jump_func_type type; > /* Represents a value of a jump function. pass_through is used only in > jump > @@ -547,7 +548,7 @@ struct GTY(()) ipcp_transformation_summary > /* Linked list of known aggregate values. */ > ipa_agg_replacement_value *agg_values; > /* Known bits information. */ > - vec<ipa_bits, va_gc> *bits; > + vec<ipa_bits *, va_gc> *bits; > /* Value range information. */ > vec<ipa_vr, va_gc> *m_vr; > }; > @@ -630,6 +631,7 @@ extern GTY(()) vec<ipa_edge_args, va_gc> > *ipa_edge_args_vector; > /* Creating and freeing ipa_node_params and ipa_edge_args. */ > void ipa_create_all_node_params (void); > void ipa_create_all_edge_args (void); > +void ipa_check_create_edge_args (void); > void ipa_free_edge_args_substructures (struct ipa_edge_args *); > void ipa_free_all_node_params (void); > void ipa_free_all_edge_args (void); > @@ -651,17 +653,6 @@ ipa_check_create_node_params (void) > ipa_node_params_t (symtab, true)); > } > > -/* This function ensures the array of edge arguments infos is big enough to > - accommodate a structure for all edges and reallocates it if not. */ > - > -static inline void > -ipa_check_create_edge_args (void) > -{ > - if (vec_safe_length (ipa_edge_args_vector) > - <= (unsigned) symtab->edges_max_uid) > - vec_safe_grow_cleared (ipa_edge_args_vector, symtab->edges_max_uid + 1); > -} > - > /* Returns true if the array of edge infos is large enough to accommodate an > info for EDGE. The main purpose of this function is that debug dumping > function can check info availability without causing reallocations. */ > @@ -703,6 +694,9 @@ tree ipa_get_indirect_edge_target (struct cgraph_edge *ie, > 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); > +ipa_bits *ipa_get_ipa_bits_for_value (const widest_int &value, > + const widest_int &mask); > + > > /* Functions related to both. */ > void ipa_analyze_node (struct cgraph_node *); > diff --git a/gcc/tree-vrp.h b/gcc/tree-vrp.h > index 4fed978d0aa..ef2c68a752b 100644 > --- a/gcc/tree-vrp.h > +++ b/gcc/tree-vrp.h > @@ -24,7 +24,7 @@ enum value_range_type { VR_UNDEFINED, VR_RANGE, > > /* Range of values that can be associated with an SSA_NAME after VRP > has executed. */ > -struct GTY(()) value_range > +struct GTY((for_user)) value_range > { > /* Lattice value represented by this range. */ > enum value_range_type type; > -- > 2.11.0 >