[PATCH] Make IPA-CP propagate alignment information of pointers
Martin Jambor
mjambor@suse.cz
Mon Dec 1 17:36:00 GMT 2014
Ping (this is a new feature submitted in stage1 so I'd really
appreciate a review before it is going to be deemed "too late").
Thanks,
Martin
On Wed, Nov 19, 2014 at 12:32:53AM +0100, Martin Jambor wrote:
> Hi,
>
...
>
> 2014-11-19 Martin Jambor <mjambor@suse.cz>
>
> * ipa-prop.h (ipa_alignment): New type.
> (ipa_jump_func): New field alignment.
> (ipcp_transformation_summary) New type.
> (ipcp_grow_transformations_if_necessary): Declare.
> (ipa_node_agg_replacements): Removed.
> (ipcp_transformations): Declare.
> (ipcp_get_transformation_summary): New function.
> (ipa_get_agg_replacements_for_node): Use it.
> * ipa-cp.c (ipcp_param_lattices): New field alignment.
> (print_all_lattices): Also print alignment.
> (alignment_bottom_p): New function.
> (set_alignment_to_bottom): Likewise.
> (set_all_contains_variable): Also set alignment to bottom.
> (initialize_node_lattices): Likewise.
> (propagate_alignment_accross_jump_function): New function.
> (propagate_constants_accross_call): Call it.
> (ipcp_store_alignment_results): New function.
> (ipcp_driver): Call it.
> * ipa-prop.c (ipa_node_agg_replacements): Removed.
> (ipcp_transformations): New.
> (ipa_print_node_jump_functions_for_edge): Also print alignment.
> (ipa_set_jf_unknown): New function.
> (detect_type_change_from_memory_writes): Use ipa_set_jf_unknown.
> (ipa_compute_jump_functions_for_edge): Also calculate alignment.
> (update_jump_functions_after_inlining): Use ipa_set_jf_unknown.
> (ipcp_grow_transformations_if_necessary): New function.
> (ipa_set_node_agg_value_chain): Use ipcp_transformations.
> (ipa_node_removal_hook): Likewise.
> (ipa_node_duplication_hook): Also duplicate alignment results.
> (ipa_write_jump_function): Also stream alignments.
> (ipa_read_jump_function): Use ipa_set_jf_unknown, also stream
> alignments.
> (write_agg_replacement_chain): Renamed to
> write_ipcp_transformation_info, also stream alignments.
> (read_agg_replacement_chain): Renamed to
> read_ipcp_transformation_info, also stream alignments.
> (ipa_prop_write_all_agg_replacement): Renamed to
> ipcp_write_transformation_summaries. Stream always.
> (ipa_prop_read_all_agg_replacement): Renamed to
> ipcp_read_transformation_summaries.
> (ipcp_update_alignments): New function.
> (ipcp_transform_function): Call it, free also alignments.
>
> testsuite/
> * gcc.dg/ipa/propalign-1.c: New test.
> * gcc.dg/ipa/propalign-2.c: Likewise.
>
> Index: src/gcc/ipa-cp.c
> ===================================================================
> --- src.orig/gcc/ipa-cp.c 2014-11-18 22:53:01.886689227 +0100
> +++ src/gcc/ipa-cp.c 2014-11-19 00:15:08.890876993 +0100
> @@ -262,6 +262,9 @@ public:
> ipcp_lattice<ipa_polymorphic_call_context> ctxlat;
> /* Lattices describing aggregate parts. */
> ipcp_agg_lattice *aggs;
> + /* Alignment information. Very basic one value lattice where !known means
> + TOP and zero alignment bottom. */
> + ipa_alignment alignment;
> /* Number of aggregate lattices */
> int aggs_count;
> /* True if aggregate data were passed by reference (as opposed to by
> @@ -444,6 +447,13 @@ print_all_lattices (FILE * f, bool dump_
> plats->itself.print (f, dump_sources, dump_benefits);
> fprintf (f, " ctxs: ");
> plats->ctxlat.print (f, dump_sources, dump_benefits);
> + if (plats->alignment.known && plats->alignment.align > 0)
> + fprintf (f, " Alignment %u, misaglignment %u\n",
> + plats->alignment.align, plats->alignment.misalign);
> + else if (plats->alignment.known)
> + fprintf (f, " Alignment unusable\n");
> + else
> + fprintf (f, " Alignment unknown\n");
> if (plats->virt_call)
> fprintf (f, " virt_call flag set\n");
>
> @@ -761,6 +771,27 @@ set_agg_lats_contain_variable (struct ip
> return ret;
> }
>
> +/* Return true if alignemnt informatin in PLATS is known to be unusable. */
> +
> +static inline bool
> +alignment_bottom_p (ipcp_param_lattices *plats)
> +{
> + return plats->alignment.known && (plats->alignment.align == 0);
> +}
> +
> +/* Set alignment information in PLATS to unusable. Return true if it
> + previously was usable or unknown. */
> +
> +static inline bool
> +set_alignment_to_bottom (ipcp_param_lattices *plats)
> +{
> + if (alignment_bottom_p (plats))
> + return false;
> + plats->alignment.known = true;
> + plats->alignment.align = 0;
> + return true;
> +}
> +
> /* Mark bot aggregate and scalar lattices as containing an unknown variable,
> return true is any of them has not been marked as such so far. */
>
> @@ -771,6 +802,7 @@ set_all_contains_variable (struct ipcp_p
> ret = plats->itself.set_contains_variable ();
> ret |= plats->ctxlat.set_contains_variable ();
> ret |= set_agg_lats_contain_variable (plats);
> + ret |= set_alignment_to_bottom (plats);
> return ret;
> }
>
> @@ -807,6 +839,7 @@ initialize_node_lattices (struct cgraph_
> plats->itself.set_to_bottom ();
> plats->ctxlat.set_to_bottom ();
> set_agg_lats_to_bottom (plats);
> + set_alignment_to_bottom (plats);
> }
> else
> set_all_contains_variable (plats);
> @@ -1375,6 +1408,77 @@ propagate_context_accross_jump_function
> return ret;
> }
>
> +/* Propagate alignments accross jump function JFUNC that is associated with
> + edge CS and update DEST_LAT accordingly. */
> +
> +static bool
> +propagate_alignment_accross_jump_function (struct cgraph_edge *cs,
> + struct ipa_jump_func *jfunc,
> + struct ipcp_param_lattices *dest_lat)
> +{
> + if (alignment_bottom_p (dest_lat))
> + return false;
> +
> + ipa_alignment cur;
> + cur.known = false;
> + if (jfunc->alignment.known)
> + cur = jfunc->alignment;
> + else if (jfunc->type == IPA_JF_PASS_THROUGH
> + || jfunc->type == IPA_JF_ANCESTOR)
> + {
> + struct ipa_node_params *caller_info = IPA_NODE_REF (cs->caller);
> + struct ipcp_param_lattices *src_lats;
> + HOST_WIDE_INT offset = 0;
> + int src_idx;
> +
> + if (jfunc->type == IPA_JF_PASS_THROUGH)
> + {
> + enum tree_code op = ipa_get_jf_pass_through_operation (jfunc);
> + if (op != NOP_EXPR)
> + {
> + if (op != POINTER_PLUS_EXPR
> + && op != PLUS_EXPR
> + && op != MINUS_EXPR)
> + goto prop_fail;
> + tree operand = ipa_get_jf_pass_through_operand (jfunc);
> + if (!tree_fits_shwi_p (operand))
> + goto prop_fail;
> + offset = tree_to_shwi (operand);
> + }
> + src_idx = ipa_get_jf_pass_through_formal_id (jfunc);
> + }
> + else
> + {
> + src_idx = ipa_get_jf_ancestor_formal_id (jfunc);
> + offset = ipa_get_jf_ancestor_offset (jfunc);
> + }
> +
> + src_lats = ipa_get_parm_lattices (caller_info, src_idx);
> + if (!src_lats->alignment.known
> + || alignment_bottom_p (src_lats))
> + goto prop_fail;
> +
> + cur = src_lats->alignment;
> + cur.misalign = (cur.misalign + offset) % cur.align;
> + }
> +
> + if (cur.known)
> + {
> + if (!dest_lat->alignment.known)
> + {
> + dest_lat->alignment = cur;
> + return true;
> + }
> + else if (dest_lat->alignment.align == cur.align
> + && dest_lat->alignment.misalign == cur.misalign)
> + return false;
> + }
> +
> + prop_fail:
> + set_alignment_to_bottom (dest_lat);
> + return true;
> +}
> +
> /* If DEST_PLATS already has aggregate items, check that aggs_by_ref matches
> NEW_AGGS_BY_REF and if not, mark all aggs as bottoms and return true (in all
> other cases, return false). If there are no aggregate items, set
> @@ -1711,6 +1815,8 @@ propagate_constants_accross_call (struct
> &dest_plats->itself);
> ret |= propagate_context_accross_jump_function (cs, jump_func, i,
> &dest_plats->ctxlat);
> + ret |= propagate_alignment_accross_jump_function (cs, jump_func,
> + dest_plats);
> ret |= propagate_aggs_accross_jump_function (cs, jump_func,
> dest_plats);
> }
> @@ -4187,6 +4293,63 @@ ipcp_decision_stage (struct ipa_topo_inf
> }
> }
>
> +/* Look up all alignment information that we have discovered and copy it over
> + to the transformation summary. */
> +
> +static void
> +ipcp_store_alignment_results (void)
> +{
> + cgraph_node *node;
> +
> + FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
> + {
> + ipa_node_params *info = IPA_NODE_REF (node);
> + bool dumped_sth = false;
> + bool found_useful_result = false;
> +
> + if (info->ipcp_orig_node)
> + info = IPA_NODE_REF (info->ipcp_orig_node);
> +
> + unsigned count = ipa_get_param_count (info);
> + for (unsigned i = 0; i < count ; i++)
> + {
> + ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
> + if (plats->alignment.known
> + && plats->alignment.align > 0)
> + {
> + found_useful_result = true;
> + break;
> + }
> + }
> + if (!found_useful_result)
> + continue;
> +
> + ipcp_grow_transformations_if_necessary ();
> + ipcp_transformation_summary *ts = ipcp_get_transformation_summary (node);
> + vec_safe_reserve_exact (ts->alignments, count);
> +
> + for (unsigned i = 0; i < count ; i++)
> + {
> + ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
> +
> + if (plats->alignment.align == 0)
> + plats->alignment.known = false;
> +
> + ts->alignments->quick_push (plats->alignment);
> + if (!dump_file || !plats->alignment.known)
> + continue;
> + if (!dumped_sth)
> + {
> + fprintf (dump_file, "Propagated alignment info for function %s/%i:\n",
> + node->name (), node->order);
> + dumped_sth = true;
> + }
> + fprintf (dump_file, " param %i: align: %u, misalign: %u\n",
> + i, plats->alignment.align, plats->alignment.misalign);
> + }
> + }
> +}
> +
> /* The IPCP driver. */
>
> static unsigned int
> @@ -4228,6 +4391,8 @@ ipcp_driver (void)
> ipcp_propagate_stage (&topo);
> /* Decide what constant propagation and cloning should be performed. */
> ipcp_decision_stage (&topo);
> + /* Store results of alignment propagation. */
> + ipcp_store_alignment_results ();
>
> /* Free all IPCP structures. */
> free_toporder_info (&topo);
> @@ -4300,9 +4465,9 @@ public:
> ipcp_generate_summary, /* generate_summary */
> ipcp_write_summary, /* write_summary */
> ipcp_read_summary, /* read_summary */
> - ipa_prop_write_all_agg_replacement, /*
> + ipcp_write_transformation_summaries, /*
> write_optimization_summary */
> - ipa_prop_read_all_agg_replacement, /*
> + ipcp_read_transformation_summaries, /*
> read_optimization_summary */
> NULL, /* stmt_fixup */
> 0, /* function_transform_todo_flags_start */
> Index: src/gcc/ipa-prop.c
> ===================================================================
> --- src.orig/gcc/ipa-prop.c 2014-11-18 22:53:01.886689227 +0100
> +++ src/gcc/ipa-prop.c 2014-11-19 00:01:08.550844968 +0100
> @@ -133,8 +133,8 @@ struct func_body_info
>
> /* Vector where the parameter infos are actually stored. */
> vec<ipa_node_params> ipa_node_params_vector;
> -/* Vector of known aggregate values in cloned nodes. */
> -vec<ipa_agg_replacement_value_p, va_gc> *ipa_node_agg_replacements;
> +/* Vector of IPA-CP transformation data for each clone. */
> +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;
>
> @@ -374,6 +374,15 @@ ipa_print_node_jump_functions_for_edge (
> fprintf (f, " Context: ");
> ctx->dump (dump_file);
> }
> +
> + if (jump_func->alignment.known)
> + {
> + fprintf (f, " Alignment: %u, misalignment: %u\n",
> + jump_func->alignment.align,
> + jump_func->alignment.misalign);
> + }
> + else
> + fprintf (f, " Unknown alignment\n");
> }
> }
>
> @@ -446,6 +455,15 @@ ipa_print_all_jump_functions (FILE *f)
> }
> }
>
> +/* Set jfunc to be a know-really nothing jump function. */
> +
> +static void
> +ipa_set_jf_unknown (struct ipa_jump_func *jfunc)
> +{
> + jfunc->type = IPA_JF_UNKNOWN;
> + jfunc->alignment.known = false;
> +}
> +
> /* Set JFUNC to be a copy of another jmp (to be used by jump function
> combination code). The two functions will share their rdesc. */
>
> @@ -750,7 +768,7 @@ detect_type_change_from_memory_writes (t
> if (!tci.type_maybe_changed)
> return false;
>
> - jfunc->type = IPA_JF_UNKNOWN;
> + ipa_set_jf_unknown (jfunc);
> return true;
> }
>
> @@ -1716,6 +1734,24 @@ ipa_compute_jump_functions_for_edge (str
> useful_context = true;
> }
>
> + if (POINTER_TYPE_P (TREE_TYPE(arg)))
> + {
> + unsigned HOST_WIDE_INT hwi_bitpos;
> + unsigned align;
> +
> + if (get_pointer_alignment_1 (arg, &align, &hwi_bitpos)
> + && align > BITS_PER_UNIT)
> + {
> + jfunc->alignment.known = true;
> + jfunc->alignment.align = align;
> + jfunc->alignment.misalign = hwi_bitpos / BITS_PER_UNIT;
> + }
> + else
> + gcc_assert (!jfunc->alignment.known);
> + }
> + else
> + gcc_assert (!jfunc->alignment.known);
> +
> if (is_gimple_ip_invariant (arg))
> ipa_set_jf_constant (jfunc, arg, cs);
> else if (!is_gimple_reg_type (TREE_TYPE (arg))
> @@ -2411,7 +2447,7 @@ update_jump_functions_after_inlining (st
> don't. */
> if (dst_fid >= ipa_get_cs_argument_count (top))
> {
> - dst->type = IPA_JF_UNKNOWN;
> + ipa_set_jf_unknown (dst);
> continue;
> }
>
> @@ -2465,7 +2501,7 @@ update_jump_functions_after_inlining (st
> src->value.ancestor.agg_preserved;
> }
> else
> - dst->type = IPA_JF_UNKNOWN;
> + ipa_set_jf_unknown (dst);
> }
> else if (dst->type == IPA_JF_PASS_THROUGH)
> {
> @@ -2503,7 +2539,7 @@ update_jump_functions_after_inlining (st
> switch (src->type)
> {
> case IPA_JF_UNKNOWN:
> - dst->type = IPA_JF_UNKNOWN;
> + ipa_set_jf_unknown (dst);
> break;
> case IPA_JF_CONST:
> ipa_set_jf_cst_copy (dst, src);
> @@ -2557,7 +2593,7 @@ update_jump_functions_after_inlining (st
> }
> }
> else
> - dst->type = IPA_JF_UNKNOWN;
> + ipa_set_jf_unknown (dst);
> }
> }
> }
> @@ -3327,18 +3363,24 @@ ipa_free_all_node_params (void)
> ipa_node_params_vector.release ();
> }
>
> +/* Grow ipcp_transformations if necessary. */
> +
> +void
> +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);
> +}
> +
> /* Set the aggregate replacements of NODE to be AGGVALS. */
>
> void
> ipa_set_node_agg_value_chain (struct cgraph_node *node,
> struct ipa_agg_replacement_value *aggvals)
> {
> - if (vec_safe_length (ipa_node_agg_replacements)
> - <= (unsigned) symtab->cgraph_max_uid)
> - vec_safe_grow_cleared (ipa_node_agg_replacements,
> - symtab->cgraph_max_uid + 1);
> -
> - (*ipa_node_agg_replacements)[node->uid] = aggvals;
> + ipcp_grow_transformations_if_necessary ();
> + (*ipcp_transformations)[node->uid].agg_values = aggvals;
> }
>
> /* Hook that is called by cgraph.c when an edge is removed. */
> @@ -3379,8 +3421,11 @@ ipa_node_removal_hook (struct cgraph_nod
> /* During IPA-CP updating we can be called on not-yet analyze clones. */
> if (ipa_node_params_vector.length () > (unsigned)node->uid)
> ipa_free_node_params_substructures (IPA_NODE_REF (node));
> - if (vec_safe_length (ipa_node_agg_replacements) > (unsigned)node->uid)
> - (*ipa_node_agg_replacements)[(unsigned)node->uid] = NULL;
> + if (vec_safe_length (ipcp_transformations) > (unsigned)node->uid)
> + {
> + (*ipcp_transformations)[(unsigned)node->uid].agg_values = NULL;
> + (*ipcp_transformations)[(unsigned)node->uid].alignments = NULL;
> + }
> }
>
> /* Hook that is called by cgraph.c when an edge is duplicated. */
> @@ -3508,21 +3553,35 @@ ipa_node_duplication_hook (struct cgraph
> new_info->node_enqueued = old_info->node_enqueued;
>
> old_av = ipa_get_agg_replacements_for_node (src);
> - if (!old_av)
> - return;
> -
> - new_av = NULL;
> - while (old_av)
> + if (old_av)
> {
> - struct ipa_agg_replacement_value *v;
> + new_av = NULL;
> + while (old_av)
> + {
> + struct ipa_agg_replacement_value *v;
>
> - v = ggc_alloc<ipa_agg_replacement_value> ();
> - memcpy (v, old_av, sizeof (*v));
> - v->next = new_av;
> - new_av = v;
> - old_av = old_av->next;
> + v = ggc_alloc<ipa_agg_replacement_value> ();
> + memcpy (v, old_av, sizeof (*v));
> + v->next = new_av;
> + new_av = v;
> + old_av = old_av->next;
> + }
> + ipa_set_node_agg_value_chain (dst, new_av);
> + }
> +
> + ipcp_transformation_summary *src_trans = ipcp_get_transformation_summary (src);
> +
> + if (src_trans && vec_safe_length (src_trans->alignments) > 0)
> + {
> + ipcp_grow_transformations_if_necessary ();
> + src_trans = ipcp_get_transformation_summary (src);
> + const vec<ipa_alignment, va_gc> *src_alignments = src_trans->alignments;
> + vec<ipa_alignment, va_gc> *&dst_alignments
> + = ipcp_get_transformation_summary (dst)->alignments;
> + vec_safe_reserve_exact (dst_alignments, src_alignments->length ());
> + for (unsigned i = 0; i < src_alignments->length (); ++i)
> + dst_alignments->quick_push ((*src_alignments)[i]);
> }
> - ipa_set_node_agg_value_chain (dst, new_av);
> }
>
>
> @@ -4450,6 +4509,15 @@ ipa_write_jump_function (struct output_b
> streamer_write_uhwi (ob, item->offset);
> stream_write_tree (ob, item->value, true);
> }
> +
> + bp = bitpack_create (ob->main_stream);
> + bp_pack_value (&bp, jump_func->alignment.known, 1);
> + streamer_write_bitpack (&bp);
> + if (jump_func->alignment.known)
> + {
> + streamer_write_uhwi (ob, jump_func->alignment.align);
> + streamer_write_uhwi (ob, jump_func->alignment.misalign);
> + }
> }
>
> /* Read in jump function JUMP_FUNC from IB. */
> @@ -4468,7 +4536,7 @@ ipa_read_jump_function (struct lto_input
> switch (jftype)
> {
> case IPA_JF_UNKNOWN:
> - jump_func->type = IPA_JF_UNKNOWN;
> + ipa_set_jf_unknown (jump_func);
> break;
> case IPA_JF_CONST:
> ipa_set_jf_constant (jump_func, stream_read_tree (ib, data_in), cs);
> @@ -4515,6 +4583,17 @@ ipa_read_jump_function (struct lto_input
> item.value = stream_read_tree (ib, data_in);
> jump_func->agg.items->quick_push (item);
> }
> +
> + struct bitpack_d bp = streamer_read_bitpack (ib);
> + bool alignment_known = bp_unpack_value (&bp, 1);
> + if (alignment_known)
> + {
> + jump_func->alignment.known = true;
> + jump_func->alignment.align = streamer_read_uhwi (ib);
> + jump_func->alignment.misalign = streamer_read_uhwi (ib);
> + }
> + else
> + jump_func->alignment.known = false;
> }
>
> /* Stream out parts of cgraph_indirect_call_info corresponding to CS that are
> @@ -4826,7 +4905,7 @@ ipa_update_after_lto_read (void)
> }
>
> void
> -write_agg_replacement_chain (struct output_block *ob, struct cgraph_node *node)
> +write_ipcp_transformation_info (output_block *ob, cgraph_node *node)
> {
> int node_ref;
> unsigned int count = 0;
> @@ -4854,14 +4933,37 @@ write_agg_replacement_chain (struct outp
> bp_pack_value (&bp, av->by_ref, 1);
> streamer_write_bitpack (&bp);
> }
> +
> + ipcp_transformation_summary *ts = ipcp_get_transformation_summary (node);
> + if (ts && vec_safe_length (ts->alignments) > 0)
> + {
> + count = ts->alignments->length ();
> +
> + streamer_write_uhwi (ob, count);
> + for (unsigned i = 0; i < count; ++i)
> + {
> + ipa_alignment *parm_al = &(*ts->alignments)[i];
> +
> + struct bitpack_d bp;
> + bp = bitpack_create (ob->main_stream);
> + bp_pack_value (&bp, parm_al->known, 1);
> + streamer_write_bitpack (&bp);
> + if (parm_al->known)
> + {
> + streamer_write_uhwi (ob, parm_al->align);
> + streamer_write_uhwi (ob, parm_al->misalign);
> + }
> + }
> + }
> + else
> + streamer_write_uhwi (ob, 0);
> }
>
> /* Stream in the aggregate value replacement chain for NODE from IB. */
>
> static void
> -read_agg_replacement_chain (struct lto_input_block *ib,
> - struct cgraph_node *node,
> - struct data_in *data_in)
> +read_ipcp_transformation_info (lto_input_block *ib, cgraph_node *node,
> + data_in *data_in)
> {
> struct ipa_agg_replacement_value *aggvals = NULL;
> unsigned int count, i;
> @@ -4882,12 +4984,35 @@ read_agg_replacement_chain (struct lto_i
> aggvals = av;
> }
> ipa_set_node_agg_value_chain (node, aggvals);
> +
> + count = streamer_read_uhwi (ib);
> + if (count > 0)
> + {
> + ipcp_grow_transformations_if_necessary ();
> +
> + ipcp_transformation_summary *ts = ipcp_get_transformation_summary (node);
> + vec_safe_grow_cleared (ts->alignments, count);
> +
> + for (i = 0; i < count; i++)
> + {
> + ipa_alignment *parm_al;
> + parm_al = &(*ts->alignments)[i];
> + struct bitpack_d bp;
> + bp = streamer_read_bitpack (ib);
> + parm_al->known = bp_unpack_value (&bp, 1);
> + if (parm_al->known)
> + {
> + parm_al->align = streamer_read_uhwi (ib);
> + parm_al->misalign = streamer_read_uhwi (ib);
> + }
> + }
> + }
> }
>
> /* Write all aggregate replacement for nodes in set. */
>
> void
> -ipa_prop_write_all_agg_replacement (void)
> +ipcp_write_transformation_summaries (void)
> {
> struct cgraph_node *node;
> struct output_block *ob;
> @@ -4895,9 +5020,6 @@ ipa_prop_write_all_agg_replacement (void
> lto_symtab_encoder_iterator lsei;
> lto_symtab_encoder_t encoder;
>
> - if (!ipa_node_agg_replacements)
> - return;
> -
> ob = create_output_block (LTO_section_ipcp_transform);
> encoder = ob->decl_state->symtab_node_encoder;
> ob->symbol = NULL;
> @@ -4905,8 +5027,7 @@ ipa_prop_write_all_agg_replacement (void
> lsei_next_function_in_partition (&lsei))
> {
> node = lsei_cgraph_node (lsei);
> - if (node->has_gimple_body_p ()
> - && ipa_get_agg_replacements_for_node (node) != NULL)
> + if (node->has_gimple_body_p ())
> count++;
> }
>
> @@ -4916,9 +5037,8 @@ ipa_prop_write_all_agg_replacement (void
> lsei_next_function_in_partition (&lsei))
> {
> node = lsei_cgraph_node (lsei);
> - if (node->has_gimple_body_p ()
> - && ipa_get_agg_replacements_for_node (node) != NULL)
> - write_agg_replacement_chain (ob, node);
> + if (node->has_gimple_body_p ())
> + write_ipcp_transformation_info (ob, node);
> }
> streamer_write_char_stream (ob->main_stream, 0);
> produce_asm (ob, NULL);
> @@ -4960,7 +5080,7 @@ read_replacements_section (struct lto_fi
> node = dyn_cast<cgraph_node *> (lto_symtab_encoder_deref (encoder,
> index));
> gcc_assert (node->definition);
> - read_agg_replacement_chain (&ib_main, node, data_in);
> + read_ipcp_transformation_info (&ib_main, node, data_in);
> }
> lto_free_section_data (file_data, LTO_section_jump_functions, NULL, data,
> len);
> @@ -4970,7 +5090,7 @@ read_replacements_section (struct lto_fi
> /* Read IPA-CP aggregate replacements. */
>
> void
> -ipa_prop_read_all_agg_replacement (void)
> +ipcp_read_transformation_summaries (void)
> {
> struct lto_file_decl_data **file_data_vec = lto_get_file_decl_data ();
> struct lto_file_decl_data *file_data;
> @@ -5137,6 +5257,58 @@ ipcp_modif_dom_walker::before_dom_childr
>
> }
>
> +/* Update alignment of formal parameters as described in
> + ipcp_transformation_summary. */
> +
> +static void
> +ipcp_update_alignments (struct cgraph_node *node)
> +{
> + tree fndecl = node->decl;
> + tree parm = DECL_ARGUMENTS (fndecl);
> + tree next_parm = parm;
> + ipcp_transformation_summary *ts = ipcp_get_transformation_summary (node);
> + if (!ts || vec_safe_length (ts->alignments) == 0)
> + return;
> + const vec<ipa_alignment, va_gc> &alignments = *ts->alignments;
> + unsigned count = alignments.length ();
> +
> + for (unsigned i = 0; i < count; ++i, parm = next_parm)
> + {
> + if (node->clone.combined_args_to_skip
> + && bitmap_bit_p (node->clone.combined_args_to_skip, i))
> + continue;
> + gcc_checking_assert (parm);
> + next_parm = DECL_CHAIN (parm);
> +
> + if (!alignments[i].known || !is_gimple_reg (parm))
> + continue;
> + tree ddef = ssa_default_def (DECL_STRUCT_FUNCTION (node->decl), parm);
> + if (!ddef)
> + continue;
> +
> + if (dump_file)
> + fprintf (dump_file, " Adjusting alignment of param %u to %u, "
> + "misalignment to %u\n", i, alignments[i].align,
> + alignments[i].misalign);
> +
> + struct ptr_info_def *pi = get_ptr_info (ddef);
> + gcc_checking_assert (pi);
> + unsigned old_align;
> + unsigned old_misalign;
> + bool old_known = get_ptr_info_alignment (pi, &old_align, &old_misalign);
> +
> + if (old_known
> + && old_align >= alignments[i].align)
> + {
> + if (dump_file)
> + fprintf (dump_file, " But the alignment has already "
> + "been %u.\n", old_align);
> + continue;
> + }
> + set_ptr_info_alignment (pi, alignments[i].align, alignments[i].misalign);
> + }
> +}
> +
> /* IPCP transformation phase doing propagation of aggregate values. */
>
> unsigned int
> @@ -5155,6 +5327,7 @@ ipcp_transform_function (struct cgraph_n
> fprintf (dump_file, "Modification phase of node %s/%i\n",
> node->name (), node->order);
>
> + ipcp_update_alignments (node);
> aggval = ipa_get_agg_replacements_for_node (node);
> if (!aggval)
> return 0;
> @@ -5184,7 +5357,8 @@ ipcp_transform_function (struct cgraph_n
> free_ipa_bb_info (bi);
> fbi.bb_infos.release ();
> free_dominance_info (CDI_DOMINATORS);
> - (*ipa_node_agg_replacements)[node->uid] = NULL;
> + (*ipcp_transformations)[node->uid].agg_values = NULL;
> + (*ipcp_transformations)[node->uid].alignments = NULL;
> descriptors.release ();
>
> if (!something_changed)
> Index: src/gcc/ipa-prop.h
> ===================================================================
> --- src.orig/gcc/ipa-prop.h 2014-11-18 22:53:01.886689227 +0100
> +++ src/gcc/ipa-prop.h 2014-11-18 23:59:53.138842094 +0100
> @@ -144,6 +144,17 @@ struct GTY(()) ipa_agg_jump_function
>
> typedef struct ipa_agg_jump_function *ipa_agg_jump_function_p;
>
> +/* Info about poiner alignments. */
> +struct GTY(()) ipa_alignment
> +{
> + /* The data fields below are valid only if known is true. */
> + bool known;
> + /* See ptr_info_def and get_pointer_alignment_1 for description of these
> + two. */
> + unsigned align;
> + unsigned misalign;
> +};
> +
> /* A jump function for a callsite represents the values passed as actual
> arguments of the callsite. See enum jump_func_type for the various
> types of jump functions supported. */
> @@ -153,6 +164,9 @@ struct GTY (()) ipa_jump_func
> description. */
> struct ipa_agg_jump_function agg;
>
> + /* Information about alignment of pointers. */
> + struct ipa_alignment alignment;
> +
> enum jump_func_type type;
> /* Represents a value of a jump function. pass_through is used only in jump
> function context. constant represents the actual constant in constant jump
> @@ -402,10 +416,19 @@ struct GTY(()) ipa_agg_replacement_value
> bool by_ref;
> };
>
> -typedef struct ipa_agg_replacement_value *ipa_agg_replacement_value_p;
> +/* Structure holding information for the transformation phase of IPA-CP. */
> +
> +struct GTY(()) ipcp_transformation_summary
> +{
> + /* Linked list of known aggregate values. */
> + ipa_agg_replacement_value *agg_values;
> + /* Alignemnt information for pointers. */
> + vec<ipa_alignment, va_gc> *alignments;
> +};
>
> void ipa_set_node_agg_value_chain (struct cgraph_node *node,
> struct ipa_agg_replacement_value *aggvals);
> +void ipcp_grow_transformations_if_necessary (void);
>
> /* ipa_edge_args stores information related to a callsite and particularly its
> arguments. It can be accessed by the IPA_EDGE_REF macro. */
> @@ -451,8 +474,8 @@ ipa_get_ith_polymorhic_call_context (str
>
> /* Vector where the parameter infos are actually stored. */
> extern vec<ipa_node_params> ipa_node_params_vector;
> -/* Vector of known aggregate values in cloned nodes. */
> -extern GTY(()) vec<ipa_agg_replacement_value_p, va_gc> *ipa_node_agg_replacements;
> +/* Vector of IPA-CP transformation data for each clone. */
> +extern GTY(()) vec<ipcp_transformation_summary, va_gc> *ipcp_transformations;
> /* Vector where the parameter infos are actually stored. */
> extern GTY(()) vec<ipa_edge_args, va_gc> *ipa_edge_args_vector;
>
> @@ -510,14 +533,21 @@ ipa_edge_args_info_available_for_edge_p
> return ((unsigned) edge->uid < vec_safe_length (ipa_edge_args_vector));
> }
>
> +static inline ipcp_transformation_summary *
> +ipcp_get_transformation_summary (cgraph_node *node)
> +{
> + if ((unsigned) node->uid >= vec_safe_length (ipcp_transformations))
> + return NULL;
> + return &(*ipcp_transformations)[node->uid];
> +}
> +
> /* Return the aggregate replacements for NODE, if there are any. */
>
> static inline struct ipa_agg_replacement_value *
> -ipa_get_agg_replacements_for_node (struct cgraph_node *node)
> +ipa_get_agg_replacements_for_node (cgraph_node *node)
> {
> - if ((unsigned) node->uid >= vec_safe_length (ipa_node_agg_replacements))
> - return NULL;
> - return (*ipa_node_agg_replacements)[node->uid];
> + ipcp_transformation_summary *ts = ipcp_get_transformation_summary (node);
> + return ts ? ts->agg_values : NULL;
> }
>
> /* Function formal parameters related computations. */
> @@ -646,8 +676,8 @@ void ipa_dump_agg_replacement_values (FI
> struct ipa_agg_replacement_value *av);
> void ipa_prop_write_jump_functions (void);
> void ipa_prop_read_jump_functions (void);
> -void ipa_prop_write_all_agg_replacement (void);
> -void ipa_prop_read_all_agg_replacement (void);
> +void ipcp_write_transformation_summaries (void);
> +void ipcp_read_transformation_summaries (void);
> void ipa_update_after_lto_read (void);
> int ipa_get_param_decl_index (struct ipa_node_params *, tree);
> tree ipa_value_from_jfunc (struct ipa_node_params *info,
> Index: src/gcc/testsuite/gcc.dg/ipa/propalign-1.c
> ===================================================================
> --- /dev/null 1970-01-01 00:00:00.000000000 +0000
> +++ src/gcc/testsuite/gcc.dg/ipa/propalign-1.c 2014-11-18 22:53:01.882689227 +0100
> @@ -0,0 +1,32 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fno-early-inlining -fdump-ipa-cp -fdump-tree-optimized" } */
> +
> +#include <stdint.h>
> +
> +extern int fail_the_test(void *);
> +extern int pass_the_test(void *);
> +extern int diversion (void *);
> +
> +static int __attribute__((noinline))
> +foo (void *p)
> +{
> + uintptr_t a = (uintptr_t) p;
> +
> + if (a % 4)
> + return fail_the_test (p);
> + else
> + return pass_the_test (p);
> +}
> +
> +int
> +bar (void)
> +{
> + double buf[8] __attribute__ ((__aligned__(__BIGGEST_ALIGNMENT__)));
> + return foo (&buf);
> +}
> +
> +
> +/* { dg-final { scan-ipa-dump "Adjusting alignment of param" "cp" } } */
> +/* { dg-final { scan-tree-dump-not "fail_the_test" "optimized" } } */
> +/* { dg-final { cleanup-ipa-dump "cp" } } */
> +/* { dg-final { cleanup-tree-dump "optimized" } } */
> Index: src/gcc/testsuite/gcc.dg/ipa/propalign-2.c
> ===================================================================
> --- /dev/null 1970-01-01 00:00:00.000000000 +0000
> +++ src/gcc/testsuite/gcc.dg/ipa/propalign-2.c 2014-11-18 22:53:01.886689227 +0100
> @@ -0,0 +1,58 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fno-early-inlining -fdump-ipa-cp -fdump-tree-optimized" } */
> +
> +#include <stdint.h>
> +
> +extern int fail_the_test(void *);
> +extern int pass_the_test(void *);
> +extern int diversion (void *);
> +
> +struct somestruct
> +{
> + void *whee;
> + void *oops;
> +};
> +
> +struct container
> +{
> + struct somestruct first;
> + struct somestruct buf[32];
> +};
> +
> +static int __attribute__((noinline))
> +foo (void *p)
> +{
> + uintptr_t a = (uintptr_t) p;
> +
> + if (a % 4)
> + return fail_the_test (p);
> + else
> + return pass_the_test (p);
> +}
> +
> +int
> +bar (void)
> +{
> + struct container c;
> + return foo (c.buf);
> +}
> +
> +
> +static int
> +through (struct somestruct *p)
> +{
> + diversion (p);
> + return foo (&p[16]);
> +}
> +
> +int
> +bar2 (void)
> +{
> + struct container c;
> + through (c.buf);
> +}
> +
> +/* { dg-final { scan-ipa-dump "Adjusting alignment of param" "cp" } } */
> +/* { dg-final { scan-tree-dump-not "fail_the_test" "optimized" } } */
> +/* { dg-final { cleanup-ipa-dump "cp" } } */
> +/* { dg-final { cleanup-tree-dump "optimized" } } */
>
More information about the Gcc-patches
mailing list