ipa vrp implementation in gcc

kugan kugan.vivekanandarajah@linaro.org
Wed Feb 10 03:49:00 GMT 2016



On 19/01/16 04:10, Jan Hubicka wrote:
> In general, given that we have existing VRP implementation I would suggest
> first implementing the IPA propagation and profile estimation bits using
> existing VRP pass and then try to compare the simple dominator based approach
> with the VRP we have and see what are the compile time/code quality effects
> of both. Based on that we can decide how complex VRP we really want.
>
> It will be probably also more fun to implement it this way:)
> I plan to collect some data on early VRP and firefox today or tomorrow.


Thanks. I started experimenting with it. Prototype patch is attached. I 
haven't tested it in any detailed way yet. This is just to understand 
the LTO and see how we can implement it.


I wanted to set the value range to parameter based on the ipa-vrp. For 
example:

extern void foo (int);

void bar (unsigned long l)
{
   foo(l == 0);
}

void bar2 (unsigned long l)
{
   foo(l & 0x2);
}


unsigned long x;

int main()
{
   x = 0;
   bar (x);
   x = 1;
   bar (x);
   x = 3;
   bar2 (x);
   x = 5;
   bar2 (x);
}


In the above case, I wanted value range of the ssa_name that gets 
initialized to [0,2]. As can be seen from the ipa-cp dump (attached), 
this is now happening. Any comments ? I also have some questions:


1.I think even if we are not going to use the tree-vrp for 
intra-procedural value range propagation, we can factor out some of the 
routines and share it. Any thoughts on this?


2. Is the DOM based intra-procedural prototype Richard Biener 
implemented available anywhere. Can you please point me to that.


Thanks,
Kugan


-------------- next part --------------

IPA structures before propagation:

Function parameters:
  function  foo/6 parameter descriptors:
    param #0 used undescribed_use
  function  main/3 parameter descriptors:
  function  bar2/1 parameter descriptors:
    param #0 used undescribed_use
  function  bar/0 parameter descriptors:
    param #0 used undescribed_use

Jump functions:
  Jump functions of caller  __builtin_puts/7:
  Jump functions of caller  foo/6:
    callsite  foo/6 -> __builtin_puts/7 : 
       param 0: CONST: &"test"[0]
         Alignment: 1, misalignment: 0
  Jump functions of caller  main/3:
    callsite  main/3 -> foo/6 : 
       param 0: CONST: 0
         Unknown alignment
    callsite  main/3 -> foo/6 : 
       param 0: CONST: 2
         Unknown alignment
    callsite  main/3 -> foo/6 : 
       param 0: CONST: 0
         Unknown alignment
    callsite  main/3 -> foo/6 : 
       param 0: CONST: 1
         Unknown alignment
  Jump functions of caller  bar2/1:
    callsite  bar2/1 -> foo/6 : 
       param 0: UNKNOWN
         Unknown alignment
  Jump functions of caller  bar/0:
    callsite  bar/0 -> foo/6 : 
       param 0: UNKNOWN
         Unknown alignment

 Propagating constants:

Not considering foo for cloning; -fipa-cp-clone disabled.
Marking all lattices of foo/6 as BOTTOM
Not considering main for cloning; -fipa-cp-clone disabled.
Marking all lattices of main/3 as BOTTOM
Not considering bar2 for cloning; -fipa-cp-clone disabled.
Marking all lattices of bar2/1 as BOTTOM
Not considering bar for cloning; -fipa-cp-clone disabled.
Marking all lattices of bar/0 as BOTTOM

overall_size: 34, max_new_size: 11001

Estimating effects for bar2/1, base_time: 14.

Estimating effects for bar/0, base_time: 14.
Meeting
  [0, 2]
and
  [0, 1]
to
  [0, 2]

Estimating effects for foo/6, base_time: 6.

IPA lattices after all propagation:

Lattices:
  Node: foo/6:
    param [0]: BOTTOM
         ctxs: BOTTOM
         Alignment unusable (BOTTOM)
[0, 2]        AGGS BOTTOM
  Node: main/3:
  Node: bar2/1:
    param [0]: BOTTOM
         ctxs: BOTTOM
         Alignment unusable (BOTTOM)
