and tree-inline.cc) according to instructions inserted to the call graph by
the second stage. */
+#define INCLUDE_ALGORITHM
#include "config.h"
#include "system.h"
#include "coretypes.h"
return true;
}
+/* Return true iff X and Y should be considered equal values by IPA-CP. */
+
+static bool
+values_equal_for_ipcp_p (tree x, tree y)
+{
+ gcc_checking_assert (x != NULL_TREE && y != NULL_TREE);
+
+ if (x == y)
+ return true;
+
+ if (TREE_CODE (x) == ADDR_EXPR
+ && TREE_CODE (y) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (x, 0)) == CONST_DECL
+ && TREE_CODE (TREE_OPERAND (y, 0)) == CONST_DECL)
+ return operand_equal_p (DECL_INITIAL (TREE_OPERAND (x, 0)),
+ DECL_INITIAL (TREE_OPERAND (y, 0)), 0);
+ else
+ return operand_equal_p (x, y, 0);
+}
+
/* Print V which is extracted from a value in a lattice to F. */
static void
drop_all_ones);
}
+/* Dump the contents of the list to FILE. */
+
+void
+ipa_argagg_value_list::dump (FILE *f)
+{
+ bool comma = false;
+ for (const ipa_argagg_value &av : m_elts)
+ {
+ fprintf (f, "%s %i[%u]=", comma ? "," : "",
+ av.index, av.unit_offset);
+ print_generic_expr (f, av.value);
+ if (av.by_ref)
+ fprintf (f, "(by_ref)");
+ comma = true;
+ }
+ fprintf (f, "\n");
+}
+
+/* Dump the contents of the list to stderr. */
+
+void
+ipa_argagg_value_list::debug ()
+{
+ dump (stderr);
+}
+
+/* Return the item describing a constant stored for INDEX at UNIT_OFFSET or
+ NULL if there is no such constant. */
+
+const ipa_argagg_value *
+ipa_argagg_value_list::get_elt (int index, unsigned unit_offset) const
+{
+ ipa_argagg_value key;
+ key.index = index;
+ key.unit_offset = unit_offset;
+ const ipa_argagg_value *res
+ = std::lower_bound (m_elts.begin (), m_elts.end (), key,
+ [] (const ipa_argagg_value &elt,
+ const ipa_argagg_value &val)
+ {
+ if (elt.index < val.index)
+ return true;
+ if (elt.index > val.index)
+ return false;
+ if (elt.unit_offset < val.unit_offset)
+ return true;
+ return false;
+ });
+
+ if (res == m_elts.end ()
+ || res->index != index
+ || res->unit_offset != unit_offset)
+ res = nullptr;
+
+ /* TODO: perhaps remove the check (that the underlying array is indeed
+ sorted) if it turns out it can be too slow? */
+ if (!flag_checking)
+ return res;
+
+ const ipa_argagg_value *slow_res = NULL;
+ int prev_index = -1;
+ unsigned prev_unit_offset = 0;
+ for (const ipa_argagg_value &av : m_elts)
+ {
+ gcc_assert (prev_index < 0
+ || prev_index < av.index
+ || prev_unit_offset < av.unit_offset);
+ prev_index = av.index;
+ prev_unit_offset = av.unit_offset;
+ if (av.index == index
+ && av.unit_offset == unit_offset)
+ slow_res = &av;
+ }
+ gcc_assert (res == slow_res);
+
+ return res;
+}
+
+/* Return the first item describing a constant stored for parameter with INDEX,
+ regardless of offset or reference, or NULL if there is no such constant. */
+
+const ipa_argagg_value *
+ipa_argagg_value_list::get_elt_for_index (int index) const
+{
+ const ipa_argagg_value *res
+ = std::lower_bound (m_elts.begin (), m_elts.end (), index,
+ [] (const ipa_argagg_value &elt, unsigned idx)
+ {
+ return elt.index < idx;
+ });
+ if (res == m_elts.end ()
+ || res->index != index)
+ res = nullptr;
+ return res;
+}
+
+/* Return the aggregate constant stored for INDEX at UNIT_OFFSET, not
+ performing any check of whether value is passed by reference, or NULL_TREE
+ if there is no such constant. */
+
+tree
+ipa_argagg_value_list::get_value (int index, unsigned unit_offset) const
+{
+ const ipa_argagg_value *av = get_elt (index, unit_offset);
+ return av ? av->value : NULL_TREE;
+}
+
+/* Return the aggregate constant stored for INDEX at UNIT_OFFSET, if it is
+ passed by reference or not according to BY_REF, or NULL_TREE if there is
+ no such constant. */
+
+tree
+ipa_argagg_value_list::get_value (int index, unsigned unit_offset,
+ bool by_ref) const
+{
+ const ipa_argagg_value *av = get_elt (index, unit_offset);
+ if (av && av->by_ref == by_ref)
+ return av->value;
+ return NULL_TREE;
+}
+
+/* Return true if all elements present in OTHER are also present in this
+ list. */
+
+bool
+ipa_argagg_value_list::superset_of_p (const ipa_argagg_value_list &other) const
+{
+ unsigned j = 0;
+ for (unsigned i = 0; i < other.m_elts.size (); i++)
+ {
+ unsigned other_index = other.m_elts[i].index;
+ unsigned other_offset = other.m_elts[i].unit_offset;
+
+ while (j < m_elts.size ()
+ && (m_elts[j].index < other_index
+ || (m_elts[j].index == other_index
+ && m_elts[j].unit_offset < other_offset)))
+ j++;
+
+ if (j >= m_elts.size ()
+ || m_elts[j].index != other_index
+ || m_elts[j].unit_offset != other_offset
+ || m_elts[j].by_ref != other.m_elts[i].by_ref
+ || !m_elts[j].value
+ || !values_equal_for_ipcp_p (m_elts[j].value, other.m_elts[i].value))
+ return false;
+ }
+ return true;
+}
+
+/* Push all items in this list that describe parameter SRC_INDEX into RES as
+ ones describing DST_INDEX while subtracting UNIT_DELTA from their unit
+ offsets but skip those which would end up with a negative offset. */
+
+void
+ipa_argagg_value_list::push_adjusted_values (unsigned src_index,
+ unsigned dest_index,
+ unsigned unit_delta,
+ vec<ipa_argagg_value> *res) const
+{
+ const ipa_argagg_value *av = get_elt_for_index (src_index);
+ if (!av)
+ return;
+ unsigned prev_unit_offset = 0;
+ bool first = true;
+ for (; av < m_elts.end (); ++av)
+ {
+ if (av->index > src_index)
+ return;
+ if (av->index == src_index
+ && (av->unit_offset >= unit_delta)
+ && av->value)
+ {
+ ipa_argagg_value new_av;
+ gcc_checking_assert (av->value);
+ new_av.value = av->value;
+ new_av.unit_offset = av->unit_offset - unit_delta;
+ new_av.index = dest_index;
+ new_av.by_ref = av->by_ref;
+
+ /* Quick check that the offsets we push are indeed increasing. */
+ gcc_assert (first
+ || new_av.unit_offset > prev_unit_offset);
+ prev_unit_offset = new_av.unit_offset;
+ first = false;
+
+ res->safe_push (new_av);
+ }
+ }
+}
+
+/* Push to RES information about single lattices describing aggregate values in
+ PLATS as those describing parameter DEST_INDEX and the original offset minus
+ UNIT_DELTA. Return true if any item has been pushed to RES. */
+
+static bool
+push_agg_values_from_plats (ipcp_param_lattices *plats, int dest_index,
+ unsigned unit_delta,
+ vec<ipa_argagg_value> *res)
+{
+ if (plats->aggs_contain_variable)
+ return false;
+
+ bool pushed_sth = false;
+ bool first = true;
+ unsigned prev_unit_offset = 0;
+ for (struct ipcp_agg_lattice *aglat = plats->aggs; aglat; aglat = aglat->next)
+ if (aglat->is_single_const ()
+ && (aglat->offset / BITS_PER_UNIT - unit_delta) >= 0)
+ {
+ ipa_argagg_value iav;
+ iav.value = aglat->values->value;
+ iav.unit_offset = aglat->offset / BITS_PER_UNIT - unit_delta;
+ iav.index = dest_index;
+ iav.by_ref = plats->aggs_by_ref;
+
+ gcc_assert (first
+ || iav.unit_offset > prev_unit_offset);
+ prev_unit_offset = iav.unit_offset;
+ first = false;
+
+ pushed_sth = true;
+ res->safe_push (iav);
+ }
+ return pushed_sth;
+}
+
+/* Turn all values in LIST that are not present in OTHER into NULL_TREEs.
+ Return the number of remaining valid entries. */
+
+static unsigned
+intersect_argaggs_with (vec<ipa_argagg_value> &elts,
+ const vec<ipa_argagg_value> &other)
+{
+ unsigned valid_entries = 0;
+ unsigned j = 0;
+ for (unsigned i = 0; i < elts.length (); i++)
+ {
+ if (!elts[i].value)
+ continue;
+
+ unsigned this_index = elts[i].index;
+ unsigned this_offset = elts[i].unit_offset;
+
+ while (j < other.length ()
+ && (other[j].index < this_index
+ || (other[j].index == this_index
+ && other[j].unit_offset < this_offset)))
+ j++;
+
+ if (j >= other.length ())
+ {
+ elts[i].value = NULL_TREE;
+ continue;
+ }
+
+ if (other[j].index == this_index
+ && other[j].unit_offset == this_offset
+ && other[j].by_ref == elts[i].by_ref
+ && other[j].value
+ && values_equal_for_ipcp_p (other[j].value, elts[i].value))
+ valid_entries++;
+ else
+ elts[i].value = NULL_TREE;
+ }
+ return valid_entries;
+}
+
/* 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. */
return false;
}
-/* Return true iff X and Y should be considered equal values by IPA-CP. */
-
-static bool
-values_equal_for_ipcp_p (tree x, tree y)
-{
- gcc_checking_assert (x != NULL_TREE && y != NULL_TREE);
-
- if (x == y)
- return true;
-
- if (TREE_CODE (x) == ADDR_EXPR
- && TREE_CODE (y) == ADDR_EXPR
- && TREE_CODE (TREE_OPERAND (x, 0)) == CONST_DECL
- && TREE_CODE (TREE_OPERAND (y, 0)) == CONST_DECL)
- return operand_equal_p (DECL_INITIAL (TREE_OPERAND (x, 0)),
- DECL_INITIAL (TREE_OPERAND (y, 0)), 0);
- else
- return operand_equal_p (x, y, 0);
-}
-
/* Return the result of a (possibly arithmetic) operation on the constant
value INPUT. OPERAND is 2nd operand for binary operation. RES_TYPE is
the type of the parameter to which the result is passed. Return
return vr;
}
-/* See if NODE is a clone with a known aggregate value at a given OFFSET of a
- parameter with the given INDEX. */
-
-static tree
-get_clone_agg_value (struct cgraph_node *node, HOST_WIDE_INT offset,
- int index)
-{
- struct ipa_agg_replacement_value *aggval;
-
- aggval = ipa_get_agg_replacements_for_node (node);
- while (aggval)
- {
- if (aggval->offset == offset
- && aggval->index == index)
- return aggval->value;
- aggval = aggval->next;
- }
- return NULL_TREE;
-}
-
/* Determine whether ITEM, jump function for an aggregate part, evaluates to a
single known constant value and if so, return it. Otherwise return NULL.
NODE and INFO describes the caller node or the one it is inlined to, and
static tree
ipa_agg_value_from_node (class ipa_node_params *info,
struct cgraph_node *node,
- struct ipa_agg_jf_item *item)
+ const ipa_agg_jf_item *item)
{
tree value = NULL_TREE;
int src_idx;
{
if (item->jftype == IPA_JF_PASS_THROUGH)
value = info->known_csts[src_idx];
- else
- value = get_clone_agg_value (node, item->value.load_agg.offset,
- src_idx);
+ else if (ipcp_transformation *ts = ipcp_get_transformation_summary (node))
+ {
+ ipa_argagg_value_list avl (ts);
+ value = avl.get_value (src_idx,
+ item->value.load_agg.offset / BITS_PER_UNIT,
+ item->value.load_agg.by_ref);
+ }
}
else if (info->lattices)
{
}
/* If an indirect edge IE can be turned into a direct one based on KNOWN_VALS
- KNOWN_CONTEXTS, KNOWN_AGGS or AGG_REPS return the destination. The latter
- three can be NULL. If AGG_REPS is not NULL, KNOWN_AGGS is ignored. */
+ KNOWN_CONTEXTS, and known aggregates either in AVS or KNOWN_AGGS return
+ the destination. The latter three can be NULL. If AGG_REPS is not NULL,
+ KNOWN_AGGS is ignored. */
static tree
ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
const vec<tree> &known_csts,
const vec<ipa_polymorphic_call_context> &known_contexts,
const vec<ipa_agg_value_set> &known_aggs,
- struct ipa_agg_replacement_value *agg_reps,
+ const ipa_argagg_value_list *avs,
bool *speculative)
{
int param_index = ie->indirect_info->param_index;
if (ie->indirect_info->agg_contents)
{
t = NULL;
- if (agg_reps && ie->indirect_info->guaranteed_unmodified)
- {
- while (agg_reps)
- {
- if (agg_reps->index == param_index
- && agg_reps->offset == ie->indirect_info->offset
- && agg_reps->by_ref == ie->indirect_info->by_ref)
- {
- t = agg_reps->value;
- break;
- }
- agg_reps = agg_reps->next;
- }
- }
+ if (avs && ie->indirect_info->guaranteed_unmodified)
+ t = avs->get_value (param_index,
+ ie->indirect_info->offset / BITS_PER_UNIT,
+ ie->indirect_info->by_ref);
if (!t)
{
const ipa_agg_value_set *agg;
t = NULL;
/* Try to work out value of virtual table pointer value in replacements. */
- if (!t && agg_reps && !ie->indirect_info->by_ref)
- {
- while (agg_reps)
- {
- if (agg_reps->index == param_index
- && agg_reps->offset == ie->indirect_info->offset
- && agg_reps->by_ref)
- {
- t = agg_reps->value;
- break;
- }
- agg_reps = agg_reps->next;
- }
- }
+ if (!t && avs && !ie->indirect_info->by_ref)
+ t = avs->get_value (param_index,
+ ie->indirect_info->offset / BITS_PER_UNIT,
+ true);
/* Try to work out value of virtual table pointer value in known
aggregate values. */
vec<tree> known_csts,
vec<ipa_polymorphic_call_context>
known_contexts,
- struct ipa_agg_replacement_value *aggvals)
+ vec<ipa_argagg_value, va_gc> *aggvals)
{
struct cgraph_edge *ie, *next_ie;
bool found = false;
bool speculative;
next_ie = ie->next_callee;
+ ipa_argagg_value_list avs (aggvals);
target = ipa_get_indirect_edge_target_1 (ie, known_csts, known_contexts,
- vNULL, aggvals, &speculative);
+ vNULL, &avs, &speculative);
if (target)
{
bool agg_contents = ie->indirect_info->agg_contents;
if (caller_info->ipcp_orig_node)
{
- tree t;
+ tree t = NULL_TREE;
if (src->offset == -1)
t = caller_info->known_csts[src->index];
- else
- t = get_clone_agg_value (cs->caller, src->offset, src->index);
+ else if (ipcp_transformation *ts
+ = ipcp_get_transformation_summary (cs->caller))
+ {
+ ipa_argagg_value_list avl (ts);
+ t = avl.get_value (src->index, src->offset / BITS_PER_UNIT);
+ }
return (t != NULL_TREE
&& values_equal_for_ipcp_p (src->val->value, t));
}
create_specialized_node (struct cgraph_node *node,
vec<tree> known_csts,
vec<ipa_polymorphic_call_context> known_contexts,
- struct ipa_agg_replacement_value *aggvals,
+ vec<ipa_argagg_value, va_gc> *aggvals,
vec<cgraph_edge *> &callers)
{
ipa_node_params *new_info, *info = ipa_node_params_sum->get (node);
vec<ipa_replace_map *, va_gc> *replace_trees = NULL;
vec<ipa_adjusted_param, va_gc> *new_params = NULL;
- struct ipa_agg_replacement_value *av;
struct cgraph_node *new_node;
int i, count = ipa_get_param_count (info);
clone_info *cinfo = clone_info::get (node);
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);
+ for (const ipa_argagg_value &av : aggvals)
+ new_node->maybe_create_reference (av.value, NULL);
if (dump_file && (dump_flags & TDF_DETAILS))
{
}
}
if (aggvals)
- ipa_dump_agg_replacement_values (dump_file, aggvals);
+ {
+ fprintf (dump_file, " Aggregate replacements:");
+ ipa_argagg_value_list avs (aggvals);
+ avs.dump (dump_file);
+ }
}
new_info = ipa_node_params_sum->get (new_node);
new_info->known_csts = known_csts;
new_info->known_contexts = known_contexts;
- ipcp_discover_new_direct_edges (new_node, known_csts, known_contexts, aggvals);
+ ipcp_discover_new_direct_edges (new_node, known_csts, known_contexts,
+ aggvals);
return new_node;
}
pass-through. */
static bool
-self_recursive_agg_pass_through_p (cgraph_edge *cs, ipa_agg_jf_item *jfunc,
+self_recursive_agg_pass_through_p (const cgraph_edge *cs,
+ const ipa_agg_jf_item *jfunc,
int i, bool simple = true)
{
enum availability availability;
}
}
-/* Go through PLATS and create a vector of values consisting of values and
- offsets (minus OFFSET) of lattices that contain only a single value. */
-
-static vec<ipa_agg_value>
-copy_plats_to_inter (class ipcp_param_lattices *plats, HOST_WIDE_INT offset)
-{
- vec<ipa_agg_value> res = vNULL;
-
- if (!plats->aggs || plats->aggs_contain_variable || plats->aggs_bottom)
- return vNULL;
-
- for (struct ipcp_agg_lattice *aglat = plats->aggs; aglat; aglat = aglat->next)
- if (aglat->is_single_const ())
- {
- struct ipa_agg_value ti;
- ti.offset = aglat->offset - offset;
- ti.value = aglat->values->value;
- res.safe_push (ti);
- }
- return res;
-}
-
-/* Intersect all values in INTER with single value lattices in PLATS (while
- subtracting OFFSET). */
-
-static void
-intersect_with_plats (class ipcp_param_lattices *plats,
- vec<ipa_agg_value> *inter,
- HOST_WIDE_INT offset)
-{
- struct ipcp_agg_lattice *aglat;
- struct ipa_agg_value *item;
- int k;
-
- if (!plats->aggs || plats->aggs_contain_variable || plats->aggs_bottom)
- {
- inter->release ();
- return;
- }
-
- aglat = plats->aggs;
- FOR_EACH_VEC_ELT (*inter, k, item)
- {
- bool found = false;
- if (!item->value)
- continue;
- while (aglat)
- {
- if (aglat->offset - offset > item->offset)
- break;
- if (aglat->offset - offset == item->offset)
- {
- if (aglat->is_single_const ())
- {
- tree value = aglat->values->value;
-
- if (values_equal_for_ipcp_p (item->value, value))
- found = true;
- }
- break;
- }
- aglat = aglat->next;
- }
- if (!found)
- item->value = NULL_TREE;
- }
-}
-
-/* Copy aggregate replacement values of NODE (which is an IPA-CP clone) to the
- vector result while subtracting OFFSET from the individual value offsets. */
-
-static vec<ipa_agg_value>
-agg_replacements_to_vector (struct cgraph_node *node, int index,
- HOST_WIDE_INT offset)
-{
- struct ipa_agg_replacement_value *av;
- vec<ipa_agg_value> res = vNULL;
-
- for (av = ipa_get_agg_replacements_for_node (node); av; av = av->next)
- if (av->index == index
- && (av->offset - offset) >= 0)
- {
- struct ipa_agg_value item;
- gcc_checking_assert (av->value);
- item.offset = av->offset - offset;
- item.value = av->value;
- res.safe_push (item);
- }
-
- return res;
-}
+/* Push all aggregate values coming along edge CS for parameter number INDEX to
+ RES. If INTERIM is non-NULL, it contains the current interim state of
+ collected aggregate values which can be used to compute values passed over
+ self-recursive edges.
-/* Intersect all values in INTER with those that we have already scheduled to
- be replaced in parameter number INDEX of NODE, which is an IPA-CP clone
- (while subtracting OFFSET). */
+ This basically one iteration of push_agg_values_from_edge over one
+ parameter, which allows for simpler early returns. */
static void
-intersect_with_agg_replacements (struct cgraph_node *node, int index,
- vec<ipa_agg_value> *inter,
- HOST_WIDE_INT offset)
+push_agg_values_for_index_from_edge (struct cgraph_edge *cs, int index,
+ vec<ipa_argagg_value> *res,
+ const ipa_argagg_value_list *interim)
{
- struct ipa_agg_replacement_value *srcvals;
- struct ipa_agg_value *item;
- int i;
+ bool agg_values_from_caller = false;
+ bool agg_jf_preserved = false;
+ unsigned unit_delta = UINT_MAX;
+ int src_idx = -1;
+ ipa_jump_func *jfunc = ipa_get_ith_jump_func (ipa_edge_args_sum->get (cs),
+ index);
- srcvals = ipa_get_agg_replacements_for_node (node);
- if (!srcvals)
+ if (jfunc->type == IPA_JF_PASS_THROUGH
+ && ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR)
{
- inter->release ();
- return;
+ agg_values_from_caller = true;
+ agg_jf_preserved = ipa_get_jf_pass_through_agg_preserved (jfunc);
+ src_idx = ipa_get_jf_pass_through_formal_id (jfunc);
+ unit_delta = 0;
}
-
- FOR_EACH_VEC_ELT (*inter, i, item)
+ else if (jfunc->type == IPA_JF_ANCESTOR
+ && ipa_get_jf_ancestor_agg_preserved (jfunc))
{
- struct ipa_agg_replacement_value *av;
- bool found = false;
- if (!item->value)
- continue;
- for (av = srcvals; av; av = av->next)
- {
- gcc_checking_assert (av->value);
- if (av->index == index
- && av->offset - offset == item->offset)
- {
- if (values_equal_for_ipcp_p (item->value, av->value))
- found = true;
- break;
- }
- }
- if (!found)
- item->value = NULL_TREE;
+ agg_values_from_caller = true;
+ agg_jf_preserved = true;
+ src_idx = ipa_get_jf_ancestor_formal_id (jfunc);
+ unit_delta = ipa_get_jf_ancestor_offset (jfunc) / BITS_PER_UNIT;
}
-}
-/* Intersect values in INTER with aggregate values that come along edge CS to
- parameter number INDEX and return it. If INTER does not actually exist yet,
- copy all incoming values to it. If we determine we ended up with no values
- whatsoever, return a released vector. */
-
-static vec<ipa_agg_value>
-intersect_aggregates_with_edge (struct cgraph_edge *cs, int index,
- vec<ipa_agg_value> inter)
-{
- struct ipa_jump_func *jfunc;
- jfunc = ipa_get_ith_jump_func (ipa_edge_args_sum->get (cs), index);
- if (jfunc->type == IPA_JF_PASS_THROUGH
- && ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR)
+ ipa_node_params *caller_info = ipa_node_params_sum->get (cs->caller);
+ if (agg_values_from_caller)
{
- ipa_node_params *caller_info = ipa_node_params_sum->get (cs->caller);
- int src_idx = ipa_get_jf_pass_through_formal_id (jfunc);
-
if (caller_info->ipcp_orig_node)
{
struct cgraph_node *orig_node = caller_info->ipcp_orig_node;
- class ipcp_param_lattices *orig_plats;
+ ipcp_transformation *ts
+ = ipcp_get_transformation_summary (cs->caller);
ipa_node_params *orig_info = ipa_node_params_sum->get (orig_node);
- orig_plats = ipa_get_parm_lattices (orig_info, src_idx);
- if (agg_pass_through_permissible_p (orig_plats, jfunc))
+ ipcp_param_lattices *orig_plats
+ = ipa_get_parm_lattices (orig_info, src_idx);
+ if (ts
+ && orig_plats->aggs
+ && (agg_jf_preserved || !orig_plats->aggs_by_ref))
{
- if (!inter.exists ())
- inter = agg_replacements_to_vector (cs->caller, src_idx, 0);
- else
- intersect_with_agg_replacements (cs->caller, src_idx,
- &inter, 0);
- return inter;
+ ipa_argagg_value_list src (ts);
+ src.push_adjusted_values (src_idx, index, unit_delta, res);
+ return;
}
}
else
{
- class ipcp_param_lattices *src_plats;
- src_plats = ipa_get_parm_lattices (caller_info, src_idx);
- if (agg_pass_through_permissible_p (src_plats, jfunc))
+ ipcp_param_lattices *src_plats
+ = ipa_get_parm_lattices (caller_info, src_idx);
+ if (src_plats->aggs
+ && !src_plats->aggs_bottom
+ && (agg_jf_preserved || !src_plats->aggs_by_ref))
{
- /* Currently we do not produce clobber aggregate jump
- functions, adjust when we do. */
- gcc_checking_assert (!jfunc->agg.items);
- if (!inter.exists ())
- inter = copy_plats_to_inter (src_plats, 0);
- else
- intersect_with_plats (src_plats, &inter, 0);
- return inter;
+ if (interim && self_recursive_pass_through_p (cs, jfunc, index))
+ {
+ interim->push_adjusted_values (src_idx, index, unit_delta,
+ res);
+ return;
+ }
+ if (!src_plats->aggs_contain_variable)
+ {
+ push_agg_values_from_plats (src_plats, index, unit_delta,
+ res);
+ return;
+ }
}
}
}
- else if (jfunc->type == IPA_JF_ANCESTOR
- && ipa_get_jf_ancestor_agg_preserved (jfunc))
- {
- ipa_node_params *caller_info = ipa_node_params_sum->get (cs->caller);
- int src_idx = ipa_get_jf_ancestor_formal_id (jfunc);
- class ipcp_param_lattices *src_plats;
- HOST_WIDE_INT delta = ipa_get_jf_ancestor_offset (jfunc);
- if (caller_info->ipcp_orig_node)
- {
- if (!inter.exists ())
- inter = agg_replacements_to_vector (cs->caller, src_idx, delta);
- else
- intersect_with_agg_replacements (cs->caller, src_idx, &inter,
- delta);
- }
- else
- {
- 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);
- if (!inter.exists ())
- inter = copy_plats_to_inter (src_plats, delta);
- else
- intersect_with_plats (src_plats, &inter, delta);
- }
- return inter;
- }
-
- if (jfunc->agg.items)
+ if (!jfunc->agg.items)
+ return;
+ bool first = true;
+ unsigned prev_unit_offset = 0;
+ for (const ipa_agg_jf_item &agg_jf : *jfunc->agg.items)
{
- ipa_node_params *caller_info = ipa_node_params_sum->get (cs->caller);
- struct ipa_agg_value *item;
- int k;
+ tree value, srcvalue;
+ /* Besides simple pass-through aggregate jump function, arithmetic
+ aggregate jump function could also bring same aggregate value as
+ parameter passed-in for self-feeding recursive call. For example,
- if (!inter.exists ())
- for (unsigned i = 0; i < jfunc->agg.items->length (); i++)
- {
- struct ipa_agg_jf_item *agg_item = &(*jfunc->agg.items)[i];
- tree value = ipa_agg_value_from_node (caller_info, cs->caller,
- agg_item);
- if (value)
- {
- struct ipa_agg_value agg_value;
+ fn (int *i)
+ {
+ int j = *i & 1;
+ fn (&j);
+ }
- agg_value.value = value;
- agg_value.offset = agg_item->offset;
- inter.safe_push (agg_value);
- }
- }
+ Given that *i is 0, recursive propagation via (*i & 1) also gets 0. */
+ if (interim
+ && self_recursive_agg_pass_through_p (cs, &agg_jf, index, false)
+ && (srcvalue = interim->get_value(index,
+ agg_jf.offset / BITS_PER_UNIT)))
+ value = ipa_get_jf_arith_result (agg_jf.value.pass_through.operation,
+ srcvalue,
+ agg_jf.value.pass_through.operand,
+ agg_jf.type);
else
- FOR_EACH_VEC_ELT (inter, k, item)
- {
- int l = 0;
- bool found = false;
-
- if (!item->value)
- continue;
-
- while ((unsigned) l < jfunc->agg.items->length ())
- {
- struct ipa_agg_jf_item *ti;
- ti = &(*jfunc->agg.items)[l];
- if (ti->offset > item->offset)
- break;
- if (ti->offset == item->offset)
- {
- tree value;
-
- /* Besides simple pass-through aggregate jump function,
- arithmetic aggregate jump function could also bring
- same aggregate value as parameter passed-in for
- self-feeding recursive call. For example,
-
- fn (int *i)
- {
- int j = *i & 1;
- fn (&j);
- }
-
- Given that *i is 0, recursive propagation via (*i & 1)
- also gets 0. */
- if (self_recursive_agg_pass_through_p (cs, ti, index,
- false))
- value = ipa_get_jf_arith_result (
- ti->value.pass_through.operation,
- item->value,
- ti->value.pass_through.operand,
- ti->type);
- else
- value = ipa_agg_value_from_node (caller_info,
- cs->caller, ti);
+ value = ipa_agg_value_from_node (caller_info, cs->caller,
+ &agg_jf);
+ if (value)
+ {
+ struct ipa_argagg_value iav;
+ iav.value = value;
+ iav.unit_offset = agg_jf.offset / BITS_PER_UNIT;
+ iav.index = index;
+ iav.by_ref = jfunc->agg.by_ref;
+
+ gcc_assert (first
+ || iav.unit_offset > prev_unit_offset);
+ prev_unit_offset = iav.unit_offset;
+ first = false;
- if (value && values_equal_for_ipcp_p (item->value, value))
- found = true;
- break;
- }
- l++;
- }
- if (!found)
- item->value = NULL;
- }
- }
- else
- {
- inter.release ();
- return vNULL;
+ res->safe_push (iav);
+ }
}
- return inter;
+ return;
}
-/* Look at edges in CALLERS and collect all known aggregate values that arrive
- from all of them. */
+/* Push all aggregate values coming along edge CS to RES. DEST_INFO is the
+ description of ultimate callee of CS or the one it was cloned from (the
+ summary where lattices are). If INTERIM is non-NULL, it contains the
+ current interim state of collected aggregate values which can be used to
+ compute values passed over self-recursive edges and to skip values which
+ clearly will not be part of intersection with INTERIM. */
-static struct ipa_agg_replacement_value *
-find_aggregate_values_for_callers_subset (struct cgraph_node *node,
- const vec<cgraph_edge *> &callers)
+static void
+push_agg_values_from_edge (struct cgraph_edge *cs,
+ ipa_node_params *dest_info,
+ vec<ipa_argagg_value> *res,
+ const ipa_argagg_value_list *interim)
{
- ipa_node_params *dest_info = ipa_node_params_sum->get (node);
- struct ipa_agg_replacement_value *res;
- struct ipa_agg_replacement_value **tail = &res;
- struct cgraph_edge *cs;
- int i, j, count = ipa_get_param_count (dest_info);
+ ipa_edge_args *args = ipa_edge_args_sum->get (cs);
+ if (!args)
+ return;
+
+ int count = MIN (ipa_get_param_count (dest_info),
+ ipa_get_cs_argument_count (args));
- FOR_EACH_VEC_ELT (callers, j, cs)
+ unsigned interim_index = 0;
+ for (int index = 0; index < count; index++)
{
- ipa_edge_args *args = ipa_edge_args_sum->get (cs);
- if (!args)
+ if (interim)
{
- count = 0;
- break;
+ while (interim_index < interim->m_elts.size ()
+ && interim->m_elts[interim_index].value
+ && interim->m_elts[interim_index].index < index)
+ interim_index++;
+ if (interim_index >= interim->m_elts.size ()
+ || interim->m_elts[interim_index].index > index)
+ continue;
}
- int c = ipa_get_cs_argument_count (args);
- if (c < count)
- count = c;
- }
- for (i = 0; i < count; i++)
- {
- struct cgraph_edge *cs;
- vec<ipa_agg_value> inter = vNULL;
- struct ipa_agg_value *item;
- class ipcp_param_lattices *plats = ipa_get_parm_lattices (dest_info, i);
- int j;
-
- /* Among other things, the following check should deal with all by_ref
- mismatches. */
+ ipcp_param_lattices *plats = ipa_get_parm_lattices (dest_info, index);
if (plats->aggs_bottom)
continue;
+ push_agg_values_for_index_from_edge (cs, index, res, interim);
+ }
+}
- FOR_EACH_VEC_ELT (callers, j, cs)
- {
- struct ipa_jump_func *jfunc
- = ipa_get_ith_jump_func (ipa_edge_args_sum->get (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 ())
- goto next_param;
- }
+/* Look at edges in CALLERS and collect all known aggregate values that arrive
+ from all of them. Return nullptr if there are none. */
- FOR_EACH_VEC_ELT (inter, j, item)
- {
- struct ipa_agg_replacement_value *v;
+static struct vec<ipa_argagg_value, va_gc> *
+find_aggregate_values_for_callers_subset (struct cgraph_node *node,
+ const vec<cgraph_edge *> &callers)
+{
+ ipa_node_params *dest_info = ipa_node_params_sum->get (node);
+ if (dest_info->ipcp_orig_node)
+ dest_info = ipa_node_params_sum->get (dest_info->ipcp_orig_node);
- if (!item->value)
- continue;
+ /* gather_edges_for_value puts a non-recursive call into the first element of
+ callers if it can. */
+ auto_vec<ipa_argagg_value, 32> interim;
+ push_agg_values_from_edge (callers[0], dest_info, &interim, NULL);
- v = ggc_alloc<ipa_agg_replacement_value> ();
- v->index = i;
- v->offset = item->offset;
- v->value = item->value;
- v->by_ref = plats->aggs_by_ref;
- *tail = v;
- tail = &v->next;
- }
+ unsigned valid_entries = interim.length ();
+ if (!valid_entries)
+ return nullptr;
+
+ unsigned caller_count = callers.length();
+ for (unsigned i = 1; i < caller_count; i++)
+ {
+ auto_vec<ipa_argagg_value, 32> last;
+ ipa_argagg_value_list avs (&interim);
+ push_agg_values_from_edge (callers[i], dest_info, &last, &avs);
- next_param:
- if (inter.exists ())
- inter.release ();
+ valid_entries = intersect_argaggs_with (interim, last);
+ if (!valid_entries)
+ return nullptr;
}
- *tail = NULL;
+
+ vec<ipa_argagg_value, va_gc> *res = NULL;
+ vec_safe_reserve_exact (res, valid_entries);
+ for (const ipa_argagg_value &av : interim)
+ if (av.value)
+ res->quick_push(av);
+ gcc_checking_assert (res->length () == valid_entries);
return res;
}
/* Determine whether CS also brings all aggregate values that NODE is
specialized for. */
+
static bool
cgraph_edge_brings_all_agg_vals_for_node (struct cgraph_edge *cs,
struct cgraph_node *node)
{
- struct ipa_agg_replacement_value *aggval;
- int i, ec, count;
-
- aggval = ipa_get_agg_replacements_for_node (node);
- if (!aggval)
+ ipcp_transformation *ts = ipcp_get_transformation_summary (node);
+ if (!ts || vec_safe_is_empty (ts->m_agg_values))
return true;
- ipa_node_params *clone_node_info = ipa_node_params_sum->get (node);
- count = ipa_get_param_count (clone_node_info);
- ec = ipa_get_cs_argument_count (ipa_edge_args_sum->get (cs));
- if (ec < count)
- for (struct ipa_agg_replacement_value *av = aggval; av; av = av->next)
- if (aggval->index >= ec)
- return false;
-
- ipa_node_params *orig_node_info
- = ipa_node_params_sum->get (clone_node_info->ipcp_orig_node);
-
- for (i = 0; i < count; i++)
- {
- class ipcp_param_lattices *plats;
- bool interesting = false;
- for (struct ipa_agg_replacement_value *av = aggval; av; av = av->next)
- if (aggval->index == i)
- {
- interesting = true;
- break;
- }
- if (!interesting)
- continue;
-
- plats = ipa_get_parm_lattices (orig_node_info, aggval->index);
- if (plats->aggs_bottom)
- return false;
-
- vec<ipa_agg_value> values = intersect_aggregates_with_edge (cs, i, vNULL);
- if (!values.exists ())
- return false;
-
- for (struct ipa_agg_replacement_value *av = aggval; av; av = av->next)
- if (aggval->index == i)
- {
- struct ipa_agg_value *item;
- int j;
- bool found = false;
- FOR_EACH_VEC_ELT (values, j, item)
- if (item->value
- && item->offset == av->offset
- && values_equal_for_ipcp_p (item->value, av->value))
- {
- found = true;
- break;
- }
- if (!found)
- {
- values.release ();
- return false;
- }
- }
- values.release ();
- }
- return true;
+ const ipa_argagg_value_list existing (ts->m_agg_values);
+ auto_vec<ipa_argagg_value, 32> edge_values;
+ ipa_node_params *dest_info = ipa_node_params_sum->get (node);
+ gcc_checking_assert (dest_info->ipcp_orig_node);
+ dest_info = ipa_node_params_sum->get (dest_info->ipcp_orig_node);
+ push_agg_values_from_edge (cs, dest_info, &edge_values, &existing);
+ const ipa_argagg_value_list avl (&edge_values);
+ return avl.superset_of_p (existing);
}
/* Given an original NODE and a VAL for which we have already created a
AGGVALS list. */
DEBUG_FUNCTION bool
-ipcp_val_agg_replacement_ok_p (ipa_agg_replacement_value *aggvals,
+ipcp_val_agg_replacement_ok_p (vec<ipa_argagg_value, va_gc> *aggvals,
int index, HOST_WIDE_INT offset, tree value)
{
if (offset == -1)
return true;
- while (aggvals)
- {
- if (aggvals->index == index
- && aggvals->offset == offset
- && values_equal_for_ipcp_p (aggvals->value, value))
- return true;
- aggvals = aggvals->next;
- }
- return false;
+ const ipa_argagg_value_list avl (aggvals);
+ tree v = avl.get_value (index, offset / BITS_PER_UNIT);
+ return v && values_equal_for_ipcp_p (v, value);
}
/* Return true if offset is minus one because source of a polymorphic context
cannot be an aggregate value. */
DEBUG_FUNCTION bool
-ipcp_val_agg_replacement_ok_p (ipa_agg_replacement_value *,
+ipcp_val_agg_replacement_ok_p (vec<ipa_argagg_value, va_gc> *,
int , HOST_WIDE_INT offset,
ipa_polymorphic_call_context)
{
ipcp_value<valtype> *val, ipa_auto_call_arg_values *avals,
vec<cgraph_node *> *self_gen_clones)
{
- struct ipa_agg_replacement_value *aggvals;
int caller_count;
sreal freq_sum;
profile_count count_sum, rec_count_sum;
}
find_more_scalar_values_for_callers_subset (node, known_csts, callers);
find_more_contexts_for_caller_subset (node, &known_contexts, callers);
- aggvals = find_aggregate_values_for_callers_subset (node, callers);
+ vec<ipa_argagg_value, va_gc> *aggvals
+ = find_aggregate_values_for_callers_subset (node, callers);
gcc_checking_assert (ipcp_val_agg_replacement_ok_p (aggvals, index,
offset, val->value));
val->spec_node = create_specialized_node (node, known_csts, 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
+ vec<ipa_argagg_value, va_gc> *aggvals
= find_aggregate_values_for_callers_subset (node, callers);
if (!known_contexts_useful_p (known_contexts))
latter can be NULL), STMT is the load statement. If function returns true,
*INDEX_P, *OFFSET_P and *BY_REF is filled with the parameter index, offset
within the aggregate and whether it is a load from a value passed by
- reference respectively. */
+ reference respectively.
+
+ Return false if the offset divided by BITS_PER_UNIT would not fit into an
+ unsigned int. */
bool
ipa_load_from_parm_agg (struct ipa_func_body_info *fbi,
bool reverse;
tree base = get_ref_base_and_extent_hwi (op, offset_p, &size, &reverse);
- if (!base)
+ if (!base
+ || (*offset_p / BITS_PER_UNIT) > UINT_MAX)
return false;
/* We can not propagate across volatile loads. */
return;
info->analysis_done = 1;
- if (ipa_func_spec_opts_forbid_analysis_p (node))
+ if (ipa_func_spec_opts_forbid_analysis_p (node)
+ || (count_formal_params (node->decl)
+ >= (1 << IPA_PROP_ARG_INDEX_LIMIT_BITS)))
{
- for (int i = 0; i < ipa_get_param_count (info); i++)
- {
- ipa_set_param_used (info, i, true);
- ipa_set_controlled_uses (info, i, IPA_UNDESCRIBED_USE);
- }
+ gcc_assert (!ipa_get_param_count (info));
return;
}
void
ipa_set_node_agg_value_chain (struct cgraph_node *node,
- struct ipa_agg_replacement_value *aggvals)
+ vec<ipa_argagg_value, va_gc> *aggs)
{
ipcp_transformation_initialize ();
ipcp_transformation *s = ipcp_transformation_sum->get_create (node);
- s->agg_values = aggvals;
+ s->m_agg_values = aggs;
}
/* Hook that is called by cgraph.cc when an edge is removed. Adjust reference
/* Hook that is called by summary when a node is duplicated. */
void
-ipa_node_params_t::duplicate(cgraph_node *src, cgraph_node *dst,
+ipa_node_params_t::duplicate(cgraph_node *, cgraph_node *,
ipa_node_params *old_info,
ipa_node_params *new_info)
{
- ipa_agg_replacement_value *old_av, *new_av;
-
new_info->descriptors = vec_safe_copy (old_info->descriptors);
new_info->lattices = NULL;
new_info->ipcp_orig_node = old_info->ipcp_orig_node;
new_info->analysis_done = old_info->analysis_done;
new_info->node_enqueued = old_info->node_enqueued;
new_info->versionable = old_info->versionable;
-
- old_av = ipa_get_agg_replacements_for_node (src);
- if (old_av)
- {
- 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;
- }
- ipa_set_node_agg_value_chain (dst, new_av);
- }
}
/* Duplication of ipcp transformation summaries. */
/* Avoid redundant work of duplicating vectors we will never use. */
if (dst->inlined_to)
return;
+ dst_trans->m_agg_values = vec_safe_copy (src_trans->m_agg_values);
dst_trans->bits = vec_safe_copy (src_trans->bits);
dst_trans->m_vr = vec_safe_copy (src_trans->m_vr);
- ipa_agg_replacement_value *agg = src_trans->agg_values,
- **aggptr = &dst_trans->agg_values;
- while (agg)
- {
- *aggptr = ggc_alloc<ipa_agg_replacement_value> ();
- **aggptr = *agg;
- agg = agg->next;
- aggptr = &(*aggptr)->next;
- }
}
/* Register our cgraph hooks if they are not already there. */
ipa_print_node_params (f, node);
}
-/* Dump the AV linked list. */
-
-void
-ipa_dump_agg_replacement_values (FILE *f, struct ipa_agg_replacement_value *av)
-{
- bool comma = false;
- fprintf (f, " Aggregate replacements:");
- for (; av; av = av->next)
- {
- fprintf (f, "%s %i[" HOST_WIDE_INT_PRINT_DEC "]=", comma ? "," : "",
- av->index, av->offset);
- print_generic_expr (f, av->value);
- comma = true;
- }
- fprintf (f, "\n");
-}
-
/* Stream out jump function JUMP_FUNC to OB. */
static void
int node_ref;
unsigned int count = 0;
lto_symtab_encoder_t encoder;
- struct ipa_agg_replacement_value *aggvals, *av;
- aggvals = ipa_get_agg_replacements_for_node (node);
encoder = ob->decl_state->symtab_node_encoder;
node_ref = lto_symtab_encoder_encode (encoder, node);
streamer_write_uhwi (ob, node_ref);
- for (av = aggvals; av; av = av->next)
- count++;
- streamer_write_uhwi (ob, count);
-
- for (av = aggvals; av; av = av->next)
+ ipcp_transformation *ts = ipcp_get_transformation_summary (node);
+ if (ts && !vec_safe_is_empty (ts->m_agg_values))
{
- struct bitpack_d bp;
+ streamer_write_uhwi (ob, ts->m_agg_values->length ());
+ for (const ipa_argagg_value &av : ts->m_agg_values)
+ {
+ struct bitpack_d bp;
- streamer_write_uhwi (ob, av->offset);
- streamer_write_uhwi (ob, av->index);
- stream_write_tree (ob, av->value, true);
+ stream_write_tree (ob, av.value, true);
+ streamer_write_uhwi (ob, av.unit_offset);
+ streamer_write_uhwi (ob, av.index);
- bp = bitpack_create (ob->main_stream);
- bp_pack_value (&bp, av->by_ref, 1);
- streamer_write_bitpack (&bp);
+ bp = bitpack_create (ob->main_stream);
+ bp_pack_value (&bp, av.by_ref, 1);
+ streamer_write_bitpack (&bp);
+ }
}
+ else
+ streamer_write_uhwi (ob, 0);
- ipcp_transformation *ts = ipcp_get_transformation_summary (node);
if (ts && vec_safe_length (ts->m_vr) > 0)
{
count = ts->m_vr->length ();
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;
count = streamer_read_uhwi (ib);
- for (i = 0; i <count; i++)
- {
- struct ipa_agg_replacement_value *av;
- struct bitpack_d bp;
-
- av = ggc_alloc<ipa_agg_replacement_value> ();
- av->offset = streamer_read_uhwi (ib);
- av->index = streamer_read_uhwi (ib);
- av->value = stream_read_tree (ib, data_in);
- bp = streamer_read_bitpack (ib);
- av->by_ref = bp_unpack_value (&bp, 1);
- av->next = aggvals;
- aggvals = av;
- }
- ipa_set_node_agg_value_chain (node, aggvals);
-
+ if (count > 0)
+ {
+ ipcp_transformation_initialize ();
+ ipcp_transformation *ts = ipcp_transformation_sum->get_create (node);
+ vec_safe_grow_cleared (ts->m_agg_values, count, true);
+ for (i = 0; i <count; i++)
+ {
+ ipa_argagg_value *av = &(*ts->m_agg_values)[i];;
+
+ av->value = stream_read_tree (ib, data_in);
+ av->unit_offset = streamer_read_uhwi (ib);
+ av->index = streamer_read_uhwi (ib);
+
+ bitpack_d bp = streamer_read_bitpack (ib);
+ av->by_ref = bp_unpack_value (&bp, 1);
+ }
+ }
+
count = streamer_read_uhwi (ib);
if (count > 0)
{
}
}
-/* Adjust the aggregate replacements in AGGVAL to reflect parameters skipped in
+/* Adjust the aggregate replacements in TS to reflect parameters skipped in
NODE but also if any parameter was IPA-SRAed into a scalar go ahead with
substitution of the default_definitions of that new param with the
appropriate constant.
- Return two bools. the first it true if at least one item in AGGVAL still
- exists and function body walk should go ahead. The second is true if any
- values were already substituted for scalarized parameters and update_cfg
- shuld be run after replace_uses_by. */
+ If after adjustments there are no aggregate replacements left, the
+ m_agg_values will be set to NULL. In other cases, it may be shrunk.
+
+ Return true if any values were already substituted for scalarized parameters
+ and update_cfg shuld be run after replace_uses_by. */
-static std::pair<bool, bool>
+static bool
adjust_agg_replacement_values (cgraph_node *node,
- ipa_agg_replacement_value *aggval,
+ ipcp_transformation *ts,
const vec<ipa_param_descriptor, va_gc>
&descriptors)
{
- struct ipa_agg_replacement_value *v;
clone_info *cinfo = clone_info::get (node);
if (!cinfo || !cinfo->param_adjustments)
- return std::pair<bool, bool> (true, false);
+ return false;
- bool anything_left = false;
+ bool removed_item = false;
bool done_replacement = false;
- for (v = aggval; v; v = v->next)
+ unsigned dst_index = 0;
+ unsigned count = ts->m_agg_values->length ();
+ for (unsigned i = 0; i < count; i++)
{
+ ipa_argagg_value *v = &(*ts->m_agg_values)[i];
gcc_checking_assert (v->index >= 0);
- unsigned unit_offset = v->offset / BITS_PER_UNIT;
tree cst_type = TREE_TYPE (v->value);
int split_idx;
int new_idx
= cinfo->param_adjustments->get_updated_index_or_split (v->index,
- unit_offset,
+ v->unit_offset,
cst_type,
&split_idx);
- v->index = new_idx;
if (new_idx >= 0)
- anything_left = true;
- else if (split_idx >= 0)
{
- tree parm = ipa_get_param (descriptors, split_idx);
- tree ddef = ssa_default_def (cfun, parm);
- if (ddef)
+ v->index = new_idx;
+ if (removed_item)
+ (*ts->m_agg_values)[dst_index] = *v;
+ dst_index++;
+ }
+ else
+ {
+ removed_item = true;
+ if (split_idx >= 0)
{
- replace_uses_by (ddef, v->value);
- done_replacement = true;
+ tree parm = ipa_get_param (descriptors, split_idx);
+ tree ddef = ssa_default_def (cfun, parm);
+ if (ddef)
+ {
+ replace_uses_by (ddef, v->value);
+ done_replacement = true;
+ }
}
}
}
- return std::pair<bool, bool> (anything_left, done_replacement);
+
+ if (dst_index == 0)
+ {
+ ggc_free (ts->m_agg_values);
+ ts->m_agg_values = NULL;
+ }
+ else if (removed_item)
+ ts->m_agg_values->truncate (dst_index);
+
+ return done_replacement;
}
/* Dominator walker driving the ipcp modification phase. */
public:
ipcp_modif_dom_walker (struct ipa_func_body_info *fbi,
vec<ipa_param_descriptor, va_gc> *descs,
- struct ipa_agg_replacement_value *av,
- bool *sc)
+ ipcp_transformation *ts, bool *sc)
: dom_walker (CDI_DOMINATORS), m_fbi (fbi), m_descriptors (descs),
- m_aggval (av), m_something_changed (sc) {}
+ m_ts (ts), m_something_changed (sc) {}
edge before_dom_children (basic_block) final override;
bool cleanup_eh ()
private:
struct ipa_func_body_info *m_fbi;
vec<ipa_param_descriptor, va_gc> *m_descriptors;
- struct ipa_agg_replacement_value *m_aggval;
+ ipcp_transformation *m_ts;
bool *m_something_changed;
auto_bitmap m_need_eh_cleanup;
};
gimple_stmt_iterator gsi;
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
{
- struct ipa_agg_replacement_value *v;
gimple *stmt = gsi_stmt (gsi);
tree rhs, val, t;
- HOST_WIDE_INT offset;
+ HOST_WIDE_INT bit_offset;
poly_int64 size;
int index;
bool by_ref, vce;
continue;
if (!ipa_load_from_parm_agg (m_fbi, m_descriptors, stmt, rhs, &index,
- &offset, &size, &by_ref))
+ &bit_offset, &size, &by_ref))
continue;
- for (v = m_aggval; v; v = v->next)
- if (v->index == index
- && v->offset == offset)
- break;
+ unsigned unit_offset = bit_offset / BITS_PER_UNIT;
+ ipa_argagg_value_list avl (m_ts);
+ tree v = avl.get_value (index, unit_offset, by_ref);
+
if (!v
- || v->by_ref != by_ref
- || maybe_ne (tree_to_poly_int64 (TYPE_SIZE (TREE_TYPE (v->value))),
- size))
+ || maybe_ne (tree_to_poly_int64 (TYPE_SIZE (TREE_TYPE (v))), size))
continue;
- gcc_checking_assert (is_gimple_ip_invariant (v->value));
- if (!useless_type_conversion_p (TREE_TYPE (rhs), TREE_TYPE (v->value)))
+ gcc_checking_assert (is_gimple_ip_invariant (v));
+ if (!useless_type_conversion_p (TREE_TYPE (rhs), TREE_TYPE (v)))
{
- if (fold_convertible_p (TREE_TYPE (rhs), v->value))
- val = fold_build1 (NOP_EXPR, TREE_TYPE (rhs), v->value);
+ if (fold_convertible_p (TREE_TYPE (rhs), v))
+ val = fold_build1 (NOP_EXPR, TREE_TYPE (rhs), v);
else if (TYPE_SIZE (TREE_TYPE (rhs))
- == TYPE_SIZE (TREE_TYPE (v->value)))
- val = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (rhs), v->value);
+ == TYPE_SIZE (TREE_TYPE (v)))
+ val = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (rhs), v);
else
{
if (dump_file)
{
fprintf (dump_file, " const ");
- print_generic_expr (dump_file, v->value);
+ print_generic_expr (dump_file, v);
fprintf (dump_file, " can't be converted to type of ");
print_generic_expr (dump_file, rhs);
fprintf (dump_file, "\n");
}
}
else
- val = v->value;
+ val = v;
if (dump_file && (dump_flags & TDF_DETAILS))
{
{
vec<ipa_param_descriptor, va_gc> *descriptors = NULL;
struct ipa_func_body_info fbi;
- struct ipa_agg_replacement_value *aggval;
int param_count;
gcc_checking_assert (cfun);
ipcp_update_bits (node);
ipcp_update_vr (node);
- aggval = ipa_get_agg_replacements_for_node (node);
- if (!aggval)
+ ipcp_transformation *ts = ipcp_get_transformation_summary (node);
+ if (!ts || vec_safe_is_empty (ts->m_agg_values))
return 0;
param_count = count_formal_params (node->decl);
if (param_count == 0)
return 0;
vec_safe_grow_cleared (descriptors, param_count, true);
ipa_populate_param_decls (node, *descriptors);
- std::pair<bool, bool> rr
- = adjust_agg_replacement_values (node, aggval, *descriptors);
- bool cfg_changed = rr.second;
- if (!rr.first)
+
+ bool cfg_changed = adjust_agg_replacement_values (node, ts, *descriptors);
+ if (vec_safe_is_empty (ts->m_agg_values))
{
vec_free (descriptors);
if (dump_file)
return 0;
}
if (dump_file)
- ipa_dump_agg_replacement_values (dump_file, aggval);
+ {
+ fprintf (dump_file, " Aggregate replacements:");
+ ipa_argagg_value_list avs (ts);
+ avs.dump (dump_file);
+ }
fbi.node = node;
fbi.info = NULL;
bool modified_mem_access = false;
calculate_dominance_info (CDI_DOMINATORS);
- ipcp_modif_dom_walker walker (&fbi, descriptors, aggval, &modified_mem_access);
+ ipcp_modif_dom_walker walker (&fbi, descriptors, ts, &modified_mem_access);
walker.walk (ENTRY_BLOCK_PTR_FOR_FN (cfun));
free_dominance_info (CDI_DOMINATORS);
cfg_changed |= walker.cleanup_eh ();
fbi.bb_infos.release ();
ipcp_transformation *s = ipcp_transformation_sum->get (node);
- s->agg_values = NULL;
+ s->m_agg_values = NULL;
s->bits = NULL;
s->m_vr = NULL;