aboutsummaryrefslogtreecommitdiff
path: root/gcc/ipa-cp.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/ipa-cp.c')
-rw-r--r--gcc/ipa-cp.c243
1 files changed, 243 insertions, 0 deletions
diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
index 60fcd02..cb60f1e 100644
--- a/gcc/ipa-cp.c
+++ b/gcc/ipa-cp.c
@@ -114,6 +114,7 @@ along with GCC; see the file COPYING3. If not see
#include "fold-const.h"
#include "gimple-fold.h"
#include "symbol-summary.h"
+#include "tree-vrp.h"
#include "ipa-prop.h"
#include "tree-pretty-print.h"
#include "tree-inline.h"
@@ -321,6 +322,25 @@ private:
void get_value_and_mask (tree, widest_int *, widest_int *);
};
+/* Lattice of value ranges. */
+
+class ipcp_vr_lattice
+{
+public:
+ value_range m_vr;
+
+ inline bool bottom_p () const;
+ inline bool top_p () const;
+ inline bool set_to_bottom ();
+ bool meet_with (const value_range *p_vr);
+ bool meet_with (const ipcp_vr_lattice &other);
+ void init () { m_vr.type = VR_UNDEFINED; }
+ void print (FILE * f);
+
+private:
+ bool meet_with_1 (const value_range *other_vr);
+};
+
/* Structure containing lattices for a parameter itself and for pieces of
aggregates that are passed in the parameter or by a reference in a parameter
plus some other useful flags. */
@@ -338,6 +358,8 @@ public:
ipcp_alignment_lattice alignment;
/* Lattice describing known bits. */
ipcp_bits_lattice bits_lattice;
+ /* Lattice describing value range. */
+ ipcp_vr_lattice m_value_range;
/* Number of aggregate lattices */
int aggs_count;
/* True if aggregate data were passed by reference (as opposed to by
@@ -405,6 +427,16 @@ ipa_get_poly_ctx_lat (struct ipa_node_params *info, int i)
return &plats->ctxlat;
}
+/* Return the lattice corresponding to the value range of the Ith formal
+ parameter of the function described by INFO. */
+
+static inline ipcp_vr_lattice *
+ipa_get_vr_lat (struct ipa_node_params *info, int i)
+{
+ struct ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
+ return &plats->m_value_range;
+}
+
/* Return whether LAT is a lattice with a single constant and without an
undefined value. */
@@ -530,6 +562,14 @@ ipcp_bits_lattice::print (FILE *f)
}
}
+/* Print value range lattice to F. */
+
+void
+ipcp_vr_lattice::print (FILE * f)
+{
+ dump_value_range (f, &m_vr);
+}
+
/* Print all ipcp_lattices of all functions to F. */
static void
@@ -557,6 +597,9 @@ print_all_lattices (FILE * f, bool dump_sources, bool dump_benefits)
plats->ctxlat.print (f, dump_sources, dump_benefits);
plats->alignment.print (f);
plats->bits_lattice.print (f);
+ fprintf (f, " ");
+ plats->m_value_range.print (f);
+ fprintf (f, "\n");
if (plats->virt_call)
fprintf (f, " virt_call flag set\n");
@@ -908,6 +951,77 @@ ipcp_alignment_lattice::set_to_bottom ()
return true;
}
+/* Meet the current value of the lattice with described by OTHER
+ lattice. */
+
+bool
+ipcp_vr_lattice::meet_with (const ipcp_vr_lattice &other)
+{
+ return meet_with_1 (&other.m_vr);
+}
+
+/* Meet the current value of the lattice with value ranfge described by VR
+ lattice. */
+
+bool
+ipcp_vr_lattice::meet_with (const value_range *p_vr)
+{
+ return meet_with_1 (p_vr);
+}
+
+/* Meet the current value of the lattice with value ranfge described by
+ OTHER_VR lattice. */
+
+bool
+ipcp_vr_lattice::meet_with_1 (const value_range *other_vr)
+{
+ tree min = m_vr.min, max = m_vr.max;
+ value_range_type type = m_vr.type;
+
+ if (bottom_p ())
+ return false;
+
+ if (other_vr->type == VR_VARYING)
+ return set_to_bottom ();
+
+ vrp_meet (&m_vr, other_vr);
+ if (type != m_vr.type
+ || min != m_vr.min
+ || max != m_vr.max)
+ return true;
+ else
+ return false;
+}
+
+/* Return true if value range information in the lattice is yet unknown. */
+
+bool
+ipcp_vr_lattice::top_p () const
+{
+ return m_vr.type == VR_UNDEFINED;
+}
+
+/* Return true if value range information in the lattice is known to be
+ unusable. */
+
+bool
+ipcp_vr_lattice::bottom_p () const
+{
+ return m_vr.type == VR_VARYING;
+}
+
+/* Set value range information in the lattice to bottom. Return true if it
+ previously was in a different state. */
+
+bool
+ipcp_vr_lattice::set_to_bottom ()
+{
+ if (m_vr.type == VR_VARYING)
+ return false;
+ m_vr.type = VR_VARYING;
+ return true;
+}
+
/* Meet the current value of the lattice with alignment described by NEW_ALIGN
and NEW_MISALIGN, assuming that we know the current value is neither TOP nor
BOTTOM. Return true if the value of lattice has changed. */
@@ -1141,6 +1255,7 @@ set_all_contains_variable (struct ipcp_param_lattices *plats)
ret |= set_agg_lats_contain_variable (plats);
ret |= plats->alignment.set_to_bottom ();
ret |= plats->bits_lattice.set_to_bottom ();
+ ret |= plats->m_value_range.set_to_bottom ();
return ret;
}
@@ -1211,6 +1326,12 @@ initialize_node_lattices (struct cgraph_node *node)
disable = true;
}
+ for (i = 0; i < ipa_get_param_count (info) ; i++)
+ {
+ struct ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
+ plats->m_value_range.init ();
+ }
+
if (disable || variable)
{
for (i = 0; i < ipa_get_param_count (info) ; i++)
@@ -1223,6 +1344,7 @@ initialize_node_lattices (struct cgraph_node *node)
set_agg_lats_to_bottom (plats);
plats->alignment.set_to_bottom ();
plats->bits_lattice.set_to_bottom ();
+ plats->m_value_range.set_to_bottom ();
}
else
set_all_contains_variable (plats);
@@ -1913,6 +2035,50 @@ propagate_bits_accross_jump_function (cgraph_edge *cs, int idx, ipa_jump_func *j
return dest_lattice->set_to_bottom ();
}
+/* Propagate value range across jump function JFUNC that is associated with
+ edge CS and update DEST_PLATS accordingly. */
+
+static bool
+propagate_vr_accross_jump_function (cgraph_edge *cs,
+ ipa_jump_func *jfunc,
+ struct ipcp_param_lattices *dest_plats)
+{
+ struct ipcp_param_lattices *src_lats;
+ ipcp_vr_lattice *dest_lat = &dest_plats->m_value_range;
+
+ if (dest_lat->bottom_p ())
+ return false;
+
+ if (jfunc->type == IPA_JF_PASS_THROUGH)
+ {
+ struct ipa_node_params *caller_info = IPA_NODE_REF (cs->caller);
+ if (dest_lat->bottom_p ())
+ return false;
+ int src_idx = ipa_get_jf_pass_through_formal_id (jfunc);
+ src_lats = ipa_get_parm_lattices (caller_info, src_idx);
+
+ if (ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR)
+ return dest_lat->meet_with (src_lats->m_value_range);
+ }
+ else if (jfunc->type == IPA_JF_CONST)
+ {
+ tree val = ipa_get_jf_constant (jfunc);
+ if (TREE_CODE (val) == INTEGER_CST)
+ {
+ 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);
+ }
+ }
+
+ if (jfunc->vr_known)
+ return dest_lat->meet_with (&jfunc->m_vr);
+ else
+ return dest_lat->set_to_bottom ();
+}
+
/* 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
@@ -2264,6 +2430,11 @@ propagate_constants_accross_call (struct cgraph_edge *cs)
&dest_plats->bits_lattice);
ret |= propagate_aggs_accross_jump_function (cs, jump_func,
dest_plats);
+ if (opt_for_fn (callee->decl, flag_ipa_vrp))
+ ret |= propagate_vr_accross_jump_function (cs,
+ jump_func, dest_plats);
+ else
+ ret |= dest_plats->m_value_range.set_to_bottom ();
}
}
for (; i < parms_count; i++)
@@ -4974,6 +5145,76 @@ ipcp_store_bits_results (void)
}
}
}
+
+/* Look up all VR information that we have discovered and copy it over
+ to the transformation summary. */
+
+static void
+ipcp_store_vr_results (void)
+{
+ cgraph_node *node;
+
+ FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
+ {
+ ipa_node_params *info = IPA_NODE_REF (node);
+ bool found_useful_result = false;
+
+ if (!opt_for_fn (node->decl, flag_ipa_vrp))
+ {
+ if (dump_file)
+ fprintf (dump_file, "Not considering %s for VR discovery "
+ "and propagate; -fipa-ipa-vrp: disabled.\n",
+ node->name ());
+ continue;
+ }
+
+ 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->m_value_range.bottom_p ()
+ && !plats->m_value_range.top_p ())
+ {
+ 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->m_vr, count);
+
+ for (unsigned i = 0; i < count ; i++)
+ {
+ ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
+ ipa_vr vr;
+
+ if (!plats->m_value_range.bottom_p ()
+ && !plats->m_value_range.top_p ())
+ {
+ vr.known = true;
+ vr.type = plats->m_value_range.m_vr.type;
+ vr.min = plats->m_value_range.m_vr.min;
+ vr.max = plats->m_value_range.m_vr.max;
+ }
+ else
+ {
+ static wide_int zero = integer_zero_node;
+ vr.known = false;
+ vr.type = VR_VARYING;
+ vr.min = zero;
+ vr.max = zero;
+ }
+ ts->m_vr->quick_push (vr);
+ }
+ }
+}
+
/* The IPCP driver. */
static unsigned int
@@ -5009,6 +5250,8 @@ ipcp_driver (void)
ipcp_store_alignment_results ();
/* Store results of bits propagation. */
ipcp_store_bits_results ();
+ /* Store results of value range propagation. */
+ ipcp_store_vr_results ();
/* Free all IPCP structures. */
free_toporder_info (&topo);