UNDEFINED        AGGS BOTTOM
  Node: bar/0:
    param [0]: BOTTOM
         ctxs: BOTTOM
         Alignment unusable (BOTTOM)
UNDEFINED        AGGS BOTTOM

IPA decision stage:


Evaluating opportunities for bar2/1.

Evaluating opportunities for bar/0.

Evaluating opportunities for foo/6.

IPA constant propagation end

Reclaiming functions:
Reclaiming variables:
Clearing address taken flags:
Symbol table:

puts/7 (__builtin_puts) @0x7ffa9ff50730
  Type: function
  Visibility: external public
  References: 
  Referring: 
  Availability: not_available
  First run: 0
  Function flags:
  Called by: foo/6 (0.19 per call) 
  Calls: 
foo/6 (foo) @0x7ffa9ff505c0
  Type: function definition analyzed
  Visibility: externally_visible public
  References: 
  Referring: 
  Read from file: t1.o
  Availability: available
  First run: 0
  Function flags:
  Called by: bar/0 (1.00 per call) bar2/1 (1.00 per call) main/3 (1.00 per call) main/3 (1.00 per call) main/3 (1.00 per call) main/3 (1.00 per call) 
  Calls: puts/7 (0.19 per call) 
x/2 (x) @0x7ffa9ff51000
  Type: variable definition analyzed
  Visibility: externally_visible public common
  References: 
  Referring: main/3 (write)main/3 (write)main/3 (write)main/3 (write)
  Read from file: t2.o
  Availability: overwritable
  Varpool flags:
main/3 (main) @0x7ffa9ff502e0
  Type: function definition analyzed
  Visibility: externally_visible public
  References: x/2 (write)x/2 (write)x/2 (write)x/2 (write)
  Referring: 
  Read from file: t2.o
  Availability: available
  First run: 0
  Function flags: only_called_at_startup executed_once only_called_at_startup
  Called by: 
  Calls: foo/6 (1.00 per call) foo/6 (1.00 per call) foo/6 (1.00 per call) foo/6 (1.00 per call) 
bar2/1 (bar2) @0x7ffa9ff50170
  Type: function definition analyzed
  Visibility: externally_visible public
  References: 
  Referring: 
  Read from file: t2.o
  Availability: available
  First run: 0
  Function flags:
  Called by: 
  Calls: foo/6 (1.00 per call) 
bar/0 (bar) @0x7ffa9ff50000
  Type: function definition analyzed
  Visibility: externally_visible public
  References: 
  Referring: 
  Read from file: t2.o
  Availability: available
  First run: 0
  Function flags:
  Called by: 
  Calls: foo/6 (1.00 per call) 

;; Function foo (foo, funcdef_no=0, decl_uid=3890, cgraph_uid=4, symbol_order=6)

Modification phase of node foo/6
Setting value range of param 0 [0,2]
__attribute__((noinline))
foo (int i)
{
  unsigned int _3;

  <bb 2>:
  _3 = (unsigned int) i_2(D);
  if (_3 > 1)
    goto <bb 4>;
  else
    goto <bb 3>;

  <bb 3>:
  __builtin_puts (&"test"[0]);

  <bb 4>:
  return;

}



;; Function main (main, funcdef_no=1, decl_uid=3884, cgraph_uid=2, symbol_order=3) (executed once)

Modification phase of node main/3
main ()
{
  <bb 2>:
  x = 0;
  foo (1);
  x = 1;
  foo (0);
  x = 3;
  foo (2);
  x = 5;
  foo (0);
  return 0;

}



;; Function bar2 (bar2, funcdef_no=2, decl_uid=3883, cgraph_uid=1, symbol_order=1)

Modification phase of node bar2/1
bar2 (long unsigned int l)
{
  int _2;
  int _3;

  <bb 2>:
  _2 = (int) l_1(D);
  _3 = _2 & 2;
  foo (_3);
  return;

}



;; Function bar (bar, funcdef_no=3, decl_uid=3882, cgraph_uid=0, symbol_order=0)

Modification phase of node bar/0
bar (long unsigned int l)
{
  _Bool _2;
  int _3;

  <bb 2>:
  _2 = l_1(D) == 0;
  _3 = (int) _2;
  foo (_3);
  return;

}


-------------- next part --------------
diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
index ee28550..cb42a51 100644
--- a/gcc/ipa-cp.c
+++ b/gcc/ipa-cp.c
@@ -121,6 +121,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-inline.h"
 #include "ipa-utils.h"
 
+extern void set_range_info (tree, enum value_range_type, const wide_int_ref &,
+			    const wide_int_ref &);
 template <typename valtype> class ipcp_value;
 
 /* Describes a particular source for an IPA-CP value.  */
@@ -266,6 +268,33 @@ private:
   bool meet_with_1 (unsigned new_align, unsigned new_misalign);
 };
 
+/* Lattice of value ranges.  */
+
+class ipcp_vr_lattice
+{
+public:
+  value_range vr;
+
+  inline bool bottom_p () const;
+  inline bool top_p () const;
+  inline bool set_to_bottom ();
+  bool meet_with (const value_range *vr);
+  bool meet_with (const ipcp_vr_lattice &other);
+  void init () { vr.type = VR_UNDEFINED; }
+  void print (FILE * f);
+
+private:
+  bool meet_with_1 (const value_range *vr);
+  /* If set, this lattice is bottom and all other fields should be
+     disregarded.  */
+  bool bottom;
+  /* If bottom and not_top are false, the lattice is TOP.  If not_top is true,
+     the known alignment is stored in the fields align and misalign.  The field
+     is negated so that memset to zero initializes the lattice to TOP
+     state.  */
+  bool not_top;
+};
+
 /* 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.  */
@@ -281,6 +310,8 @@ public:
   ipcp_agg_lattice *aggs;
   /* Lattice describing known alignment.  */
   ipcp_alignment_lattice alignment;
+  /* Lattice describing value range.  */
+  ipcp_vr_lattice vr;
   /* Number of aggregate lattices */
   int aggs_count;
   /* True if aggregate data were passed by reference (as opposed to by
@@ -348,6 +379,15 @@ 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->vr;
+}
+
 /* Return whether LAT is a lattice with a single constant and without an
    undefined value.  */
 
@@ -458,6 +498,14 @@ ipcp_alignment_lattice::print (FILE * f)
     fprintf (f, "         Alignment %u, misalignment %u\n", align, misalign);
 }
 
+/* Print vr lattice to F.  */
+
+void
+ipcp_vr_lattice::print (FILE * f)
+{
+  dump_value_range (f, &vr);
+}
+
 /* Print all ipcp_lattices of all functions to F.  */
 
 static void
@@ -484,6 +532,7 @@ print_all_lattices (FILE * f, bool dump_sources, bool dump_benefits)
 	  fprintf (f, "         ctxs: ");
 	  plats->ctxlat.print (f, dump_sources, dump_benefits);
 	  plats->alignment.print (f);
+	  plats->vr.print (f);
 	  if (plats->virt_call)
 	    fprintf (f, "        virt_call flag set\n");
 
@@ -828,6 +877,98 @@ 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.vr);
+}
+
+/* Meet the current value of the lattice with value ranfge described by VR
+   lattice.  */
+
+bool
+ipcp_vr_lattice::meet_with (const value_range *vr)
+{
+  return meet_with_1 (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 = NULL_TREE, max = NULL_TREE;
+  value_range_type type = VR_LAST;
+
+  if (bottom_p ())
+    return false;
+
+  if (other_vr->type == VR_VARYING)
+    {
+      set_to_bottom ();
+      return (vr.type != VR_VARYING);
+    }
+  else if ( other_vr->type == VR_UNDEFINED)
+    return false;
+
+  if (top_p ())
+    {
+      vr.min = other_vr->min;
+      vr.max = other_vr->max;
+      vr.type = other_vr->type;
+      return true;
+    }
+
+  if (vr.type == VR_RANGE
+      || vr.type == VR_ANTI_RANGE)
+    {
+      min = vr.min;
+      max = vr.max;
+      type = vr.type;
+    }
+
+  vrp_meet (&vr, const_cast<value_range *> (other_vr));
+  if (type != vr.type
+      || min != vr.min
+      || max != vr.max)
+    return true;
+  else
+    return false;
+}
+
+/* Return true if alignment information in the lattice is yet unknown.  */
+
+bool
+ipcp_vr_lattice::top_p () const
+{
+  return 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 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 (vr.type == VR_VARYING)
+    return false;
+  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.  */
@@ -915,6 +1056,7 @@ set_all_contains_variable (struct ipcp_param_lattices *plats)
   ret |= plats->ctxlat.set_contains_variable ();
   ret |= set_agg_lats_contain_variable (plats);
   ret |= plats->alignment.set_to_bottom ();
+  ret |= plats->vr.set_to_bottom ();
   return ret;
 }
 
@@ -999,6 +1141,7 @@ initialize_node_lattices (struct cgraph_node *node)
 	    }
 	  else
 	    set_all_contains_variable (plats);
+	  plats->vr.init ();
 	}
       if (dump_file && (dump_flags & TDF_DETAILS)
 	  && !node->alias && !node->thunk.thunk_p)
@@ -1613,7 +1756,26 @@ propagate_alignment_accross_jump_function (cgraph_edge *cs,
     }
 }
 
-/* If DEST_PLATS already has aggregate items, check that aggs_by_ref matches
+/* Propagate alignments across jump function JFUNC that is associated with
+   edge CS and update DEST_LAT accordingly.  */
+static bool
+propagate_vr_accross_jump_function (ipa_jump_func *jfunc,
+				    struct ipcp_param_lattices *dest_plats)
+{
+  ipcp_vr_lattice *dest_lat = &dest_plats->vr;
+  if (dest_lat->bottom_p ())
+    return false;
+
+  //if (!jfunc->vr_known)
+  //  return dest_lat->set_to_bottom ();
+
+  if (dest_lat->meet_with (&jfunc->vr))
+    return true;
+
+  return false;
+}
+
+/* If DEST_PLATS alvrhas 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
    aggs_by_ref to NEW_AGGS_BY_REF.  */
@@ -1953,6 +2115,7 @@ propagate_constants_accross_call (struct cgraph_edge *cs)
 							 &dest_plats->alignment);
 	  ret |= propagate_aggs_accross_jump_function (cs, jump_func,
 						       dest_plats);
+	  ret |= propagate_vr_accross_jump_function (jump_func, dest_plats);
 	}
     }
   for (; i < parms_count; i++)
@@ -4479,7 +4642,7 @@ ipcp_decision_stage (struct ipa_topo_info *topo)
    to the transformation summary.  */
 
 static void
-ipcp_store_alignment_results (void)
+ipcp_store_alignment_and_vr_results (void)
 {
   cgraph_node *node;
 
@@ -4489,6 +4652,7 @@ ipcp_store_alignment_results (void)
     bool dumped_sth = false;
     bool found_useful_result = false;
 
+#if 0
     if (!opt_for_fn (node->decl, flag_ipa_cp_alignment))
       {
 	if (dump_file)
@@ -4497,6 +4661,7 @@ ipcp_store_alignment_results (void)
 		   node->name ());
 	continue;
       }
+#endif
 
    if (info->ipcp_orig_node)
       info = IPA_NODE_REF (info->ipcp_orig_node);
@@ -4512,6 +4677,12 @@ ipcp_store_alignment_results (void)
 	   found_useful_result = true;
 	   break;
 	 }
+       if (!plats->vr.bottom_p ()
+	   && !plats->vr.top_p ())
+	 {
+	   found_useful_result = true;
+	   break;
+	 }
      }
    if (!found_useful_result)
      continue;
@@ -4519,11 +4690,13 @@ ipcp_store_alignment_results (void)
    ipcp_grow_transformations_if_necessary ();
    ipcp_transformation_summary *ts = ipcp_get_transformation_summary (node);
    vec_safe_reserve_exact (ts->alignments, count);
+   vec_safe_reserve_exact (ts->vr, count);
 
    for (unsigned i = 0; i < count ; i++)
      {
        ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
        ipa_alignment al;
+       ipa_vr vr;
 
        if (!plats->alignment.bottom_p ()
 	   && !plats->alignment.top_p ())
@@ -4535,7 +4708,19 @@ ipcp_store_alignment_results (void)
        else
 	 al.known = false;
 
+       if (!plats->vr.bottom_p ()
+	   && !plats->vr.top_p ())
+	 {
+	   vr.known = true;
+	   vr.type = plats->vr.vr.type;
+	   vr.min = plats->vr.vr.min;
+	   vr.max = plats->vr.vr.max;
+	 }
+       else
+	 vr.known = false;
+
        ts->alignments->quick_push (al);
+       ts->vr->quick_push (vr);
        if (!dump_file || !al.known)
 	 continue;
        if (!dumped_sth)
@@ -4582,7 +4767,7 @@ ipcp_driver (void)
   /* Decide what constant propagation and cloning should be performed.  */
   ipcp_decision_stage (&topo);
   /* Store results of alignment propagation. */
-  ipcp_store_alignment_results ();
+  ipcp_store_alignment_and_vr_results ();
 
   /* Free all IPCP structures.  */
   free_toporder_info (&topo);
diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c
index 72c2fed..0c4878b 100644
--- a/gcc/ipa-prop.c
+++ b/gcc/ipa-prop.c
@@ -1655,7 +1655,20 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
 	    gcc_assert (!jfunc->alignment.known);
 	}
       else
-	gcc_assert (!jfunc->alignment.known);
+	{
+	  wide_int min, max;
+	  value_range_type type;
+	  if (TREE_CODE (arg) == SSA_NAME
+	      && (type = get_range_info (arg, &min, &max))
+	      && (type == VR_RANGE || type == VR_ANTI_RANGE))
+	    {
+	      jfunc->vr_known = true;
+	      jfunc->vr.type = type;
+	      jfunc->vr.min = wide_int_to_tree (TREE_TYPE (arg), min);
+	      jfunc->vr.max = wide_int_to_tree (TREE_TYPE (arg), max);
+	    }
+	  gcc_assert (!jfunc->alignment.known);
+	}
 
       if (is_gimple_ip_invariant (arg))
 	ipa_set_jf_constant (jfunc, arg, cs);
@@ -3532,16 +3545,24 @@ ipa_node_params_t::duplicate(cgraph_node *src, cgraph_node *dst,
 
   ipcp_transformation_summary *src_trans = ipcp_get_transformation_summary (src);
 
-  if (src_trans && vec_safe_length (src_trans->alignments) > 0)
+  if (src_trans
+      && (vec_safe_length (src_trans->alignments) > 0
+	  || vec_safe_length (src_trans->vr) > 0))
     {
       ipcp_grow_transformations_if_necessary ();
       src_trans = ipcp_get_transformation_summary (src);
       const vec<ipa_alignment, va_gc> *src_alignments = src_trans->alignments;
+      const vec<ipa_vr, va_gc> *src_vr = src_trans->vr;
       vec<ipa_alignment, va_gc> *&dst_alignments
 	= ipcp_get_transformation_summary (dst)->alignments;
+      vec<ipa_vr, va_gc> *&dst_vr
+	= ipcp_get_transformation_summary (dst)->vr;
       vec_safe_reserve_exact (dst_alignments, src_alignments->length ());
+      vec_safe_reserve_exact (dst_vr, src_vr->length ());
       for (unsigned i = 0; i < src_alignments->length (); ++i)
 	dst_alignments->quick_push ((*src_alignments)[i]);
+      for (unsigned i = 0; i < src_vr->length (); ++i)
+	dst_vr->quick_push ((*src_vr)[i]);
     }
 }
 
@@ -4462,6 +4483,14 @@ ipa_write_jump_function (struct output_block *ob,
       streamer_write_uhwi (ob, jump_func->alignment.align);
       streamer_write_uhwi (ob, jump_func->alignment.misalign);
     }
+  bp_pack_value (&bp, jump_func->vr_known, 1);
+  streamer_write_bitpack (&bp);
+  if (jump_func->vr_known)
+    {
+      streamer_write_enum (ob->main_stream, value_rang_type, VR_LAST, jump_func->vr.type);
+      stream_write_tree (ob, jump_func->vr.min, true);
+      stream_write_tree (ob, jump_func->vr.max, true);
+    }
 }
 
 /* Read in jump function JUMP_FUNC from IB.  */
@@ -4538,6 +4567,17 @@ ipa_read_jump_function (struct lto_input_block *ib,
     }
   else
     jump_func->alignment.known = false;
+  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->vr.type = streamer_read_enum (ib, value_range_type, VR_LAST);
+      jump_func->vr.min = stream_read_tree (ib, data_in);
+      jump_func->vr.max = stream_read_tree (ib, data_in);
+    }
+  else
+    jump_func->vr_known = false;
 }
 
 /* Stream out parts of cgraph_indirect_call_info corresponding to CS that are
@@ -4878,7 +4918,8 @@ write_ipcp_transformation_info (output_block *ob, cgraph_node *node)
     }
 
   ipcp_transformation_summary *ts = ipcp_get_transformation_summary (node);
-  if (ts && vec_safe_length (ts->alignments) > 0)
+  if (ts && (vec_safe_length (ts->alignments) > 0
+	     || vec_safe_length (ts->alignments) > 0))
     {
       count = ts->alignments->length ();
 
@@ -4886,6 +4927,7 @@ write_ipcp_transformation_info (output_block *ob, cgraph_node *node)
       for (unsigned i = 0; i < count; ++i)
 	{
 	  ipa_alignment *parm_al = &(*ts->alignments)[i];
+	  ipa_vr *parm_vr = &(*ts->vr)[i];
 
 	  struct bitpack_d bp;
 	  bp = bitpack_create (ob->main_stream);
@@ -4897,6 +4939,15 @@ write_ipcp_transformation_info (output_block *ob, cgraph_node *node)
 	      streamer_write_hwi_in_range (ob->main_stream, 0, parm_al->align,
 					   parm_al->misalign);
 	    }
+	  bp = bitpack_create (ob->main_stream);
+	  bp_pack_value (&bp, parm_vr->known, 1);
+	  streamer_write_bitpack (&bp);
+	  if (parm_vr->known)
+	    {
+	      streamer_write_enum (ob->main_stream, value_rang_type, VR_LAST, parm_vr->type);
+	      stream_write_tree (ob, parm_vr->min, true);
+	      stream_write_tree (ob, parm_vr->max, true);
+	    }
 	}
     }
   else
@@ -4936,11 +4987,14 @@ read_ipcp_transformation_info (lto_input_block *ib, cgraph_node *node,
 
       ipcp_transformation_summary *ts = ipcp_get_transformation_summary (node);
       vec_safe_grow_cleared (ts->alignments, count);
+      vec_safe_grow_cleared (ts->vr, count);
 
       for (i = 0; i < count; i++)
 	{
 	  ipa_alignment *parm_al;
+	  ipa_vr *parm_vr;
 	  parm_al = &(*ts->alignments)[i];
+	  parm_vr = &(*ts->vr)[i];
 	  struct bitpack_d bp;
 	  bp = streamer_read_bitpack (ib);
 	  parm_al->known = bp_unpack_value (&bp, 1);
@@ -4951,6 +5005,14 @@ read_ipcp_transformation_info (lto_input_block *ib, cgraph_node *node,
 		= streamer_read_hwi_in_range (ib, "ipa-prop misalign",
 					      0, parm_al->align);
 	    }
+	  bp = streamer_read_bitpack (ib);
+	  parm_vr->known = bp_unpack_value (&bp, 1);
+	  if (parm_vr->known)
+	    {
+	      parm_vr->type = streamer_read_enum (ib, value_range_type, VR_LAST);
+	      parm_vr->min = stream_read_tree (ib, data_in);
+	      parm_vr->max = stream_read_tree (ib, data_in);
+	    }
 	}
     }
 }
@@ -5207,15 +5269,17 @@ ipcp_modif_dom_walker::before_dom_children (basic_block bb)
    ipcp_transformation_summary.  */
 
 static void
-ipcp_update_alignments (struct cgraph_node *node)
+ipcp_update_vr_and_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)
+  if (!ts || ((vec_safe_length (ts->alignments) == 0)
+	      && (vec_safe_length (ts->vr) == 0)))
     return;
   const vec<ipa_alignment, va_gc> &alignments = *ts->alignments;
+  const vec<ipa_vr, va_gc> &vr = *ts->vr;
   unsigned count = alignments.length ();
 
   for (unsigned i = 0; i < count; ++i, parm = next_parm)
@@ -5225,13 +5289,32 @@ ipcp_update_alignments (struct cgraph_node *node)
 	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 (vr[i].known
+	  && TREE_CODE (vr[i].min) == INTEGER_CST
+	  && TREE_CODE (vr[i].max) == INTEGER_CST)
+	{
+	  if (dump_file)
+	    {
+	      fprintf (dump_file, "Setting value range of param %u ", i);
+	      fprintf (dump_file, "%s[", (vr[i].type == VR_ANTI_RANGE) ? "~" : "");
+	      print_generic_expr (dump_file, vr[i].min, 0);
+	      fprintf (dump_file, ",");
+	      print_generic_expr (dump_file, vr[i].max, 0);
+	      fprintf (dump_file, "]\n");
+	    }
+	  set_range_info (ddef, vr[i].type,
+			  wide_int_to_tree (TREE_TYPE (ddef), vr[i].min),
+			  wide_int_to_tree (TREE_TYPE (ddef), vr[i].max));
+
+	}
+
+      if (!alignments[i].known || !is_gimple_reg (parm))
+	continue;
+
       if (dump_file)
 	fprintf (dump_file, "  Adjusting alignment of param %u to %u, "
 		 "misalignment to %u\n", i, alignments[i].align,
@@ -5273,7 +5356,7 @@ ipcp_transform_function (struct cgraph_node *node)
     fprintf (dump_file, "Modification phase of node %s/%i\n",
 	     node->name (), node->order);
 
-  ipcp_update_alignments (node);
+  ipcp_update_vr_and_alignments (node);
   aggval = ipa_get_agg_replacements_for_node (node);
   if (!aggval)
       return 0;
diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h
index 2fe824d..169ec97 100644
--- a/gcc/ipa-prop.h
+++ b/gcc/ipa-prop.h
@@ -154,6 +154,16 @@ struct GTY(()) ipa_alignment
   unsigned misalign;
 };
 
+/* Info about value ranges. */
+struct GTY(()) ipa_vr
+{
+  /* The data fields below are valid only if known is true.  */
+  bool known;
+  enum value_range_type type;
+  tree GTY ((skip)) min;
+  tree GTY ((skip)) max;
+};
+
 /* 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.  */
@@ -166,6 +176,10 @@ struct GTY (()) ipa_jump_func
   /* Information about alignment of pointers. */
   struct ipa_alignment alignment;
 
+  /* Information about value range. */
+  bool vr_known;
+  value_range vr;
+
   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
@@ -482,6 +496,8 @@ struct GTY(()) ipcp_transformation_summary
   ipa_agg_replacement_value *agg_values;
   /* Alignment information for pointers.  */
   vec<ipa_alignment, va_gc> *alignments;
+  /* Value range information.  */
+  vec<ipa_vr, va_gc> *vr;
 };
 
 void ipa_set_node_agg_value_chain (struct cgraph_node *node,
diff --git a/gcc/passes.def b/gcc/passes.def
index 43ce3d5..6d0dbec 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -119,6 +119,7 @@ along with GCC; see the file COPYING3.  If not see
 	     early optimizations again.  It is thus good idea to do this
 	      late.  */
 	  NEXT_PASS (pass_split_functions);
+      NEXT_PASS (pass_vrp, false /* warn_array_bounds_p */);
       POP_INSERT_PASSES ()
       NEXT_PASS (pass_release_ssa_names);
       NEXT_PASS (pass_rebuild_cgraph_edges);
diff --git a/gcc/tree-ssanames.h b/gcc/tree-ssanames.h
index 092ada1..73ff5f4 100644
--- a/gcc/tree-ssanames.h
+++ b/gcc/tree-ssanames.h
@@ -63,9 +63,7 @@ struct GTY ((variable_size)) range_info_def {
 #define ssa_name(i) ((*cfun->gimple_df->ssa_names)[(i)])
 
 
-/* Type of value ranges.  See value_range_d In tree-vrp.c for a
-   description of these types.  */
-enum value_range_type { VR_UNDEFINED, VR_RANGE, VR_ANTI_RANGE, VR_VARYING };
+#define VR_INITIALIZER { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL }
 
 /* Sets the value range to SSA.  */
 extern void set_range_info (tree, enum value_range_type, const wide_int_ref &,
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index acbb70b..ed92fda 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -59,33 +59,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "target.h"
 #include "case-cfn-macros.h"
 
-/* Range of values that can be associated with an SSA_NAME after VRP
-   has executed.  */
-struct value_range
-{
-  /* Lattice value represented by this range.  */
-  enum value_range_type type;
-
-  /* Minimum and maximum values represented by this range.  These
-     values should be interpreted as follows:
-
-	- If TYPE is VR_UNDEFINED or VR_VARYING then MIN and MAX must
-	  be NULL.
-
-	- If TYPE == VR_RANGE then MIN holds the minimum value and
-	  MAX holds the maximum value of the range [MIN, MAX].
-
-	- If TYPE == ANTI_RANGE the variable is known to NOT
-	  take any values in the range [MIN, MAX].  */
-  tree min;
-  tree max;
-
-  /* Set of SSA names whose value ranges are equivalent to this one.
-     This set is only valid when TYPE is VR_RANGE or VR_ANTI_RANGE.  */
-  bitmap equiv;
-};
-
-#define VR_INITIALIZER { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL }
 
 /* Set of SSA names found live during the RPO traversal of the function
    for still active basic-blocks.  */
@@ -103,7 +76,6 @@ live_on_edge (edge e, tree name)
 /* Local functions.  */
 static int compare_values (tree val1, tree val2);
 static int compare_values_warnv (tree val1, tree val2, bool *);
-static void vrp_meet (value_range *, value_range *);
 static void vrp_intersect_ranges (value_range *, value_range *);
 static tree vrp_evaluate_conditional_warnv_with_ops (enum tree_code,
 						     tree, tree, bool, bool *,
@@ -4629,7 +4601,6 @@ compare_range_with_value (enum tree_code comp, value_range *vr, tree val,
 
 /* Debugging dumps.  */
 
-void dump_value_range (FILE *, value_range *);
 void debug_value_range (value_range *);
 void dump_all_value_ranges (FILE *);
 void debug_all_value_ranges (void);
@@ -8623,7 +8594,7 @@ vrp_meet_1 (value_range *vr0, value_range *vr1)
     bitmap_clear (vr0->equiv);
 }
 
-static void
+void
 vrp_meet (value_range *vr0, value_range *vr1)
 {
   if (dump_file && (dump_flags & TDF_DETAILS))
diff --git a/gcc/tree.h b/gcc/tree.h
index 96ffa83..e1bbc27 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -2696,6 +2696,40 @@ extern priority_type decl_fini_priority_lookup (tree);
 extern void decl_init_priority_insert (tree, priority_type);
 extern void decl_fini_priority_insert (tree, priority_type);
 
+/* Type of value ranges.  See value_range_d In tree-vrp.c for a
+   description of these types.  */
+enum value_range_type { VR_UNDEFINED, VR_RANGE, VR_ANTI_RANGE, VR_VARYING, VR_LAST };
+
+/* Range of values that can be associated with an SSA_NAME after VRP
+   has executed.  */
+struct GTY(()) value_range
+{
+  /* Lattice value represented by this range.  */
+  enum value_range_type type;
+
+  /* Minimum and maximum values represented by this range.  These
+     values should be interpreted as follows:
+
+	- If TYPE is VR_UNDEFINED or VR_VARYING then MIN and MAX must
+	  be NULL.
+
+	- If TYPE == VR_RANGE then MIN holds the minimum value and
+	  MAX holds the maximum value of the range [MIN, MAX].
+
+	- If TYPE == ANTI_RANGE the variable is known to NOT
+	  take any values in the range [MIN, MAX].  */
+  tree min;
+  tree max;
+
+  /* Set of SSA names whose value ranges are equivalent to this one.
+     This set is only valid when TYPE is VR_RANGE or VR_ANTI_RANGE.  */
+  bitmap equiv;
+};
+
+void vrp_meet (value_range *vr0, value_range *vr1);
+void dump_value_range (FILE *, value_range *);
+
+
 /* For a VAR_DECL or FUNCTION_DECL the initialization priority of
    NODE.  */
 #define DECL_INIT_PRIORITY(NODE) \


More information about the Gcc mailing list