public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [RFC][IPA-VRP] IPA VRP Implementation
@ 2016-07-15  4:41 kugan
  2016-07-15  4:42 ` [RFC][IPA-VRP] Disable setting param of __builtin_constant_p to null kugan
                   ` (4 more replies)
  0 siblings, 5 replies; 67+ messages in thread
From: kugan @ 2016-07-15  4:41 UTC (permalink / raw)
  To: gcc-patches; +Cc: Richard Biener, Jan Hubicka, Martin Jambor

Hi,



This patch series implements IPA-VRP based on the previous discussions 
in https://gcc.gnu.org/ml/gcc/2016-01/msg00063.html.



0001-Hack-Prevent-setting-__builtin_constant_p-of-param-t.patch -This is 
to prevent EVRP setting result of __builtin_constant_p to null that will 
inlined later.



0002-Inliner-Check-for-POINTER_TYPE.patch - This is to make sure that we 
call SSA_NAME_PTR_INFO only for POINTER_TYPE_P. This is exposed with 
IPA-VRP but not related to rest of the patch.



0003-Refactor-vrp.patch - Re-factors tree-vrp to expose some of the 
common functionalities.

0004-Add-early-vrp.patch - Adds a simple Early VRP pass.

0005-Add-ipa-vrp.patch - Implements IPA VRP

0006-Teach-tree-vrp-to-use-ipa-vrp-results.patch - Teaches tree-vrp to 
use the value ranges set for the PARMs.



More details about the patches are later with each patch.



Before I go into the details, here is a simple example and the relevant 
dumps as of now:



static __attribute__((noinline, noclone))

int foo (int i)

{

   if (i > 5)

     printf ("OK\n");

   else

     printf ("NOK\n");

}



int bar (int j)

{

   if (j > 8)

     return foo (j + 2);

   else if (j > 2)

     return foo (j + 3);



   return 0;

}





The Early VRP dump shows:



_1: [11, +INF(OVF)]

_2: [6, 11]

....



bar (int j)

{

....

   _8 = foo (_1);

   goto <bb 6>;



   <bb 4>:

   if (j_5(D) > 2)

     goto <bb 5>;

   else

     goto <bb 6>;



   <bb 5>:

   _2 = j_5(D) + 3;

   _10 = foo (_2);



....




The IPA-CP dump shows:

....

Modification phase of node foo/0

Setting value range of param 0 [6, 2147483647]

__attribute__((noclone, noinline))

foo (int i)

....





The VRP1 dump shows:



Value ranges after VRP:



.MEM_1: VARYING

i_2(D): [6, +INF]





Folding predicate i_2(D) > 5 to 1

Removing basic block 4

Merging blocks 2 and 3

Merging blocks 2 and 5

__attribute__((noclone, noinline))

foo (int i)

{

   <bb 2>:

   __builtin_puts (&"OK"[0]);

   return;



}



I have bootstrapped and regression tested the patches in this series on 
x86-64 and aarch64 (both normal bootstrap and LTO bootstrap).

There are couple of testcase failures which I am looking into.



Any thoughts?



Thanks,

Kugan


^ permalink raw reply	[flat|nested] 67+ messages in thread

* [RFC][IPA-VRP] Disable setting param of __builtin_constant_p to null
  2016-07-15  4:41 [RFC][IPA-VRP] IPA VRP Implementation kugan
@ 2016-07-15  4:42 ` kugan
  2016-07-15  8:43   ` Jan Hubicka
  2016-07-15  4:43 ` [RFC][IPA-VRP] Check for POINTER_TYPE_P before accessing SSA_NAME_PTR_INFO in tree-inline kugan
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 67+ messages in thread
From: kugan @ 2016-07-15  4:42 UTC (permalink / raw)
  To: gcc-patches; +Cc: Richard Biener, Jan Hubicka, Martin Jambor

[-- Attachment #1: Type: text/plain, Size: 489 bytes --]

Hi,



VRP assumes that it is run after inlining. Therefore, if there is a call 
to __builtin_constant_p with function parameter, it resolve it to false 
to avoid bogus warnings. Since we use this as an early vrp before 
inling, it leads to  wrong code. As a workaround I have disabled it for 
the time being. That is, this patch is not intended for committing but 
just to get the VRP tested.



Original patch which introduced this also talks about doing it earlier.





Thanks,

Kugan

[-- Attachment #2: 0001-Hack-Prevent-setting-__builtin_constant_p-of-param-t.patch --]
[-- Type: text/x-patch, Size: 805 bytes --]

From 99f8e7884d582cfae2d7cb50ad59dab7ac6772fc Mon Sep 17 00:00:00 2001
From: Kugan Vivekanandarajah <kugan.vivekanandarajah@linaro.org>
Date: Sat, 25 Jun 2016 11:52:57 +1000
Subject: [PATCH 1/6] Hack-Prevent setting __builtin_constant_p of param to
 null before inlining in Early VRP

---
 gcc/tree-vrp.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index ecfab1f..23c12b5 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -3759,8 +3759,10 @@ extract_range_basic (value_range *vr, gimple *stmt)
 	      && SSA_NAME_IS_DEFAULT_DEF (arg)
 	      && TREE_CODE (SSA_NAME_VAR (arg)) == PARM_DECL)
 	    {
+#if 0
 	      set_value_range_to_null (vr, type);
 	      return;
+#endif
 	    }
 	  break;
 	  /* Both __builtin_ffs* and __builtin_popcount return
-- 
1.9.1


^ permalink raw reply	[flat|nested] 67+ messages in thread

* [RFC][IPA-VRP] Check for POINTER_TYPE_P before accessing SSA_NAME_PTR_INFO in tree-inline
  2016-07-15  4:41 [RFC][IPA-VRP] IPA VRP Implementation kugan
  2016-07-15  4:42 ` [RFC][IPA-VRP] Disable setting param of __builtin_constant_p to null kugan
@ 2016-07-15  4:43 ` kugan
  2016-07-15  4:47   ` Andrew Pinski
  2016-07-15  7:32   ` Richard Biener
  2016-07-15  4:44 ` [RFC][IPA-VRP] Re-factor tree-vrp to factor out common code kugan
                   ` (2 subsequent siblings)
  4 siblings, 2 replies; 67+ messages in thread
From: kugan @ 2016-07-15  4:43 UTC (permalink / raw)
  To: gcc-patches; +Cc: Richard Biener, Jan Hubicka, Martin Jambor

[-- Attachment #1: Type: text/plain, Size: 401 bytes --]


Hi,



This patch adds check for POINTER_TYPE_P before accessing 
SSA_NAME_PTR_INFO in remap_ssa_name in gcc/tree-inline.c. This is not 
related to IPA_VRP but was exposed by that.



Thanks,

Kugan





gcc/ChangeLog:



2016-07-14  Kugan Vivekanandarajah  <kuganv@linaro.org>



         * tree-inline.c (remap_ssa_name): Check for POINTER_TYPE_P before

         accessing SSA_NAME_PTR_INFO.






[-- Attachment #2: 0002-Inliner-Check-for-POINTER_TYPE.patch --]
[-- Type: text/x-patch, Size: 1074 bytes --]

From 7c1e5f3058a55d635e57bb4e9f2fd4ff14cd2b94 Mon Sep 17 00:00:00 2001
From: Kugan Vivekanandarajah <kugan.vivekanandarajah@linaro.org>
Date: Tue, 5 Jul 2016 17:14:52 +1000
Subject: [PATCH 2/6] Inliner Check for POINTER_TYPE

---
 gcc/tree-inline.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index 07f6a83..f926304 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -244,6 +244,7 @@ remap_ssa_name (tree name, copy_body_data *id)
       /* At least IPA points-to info can be directly transferred.  */
       if (id->src_cfun->gimple_df
 	  && id->src_cfun->gimple_df->ipa_pta
+	  && POINTER_TYPE_P (TREE_TYPE (name))
 	  && (pi = SSA_NAME_PTR_INFO (name))
 	  && !pi->pt.anything)
 	{
@@ -276,6 +277,7 @@ remap_ssa_name (tree name, copy_body_data *id)
       /* At least IPA points-to info can be directly transferred.  */
       if (id->src_cfun->gimple_df
 	  && id->src_cfun->gimple_df->ipa_pta
+	  && POINTER_TYPE_P (TREE_TYPE (name))
 	  && (pi = SSA_NAME_PTR_INFO (name))
 	  && !pi->pt.anything)
 	{
-- 
1.9.1


^ permalink raw reply	[flat|nested] 67+ messages in thread

* [RFC][IPA-VRP] Re-factor tree-vrp to factor out common code
  2016-07-15  4:41 [RFC][IPA-VRP] IPA VRP Implementation kugan
  2016-07-15  4:42 ` [RFC][IPA-VRP] Disable setting param of __builtin_constant_p to null kugan
  2016-07-15  4:43 ` [RFC][IPA-VRP] Check for POINTER_TYPE_P before accessing SSA_NAME_PTR_INFO in tree-inline kugan
@ 2016-07-15  4:44 ` kugan
  2016-07-15  4:47   ` [RFC][IPA-VRP] Add support for IPA VRP in ipa-cp/ipa-prop kugan
  2016-07-22 12:27   ` [RFC][IPA-VRP] Re-factor tree-vrp to factor out common code kugan
  2016-07-15  4:45 ` [RFC][IPA-VRP] Early VRP Implementation kugan
  2016-07-15  4:47 ` [RFC][IPA-VRP] Teach tree-vrp to use the VR set in params kugan
  4 siblings, 2 replies; 67+ messages in thread
From: kugan @ 2016-07-15  4:44 UTC (permalink / raw)
  To: gcc-patches; +Cc: Richard Biener, Jan Hubicka, Martin Jambor

[-- Attachment #1: Type: text/plain, Size: 857 bytes --]


Hi,



This patch re-factors common code in tree-vrp to be used in early vrp. I 
am not entirely sure where I should place struct value_range. For now I 
have placed in tree.h.



Thanks,

Kugan



2016-07-14  Kugan Vivekanandarajah  <kuganv@linaro.org>



	* tree-ssanames.h (enum value_range_type): Move to tree.h.

	* tree-vrp.c (struct value_range): Add GTY marker and move to

	tree.h.

	(set_value_range_to_varying): Move inline function to tree-vrp.h

	(symbolic_range_p): Likewise.

	(change_value_range): New.

	(vrp_finalize): Add param jump_thread_p and make function global.

	(execute_vrp): Make function global.

	(extract_range_from_assert): Likewise.

	(stmt_interesting_for_vrp): Likewise.

	(vrp_initialize): Likewise.

	(vrp_meet): Likewise.

	(vrp_visit_stmt): Likewise.

	(vrp_visit_phi_node): Likewise.

	* tree-vrp.h: New file.






[-- Attachment #2: 0003-Refactor-vrp.patch --]
[-- Type: text/x-patch, Size: 11525 bytes --]

From ce7b251bc5a17ae04be57a7fb1db22e86adac282 Mon Sep 17 00:00:00 2001
From: Kugan Vivekanandarajah <kugan.vivekanandarajah@linaro.org>
Date: Tue, 21 Jun 2016 12:42:44 +1000
Subject: [PATCH 3/6] Refactor vrp

---
 gcc/tree-ssanames.h |  5 ---
 gcc/tree-vrp.c      | 93 +++++++++++++++++------------------------------------
 gcc/tree-vrp.h      | 65 +++++++++++++++++++++++++++++++++++++
 gcc/tree.h          | 31 ++++++++++++++++++
 4 files changed, 125 insertions(+), 69 deletions(-)
 create mode 100644 gcc/tree-vrp.h

diff --git a/gcc/tree-ssanames.h b/gcc/tree-ssanames.h
index c81b1a1..8e66ce6 100644
--- a/gcc/tree-ssanames.h
+++ b/gcc/tree-ssanames.h
@@ -62,11 +62,6 @@ struct GTY ((variable_size)) range_info_def {
 #define num_ssa_names (vec_safe_length (cfun->gimple_df->ssa_names))
 #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 };
-
 /* Sets the value range to SSA.  */
 extern void set_range_info (tree, enum value_range_type, const wide_int_ref &,
 			    const wide_int_ref &);
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index 23c12b5..8c87c06 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -58,32 +58,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "omp-low.h"
 #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;
-};
+#include "tree-vrp.h"
 
 #define VR_INITIALIZER { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL }
 
@@ -103,8 +78,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 *,
 						     bool *);
@@ -351,21 +324,9 @@ set_value_range_to_undefined (value_range *vr)
 }
 
 
-/* Set value range VR to VR_VARYING.  */
-
-static inline void
-set_value_range_to_varying (value_range *vr)
-{
-  vr->type = VR_VARYING;
-  vr->min = vr->max = NULL_TREE;
-  if (vr->equiv)
-    bitmap_clear (vr->equiv);
-}
-
-
 /* Set value range VR to {T, MIN, MAX, EQUIV}.  */
 
-static void
+void
 set_value_range (value_range *vr, enum value_range_type t, tree min,
 		 tree max, bitmap equiv)
 {
@@ -660,7 +621,7 @@ abs_extent_range (value_range *vr, tree min, tree max)
    If we have no values ranges recorded (ie, VRP is not running), then
    return NULL.  Otherwise create an empty range if none existed for VAR.  */
 
-static value_range *
+value_range *
 get_value_range (const_tree var)
 {
   static const value_range vr_const_varying
@@ -717,6 +678,19 @@ get_value_range (const_tree var)
   return vr;
 }
 
+/* Update the value range VR to VAR.  */
+
+void change_value_range (const_tree var, value_range *vr)
+{
+  unsigned ver = SSA_NAME_VERSION (var);
+
+  if (!vr_value)
+    return;
+
+  if (ver < num_vr_values)
+      vr_value[ver] = vr;
+}
+
 /* Return true, if VAL1 and VAL2 are equal values for VRP purposes.  */
 
 static inline bool
@@ -751,7 +725,7 @@ vrp_bitmap_equal_p (const_bitmap b1, const_bitmap b2)
    this function.  Do not call update_value_range when NEW_VR
    is the range object associated with another SSA name.  */
 
-static inline bool
+bool
 update_value_range (const_tree var, value_range *new_vr)
 {
   value_range *old_vr;
@@ -867,15 +841,6 @@ range_int_cst_singleton_p (value_range *vr)
 	  && tree_int_cst_equal (vr->min, vr->max));
 }
 
-/* Return true if value range VR involves at least one symbol.  */
-
-static inline bool
-symbolic_range_p (value_range *vr)
-{
-  return (!is_gimple_min_invariant (vr->min)
-          || !is_gimple_min_invariant (vr->max));
-}
-
 /* Return the single symbol (an SSA_NAME) contained in T if any, or NULL_TREE
    otherwise.  We only handle additive operations and set NEG to true if the
    symbol is negated and INV to the invariant part, if any.  */
@@ -1461,7 +1426,7 @@ op_with_boolean_value_range_p (tree op)
 /* Extract value range information from an ASSERT_EXPR EXPR and store
    it in *VR_P.  */
 
-static void
+void
 extract_range_from_assert (value_range *vr_p, tree expr)
 {
   tree var, cond, limit, min, max, type;
@@ -4600,7 +4565,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);
@@ -6828,7 +6792,7 @@ remove_range_assertions (void)
 
 /* Return true if STMT is interesting for VRP.  */
 
-static bool
+bool
 stmt_interesting_for_vrp (gimple *stmt)
 {
   if (gimple_code (stmt) == GIMPLE_PHI)
@@ -6876,7 +6840,7 @@ stmt_interesting_for_vrp (gimple *stmt)
 
 /* Initialize local data structures for VRP.  */
 
-static void
+void
 vrp_initialize (void)
 {
   basic_block bb;
@@ -7862,7 +7826,7 @@ vrp_visit_switch_stmt (gswitch *stmt, edge *taken_edge_p)
 
    If STMT produces a varying value, return SSA_PROP_VARYING.  */
 
-static enum ssa_prop_result
+enum ssa_prop_result
 vrp_visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
 {
   tree def;
@@ -8493,7 +8457,7 @@ vrp_intersect_ranges_1 (value_range *vr0, value_range *vr1)
     bitmap_copy (vr0->equiv, vr1->equiv);
 }
 
-static void
+void
 vrp_intersect_ranges (value_range *vr0, value_range *vr1)
 {
   if (dump_file && (dump_flags & TDF_DETAILS))
@@ -8590,7 +8554,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))
@@ -8615,7 +8579,7 @@ vrp_meet (value_range *vr0, value_range *vr1)
    edges.  If a valid value range can be derived from all the incoming
    value ranges, set a new range for the LHS of PHI.  */
 
-static enum ssa_prop_result
+enum ssa_prop_result
 vrp_visit_phi_node (gphi *phi)
 {
   size_t i;
@@ -10164,8 +10128,8 @@ finalize_jump_threads (void)
 
 /* Traverse all the blocks folding conditionals with known ranges.  */
 
-static void
-vrp_finalize (bool warn_array_bounds_p)
+void
+vrp_finalize (bool jump_thread_p, bool warn_array_bounds_p)
 {
   size_t i;
 
@@ -10206,7 +10170,8 @@ vrp_finalize (bool warn_array_bounds_p)
 
   /* We must identify jump threading opportunities before we release
      the datastructures built by VRP.  */
-  identify_jump_threads ();
+  if (jump_thread_p)
+    identify_jump_threads ();
 
   /* Free allocated memory.  */
   for (i = 0; i < num_vr_values; i++)
@@ -10295,7 +10260,7 @@ execute_vrp (bool warn_array_bounds_p)
 
   vrp_initialize ();
   ssa_propagate (vrp_visit_stmt, vrp_visit_phi_node);
-  vrp_finalize (warn_array_bounds_p);
+  vrp_finalize (true, warn_array_bounds_p);
 
   free_numbers_of_iterations_estimates (cfun);
 
diff --git a/gcc/tree-vrp.h b/gcc/tree-vrp.h
new file mode 100644
index 0000000..bcefaa7
--- /dev/null
+++ b/gcc/tree-vrp.h
@@ -0,0 +1,65 @@
+/* Support routines for Value Range Propagation (VRP).
+   Copyright (C) Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "tree-ssa-operands.h"
+#include "gimple.h"
+#include "tree-ssa-propagate.h"
+
+#define VR_INITIALIZER { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL }
+
+extern void vrp_initialize (void);
+extern void vrp_finalize (bool update, bool warn_array_bounds_p);
+extern void vrp_intersect_ranges (value_range *vr0, value_range *vr1);
+extern void vrp_meet (value_range *vr0, value_range *vr1);
+extern enum ssa_prop_result vrp_visit_stmt (gimple *stmt,
+					    edge *taken_edge_p,
+					    tree *output_p);
+extern enum ssa_prop_result vrp_visit_phi_node (gphi *phi);
+extern bool stmt_interesting_for_vrp (gimple *stmt);
+
+extern void extract_range_from_assert (value_range *vr_p, tree expr);
+extern bool update_value_range (const_tree var, value_range *vr);
+extern value_range *get_value_range (const_tree var);
+extern void set_value_range (value_range *vr, enum value_range_type t,
+			     tree min, tree max, bitmap equiv);
+extern void change_value_range (const_tree var, value_range *new_vr);
+
+extern void dump_value_range (FILE *, value_range *);
+
+/* Return true if value range VR involves at least one symbol.  */
+
+inline bool
+symbolic_range_p (value_range *vr)
+{
+  return (!is_gimple_min_invariant (vr->min)
+	  || !is_gimple_min_invariant (vr->max));
+}
+
+/* Set value range VR to VR_VARYING.  */
+
+inline void
+set_value_range_to_varying (value_range *vr)
+{
+  vr->type = VR_VARYING;
+  vr->min = vr->max = NULL_TREE;
+  if (vr->equiv)
+    bitmap_clear (vr->equiv);
+}
+
diff --git a/gcc/tree.h b/gcc/tree.h
index 90413fc..8fc4f4f 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -230,6 +230,37 @@ as_internal_fn (combined_fn code)
 
 #define TREE_CODE_LENGTH(CODE)	tree_code_length[(int) (CODE)]
 
+/* 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;
+};
+
 
 /* Helper macros for math builtins.  */
 
-- 
1.9.1


^ permalink raw reply	[flat|nested] 67+ messages in thread

* [RFC][IPA-VRP] Early VRP Implementation
  2016-07-15  4:41 [RFC][IPA-VRP] IPA VRP Implementation kugan
                   ` (2 preceding siblings ...)
  2016-07-15  4:44 ` [RFC][IPA-VRP] Re-factor tree-vrp to factor out common code kugan
@ 2016-07-15  4:45 ` kugan
  2016-07-15  4:52   ` Andrew Pinski
  2016-07-15  4:47 ` [RFC][IPA-VRP] Teach tree-vrp to use the VR set in params kugan
  4 siblings, 1 reply; 67+ messages in thread
From: kugan @ 2016-07-15  4:45 UTC (permalink / raw)
  To: gcc-patches; +Cc: Richard Biener, Jan Hubicka, Martin Jambor

[-- Attachment #1: Type: text/plain, Size: 1554 bytes --]


Hi,



This patch adds a very simple early vrp implementation. This visits the 
basic blocks in the dominance order and set the Value Ranges (VR) for

SSA_NAMEs in the scope. Use this VR to discover more VRs. Restore the 
old VR once the scope is exit.



Thanks,

Kugan





gcc/ChangeLog:



2016-07-14  Kugan Vivekanandarajah  <kuganv@linaro.org>



         * Makefile.in: Add tree-early-vrp.o.

         * common.opt: New option -ftree-evrp.

         * doc/invoke.texi: Document -ftree-evrp.

         * passes.def: Define new pass_early_vrp.

         * timevar.def: Define new TV_TREE_EARLY_VRP.

         * tree-early-vrp.c: New file.

         * tree-pass.h (make_pass_early_vrp): New.



gcc/testsuite/ChangeLog:



2016-07-14  Kugan Vivekanandarajah  <kuganv@linaro.org>



         * gcc.dg/tree-ssa/evrp1.c: New test.

         * gcc.dg/tree-ssa/evrp2.c: New test.

         * gcc.dg/tree-ssa/evrp3.c: New test.

         * g++.dg/tree-ssa/pr31146-2.C: Run with -fno-tree-evrp as evrp also

         does the same transformation.

         * gcc.dg/tree-ssa/pr20318.c: Check for the pattern in evrp dump.

         * gcc.dg/tree-ssa/pr22117.c: Likewise.

         * gcc.dg/tree-ssa/pr25382.c: Likewise.

         * gcc.dg/tree-ssa/pr68431.c: LIkewise.

         * gcc.dg/tree-ssa/vrp19.c: Likewise.

         * gcc.dg/tree-ssa/vrp23.c: Likewise.

         * gcc.dg/tree-ssa/vrp24.c: Likewise.

         * gcc.dg/tree-ssa/vrp58.c: Likewise.

         * gcc.dg/tree-ssa/vrp67.c: Likewise.

         * gcc.dg/tree-ssa/vrp98.c: Likewise.






[-- Attachment #2: 0004-Add-early-vrp.patch --]
[-- Type: text/x-patch, Size: 24182 bytes --]

From d73d443762e1741b810143b2333801cf952c8f17 Mon Sep 17 00:00:00 2001
From: Kugan Vivekanandarajah <kugan.vivekanandarajah@linaro.org>
Date: Fri, 24 Jun 2016 14:45:24 +1000
Subject: [PATCH 4/6] Add early vrp

---
 gcc/Makefile.in                           |   1 +
 gcc/common.opt                            |   4 +
 gcc/doc/invoke.texi                       |   9 +
 gcc/passes.def                            |   1 +
 gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C |   2 +-
 gcc/testsuite/gcc.dg/tree-ssa/evrp1.c     |  13 ++
 gcc/testsuite/gcc.dg/tree-ssa/evrp2.c     |  18 ++
 gcc/testsuite/gcc.dg/tree-ssa/evrp3.c     |  15 ++
 gcc/testsuite/gcc.dg/tree-ssa/pr20318.c   |   4 +-
 gcc/testsuite/gcc.dg/tree-ssa/pr22117.c   |   4 +-
 gcc/testsuite/gcc.dg/tree-ssa/pr25382.c   |   4 +-
 gcc/testsuite/gcc.dg/tree-ssa/pr68431.c   |   4 +-
 gcc/testsuite/gcc.dg/tree-ssa/vrp19.c     |   6 +-
 gcc/testsuite/gcc.dg/tree-ssa/vrp23.c     |   4 +-
 gcc/testsuite/gcc.dg/tree-ssa/vrp24.c     |   5 +-
 gcc/testsuite/gcc.dg/tree-ssa/vrp58.c     |   4 +-
 gcc/testsuite/gcc.dg/tree-ssa/vrp67.c     |   4 +-
 gcc/testsuite/gcc.dg/tree-ssa/vrp98.c     |   6 +-
 gcc/timevar.def                           |   1 +
 gcc/tree-early-vrp.c                      | 324 ++++++++++++++++++++++++++++++
 gcc/tree-pass.h                           |   1 +
 21 files changed, 411 insertions(+), 23 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/evrp1.c
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/evrp2.c
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/evrp3.c
 create mode 100644 gcc/tree-early-vrp.c

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 776f6d7..1804632 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1528,6 +1528,7 @@ OBJS = \
 	tree-vect-loop-manip.o \
 	tree-vect-slp.o \
 	tree-vectorizer.o \
+	tree-early-vrp.o \
 	tree-vrp.o \
 	tree.o \
 	valtrack.o \
diff --git a/gcc/common.opt b/gcc/common.opt
index f0d7196..29d0e4d 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2471,6 +2471,10 @@ ftree-vrp
 Common Report Var(flag_tree_vrp) Init(0) Optimization
 Perform Value Range Propagation on trees.
 
+ftree-evrp
+Common Report Var(flag_tree_early_vrp) Init(1) Optimization
+Perform Early Value Range Propagation on trees.
+
 fsplit-paths
 Common Report Var(flag_split_paths) Init(0) Optimization
 Split paths leading to loop backedges.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index e000218..f4dc88d 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -7665,6 +7665,10 @@ enabled by default at @option{-O2} and higher.  Null pointer check
 elimination is only done if @option{-fdelete-null-pointer-checks} is
 enabled.
 
+@item -ftree-evrp
+@opindex ftree-evrp
+Perform Early Value Range Propagation on trees.
+
 @item -fsplit-paths
 @opindex fsplit-paths
 Split paths leading to loop backedges.  This can improve dead code
@@ -12270,6 +12274,11 @@ is made by appending @file{.slp} to the source file name.
 Dump each function after Value Range Propagation (VRP).  The file name
 is made by appending @file{.vrp} to the source file name.
 
+@item early vrp
+@opindex fdump-tree-evrp
+Dump each function after Early Value Range Propagation (EVRP).  The file name
+is made by appending @file{.evrp} to the source file name.
+
 @item oaccdevlow
 @opindex fdump-tree-oaccdevlow
 Dump each function after applying device-specific OpenACC transformations.
diff --git a/gcc/passes.def b/gcc/passes.def
index 3647e90..1e59d45 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -102,6 +102,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_early_vrp);
       POP_INSERT_PASSES ()
       NEXT_PASS (pass_release_ssa_names);
       NEXT_PASS (pass_rebuild_cgraph_edges);
diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C b/gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C
index 5e09583..dce05d6 100644
--- a/gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C
+++ b/gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O -fdump-tree-forwprop1" } */
+/* { dg-options "-O -fno-tree-evrp -fdump-tree-forwprop1" } */
 
 #include <new>
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/evrp1.c b/gcc/testsuite/gcc.dg/tree-ssa/evrp1.c
new file mode 100644
index 0000000..8c6e4e6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/evrp1.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+int foo (int i);
+int bar (int j)
+{
+  if (j > 2)
+    return foo (j + 2);
+  else
+    return j;
+}
+
+/* { dg-final { scan-tree-dump "\\\[5, \\+INF" "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/evrp2.c b/gcc/testsuite/gcc.dg/tree-ssa/evrp2.c
new file mode 100644
index 0000000..e6d4235
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/evrp2.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+int foo (int i);
+int bar2 (int j)
+{
+  if (j > 2)
+    {
+      if (j < 7)
+	return foo (j + 1);
+      else
+	return foo (j + 2);
+    }
+  return j;
+}
+
+
+/* { dg-final { scan-tree-dump "\\\[4, 7\\\]" "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/evrp3.c b/gcc/testsuite/gcc.dg/tree-ssa/evrp3.c
new file mode 100644
index 0000000..1a3bbd5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/evrp3.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+int foo (int i);
+void bar (int j)
+{
+  unsigned int i;
+  for (i = 0; i < 10; ++i)
+    {
+      bar (i + 1);
+    }
+}
+
+/* { dg-final { scan-tree-dump "\\\[1, 10\\\]" "evrp" } } */
+
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr20318.c b/gcc/testsuite/gcc.dg/tree-ssa/pr20318.c
index 41f569e..8c12863 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr20318.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr20318.c
@@ -1,5 +1,5 @@
 /* { dg-do compile { target { ! keeps_null_pointer_checks } } } */
-/* { dg-options "-O2 -fdump-tree-original -fdump-tree-vrp1 -fdelete-null-pointer-checks" } */
+/* { dg-options "-O2 -fdump-tree-original -fdump-tree-evrp  -fdelete-null-pointer-checks" } */
 
 extern int* f(int) __attribute__((returns_nonnull));
 extern void eliminate ();
@@ -14,4 +14,4 @@ void h () {
 }
 
 /* { dg-final { scan-tree-dump-times "== 0" 1 "original" } } */
-/* { dg-final { scan-tree-dump-times "Folding predicate\[^\\n\]*to 0" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "Folding predicate\[^\\n\]*to 0" 1 "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c b/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c
index 7efdd63..49a20bc 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c
@@ -3,7 +3,7 @@
    known to be zero after entering the first two "if" statements.  */
 
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1" } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
 
 void link_error (void);
 
@@ -21,4 +21,4 @@ foo (int *p, int q)
     }
 }
 
-/* { dg-final { scan-tree-dump-times "Folding predicate r_.* != 0B to 0" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "Folding predicate r_.* != 0B to 0" 1 "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c b/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c
index dcf9148..0d19d0d 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c
@@ -3,7 +3,7 @@
    Check that VRP now gets ranges from BIT_AND_EXPRs.  */
 
 /* { dg-do compile } */
-/* { dg-options "-O2 -fno-tree-ccp -fdump-tree-vrp1" } */
+/* { dg-options "-O2 -fno-tree-ccp -fdump-tree-evrp" } */
 
 int
 foo (int a)
@@ -15,4 +15,4 @@ foo (int a)
     return 1;
 }
 
-/* { dg-final { scan-tree-dump-times "Folding predicate b_.* > 300 to 0" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "Folding predicate b_.* > 300 to 0" 1 "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr68431.c b/gcc/testsuite/gcc.dg/tree-ssa/pr68431.c
index 3bd3843..a73aa00 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr68431.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr68431.c
@@ -1,5 +1,5 @@
 /* PR tree-optimization/68431 */
-/* { dg-options "-O2 -fdump-tree-vrp1-details" } */
+/* { dg-options "-O2 -fdump-tree-evrp-details" } */
 
 unsigned int x = 1;
 int
@@ -13,4 +13,4 @@ main (void)
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "Folding predicate .*to 0" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "Folding predicate .*to 0" 1 "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp19.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp19.c
index cecacb6..3d47bfd 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp19.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp19.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-fwrapv -O1 -ftree-vrp -fdump-tree-vrp1" } */
+/* { dg-options "-fwrapv -O1 -ftree-vrp -fdump-tree-evrp" } */
 
 #include <limits.h>
 extern void abort ();
@@ -22,5 +22,5 @@ int g (int b) {
 	}
 	return 1;
 }
-/* { dg-final { scan-tree-dump "Folding predicate a_. < 0 to 0" "vrp1" } } */
-/* { dg-final { scan-tree-dump "Folding predicate b_. >= 0 to 1" "vrp1" } } */
+/* { dg-final { scan-tree-dump "Folding predicate a_. < 0 to 0" "evrp" } } */
+/* { dg-final { scan-tree-dump "Folding predicate b_. >= 0 to 1" "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp23.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp23.c
index b877ccc..a6d2a24 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp23.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp23.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1-details" } */
+/* { dg-options "-O2 -fdump-tree-evrp-details" } */
 
 void aa (void);
 void aos (void);
@@ -45,5 +45,5 @@ L8:
 /* The n_sets > 0 test can be simplified into n_sets == 1 since the
    only way to reach the test is when n_sets <= 1, and the only value
    which satisfies both conditions is n_sets == 1.  */
-/* { dg-final { scan-tree-dump-times "Simplified relational" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "Simplified relational" 1 "evrp" } } */
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp24.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp24.c
index e740575..0e1e69c 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp24.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp24.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1-details" } */
+/* { dg-options "-O2 -fdump-tree-evrp-details -fdump-tree-vrp1-details" } */
 
 
 struct rtx_def;
@@ -91,5 +91,6 @@ L7:
    The second n_sets > 0 test can also be simplified into n_sets == 1
    as the only way to reach the tests is when n_sets <= 1 and the only
    value which satisfies both conditions is n_sets == 1.  */
-/* { dg-final { scan-tree-dump-times "Simplified relational" 2 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "Simplified relational" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "Simplified relational" 1 "evrp" } } */
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp58.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp58.c
index 5b44ae2..6df91ca 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp58.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp58.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1-details" } */
+/* { dg-options "-O2 -fdump-tree-evrp-details" } */
 
 long long
 foo (long long a, signed char b, signed char c)
@@ -9,4 +9,4 @@ foo (long long a, signed char b, signed char c)
 }
 
 /* { dg-final { scan-tree-dump "Folded into" "vrp1" { target int32plus } } } */
-/* { dg-final { scan-tree-dump "Folding statement: _\[0-9\]\* = \\(long long int\\) bc_\[0-9\]\*;" "vrp1" { target int16 } } } */
+/* { dg-final { scan-tree-dump "Folding statement: _\[0-9\]\* = \\(long long int\\) bc_\[0-9\]\*;" "evrp" { target int16 } } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp67.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp67.c
index ef5e8f9..b19b546 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp67.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp67.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1" } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
 
 extern void link_error (void);
 
@@ -36,4 +36,4 @@ unsigned baz (unsigned i)
   return i;
 }
 
-/* { dg-final { scan-tree-dump-times "Folding predicate" 3 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "Folding predicate" 3 "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp98.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp98.c
index 982f091..6e3b15f 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp98.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp98.c
@@ -1,6 +1,6 @@
 /* { dg-do compile } */
 /* { dg-require-effective-target int128 } */
-/* { dg-options "-Os -fdump-tree-vrp1-details" } */
+/* { dg-options "-Os -fdump-tree-evrp-details -fdump-tree-evrp-details" } */
 
 #include <stdint.h>
 #include <limits.h>
@@ -36,6 +36,6 @@ foo (bigger_than_word a, word b, uint8_t c)
   return ret;
 }
 
-/* { dg-final { scan-tree-dump "Folded into: if \\(_\[0-9\]+ == 1\\)" "vrp1" } } */
+/* { dg-final { scan-tree-dump "Folded into: if \\(_\[0-9\]+ == 1\\)" "evrp" } } */
 /* { dg-final { scan-tree-dump-not "Folded into: if \\(_\[0-9\]+ == 2\\)" "vrp1" } } */
-/* { dg-final { scan-tree-dump "Folded into: if \\(_\[0-9\]+ == 3\\)" "vrp1" } } */
+/* { dg-final { scan-tree-dump "Folded into: if \\(_\[0-9\]+ == 3\\)" "evrp" } } */
diff --git a/gcc/timevar.def b/gcc/timevar.def
index 362aa6e..8d308ac 100644
--- a/gcc/timevar.def
+++ b/gcc/timevar.def
@@ -147,6 +147,7 @@ DEFTIMEVAR (TV_TREE_CFG		     , "tree CFG construction")
 DEFTIMEVAR (TV_TREE_CLEANUP_CFG	     , "tree CFG cleanup")
 DEFTIMEVAR (TV_TREE_TAIL_MERGE       , "tree tail merge")
 DEFTIMEVAR (TV_TREE_VRP              , "tree VRP")
+DEFTIMEVAR (TV_TREE_EARLY_VRP        , "tree Early VRP")
 DEFTIMEVAR (TV_TREE_COPY_PROP        , "tree copy propagation")
 DEFTIMEVAR (TV_FIND_REFERENCED_VARS  , "tree find ref. vars")
 DEFTIMEVAR (TV_TREE_PTA		     , "tree PTA")
diff --git a/gcc/tree-early-vrp.c b/gcc/tree-early-vrp.c
new file mode 100644
index 0000000..adfcbe4
--- /dev/null
+++ b/gcc/tree-early-vrp.c
@@ -0,0 +1,324 @@
+/* Early Value Range Propagation (VRP) Implementation.
+   Copyright (C) 2016 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "insn-codes.h"
+#include "rtl.h"
+#include "tree.h"
+#include "gimple.h"
+#include "cfghooks.h"
+#include "tree-pass.h"
+#include "ssa.h"
+#include "optabs-tree.h"
+#include "gimple-pretty-print.h"
+#include "diagnostic-core.h"
+#include "flags.h"
+#include "fold-const.h"
+#include "stor-layout.h"
+#include "calls.h"
+#include "cfganal.h"
+#include "gimple-fold.h"
+#include "tree-eh.h"
+#include "gimple-iterator.h"
+#include "gimple-walk.h"
+#include "tree-cfg.h"
+#include "tree-ssa-loop-manip.h"
+#include "tree-ssa-loop-niter.h"
+#include "tree-ssa-loop.h"
+#include "tree-into-ssa.h"
+#include "tree-ssa.h"
+#include "intl.h"
+#include "cfgloop.h"
+#include "tree-scalar-evolution.h"
+#include "tree-ssa-propagate.h"
+#include "tree-chrec.h"
+#include "tree-ssa-threadupdate.h"
+#include "tree-ssa-scopedtables.h"
+#include "tree-ssa-threadedge.h"
+#include "omp-low.h"
+#include "target.h"
+#include "case-cfn-macros.h"
+#include "domwalk.h"
+#include "tree-vrp.h"
+
+/* A simplified non-iterative version of visit_phi_node which discovers
+   value ranges for PHI definition. I.e. whenever there is a backedge
+   in the PHI set the PHI definition to VARYING.  */
+
+static enum ssa_prop_result
+vrp_visit_phi_node_local (gphi *phi)
+{
+  size_t i;
+  tree lhs = PHI_RESULT (phi);
+  value_range vr_result = VR_INITIALIZER;
+  bool first = true;
+  int edges;
+
+  edges = 0;
+  for (i = 0; i < gimple_phi_num_args (phi); i++)
+    {
+      edge e = gimple_phi_arg_edge (phi, i);
+      tree arg = PHI_ARG_DEF (phi, i);
+      value_range vr_arg = VR_INITIALIZER;
+      ++edges;
+
+      /* If there is a back-edge, set the result to VARYING.  */
+      if (e->flags & EDGE_DFS_BACK
+	  || e->flags & EDGE_ABNORMAL)
+	{
+	  set_value_range_to_varying (&vr_result);
+	  break;
+	}
+
+      if (TREE_CODE (arg) == SSA_NAME)
+	vr_arg = *(get_value_range (arg));
+      else
+	set_value_range_to_varying (&vr_arg);
+
+      /* If any of the RHS value is VARYING, set the result to VARYING.  */
+      if (vr_arg.type == VR_VARYING)
+	{
+	  set_value_range_to_varying (&vr_result);
+	  break;
+	}
+
+      /* Set/meet the RHS value range with the result so far.  */
+      if (first)
+	set_value_range (&vr_result, vr_arg.type, vr_arg.min,
+			 vr_arg.max, vr_arg.equiv);
+      else
+	vrp_meet (&vr_result, &vr_arg);
+      first = false;
+
+      if (vr_result.type == VR_VARYING)
+	break;
+    }
+
+  /* Check if the value range has changed and return accordingly.  */
+  if (update_value_range (lhs, &vr_result))
+    {
+      if (vr_result.type == VR_VARYING)
+	{
+	  set_value_range_to_varying (&vr_result);
+	  return SSA_PROP_VARYING;
+	}
+      return SSA_PROP_INTERESTING;
+    }
+
+  return SSA_PROP_NOT_INTERESTING;
+}
+
+/* Visit the basic blocks in the dominance order and set the Value Ranges (VR) for
+   SSA_NAMEs in the scope. Use this VR to discover more VRs. Restore the old VR
+   once the scope is exited.  */
+
+class evrp_dom_walker : public dom_walker
+{
+public:
+  evrp_dom_walker ()
+    : dom_walker (CDI_DOMINATORS), cond_stack (vNULL) {}
+
+  void finalize_dom_walker ();
+  virtual edge before_dom_children (basic_block);
+
+  /* Cond_stack holds the old VR.  */
+  vec<std::pair <basic_block, std::pair <tree, value_range*> > > cond_stack;
+};
+
+edge evrp_dom_walker::before_dom_children (basic_block bb)
+{
+  /* If we are going out of scope, restore the old VR.  */
+  while (!cond_stack.is_empty ()
+	 && !dominated_by_p (CDI_DOMINATORS, bb, cond_stack.last ().first))
+    {
+      tree var = cond_stack.last ().second.first;
+      value_range *vr = cond_stack.last ().second.second;
+      value_range *vr_to_del = get_value_range (var);
+      XDELETE (vr_to_del);
+      change_value_range (var, vr);
+      cond_stack.pop ();
+    }
+
+  /* See if there is any new scope is entered with new VR and set that VR to
+     ssa_name before visiting the statements in the scope.  */
+  if (single_pred_p (bb))
+    {
+      edge te = NULL, fe = NULL;
+      edge e = single_pred_edge (bb);
+      value_range vr = VR_INITIALIZER;
+      gimple *stmt = last_stmt (e->src);
+
+      if (stmt
+	  && gimple_code (stmt) == GIMPLE_COND
+	  && INTEGRAL_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt))))
+	{
+	  extract_true_false_edges_from_block (e->src,
+					       &te, &fe);
+	  tree op0 = gimple_cond_lhs (stmt);
+	  tree op1 = gimple_cond_rhs (stmt);
+	  tree_code code = gimple_cond_code (stmt);
+	  value_range *old_vr = get_value_range (op0);
+
+	  /* Discover VR when condition is true.  */
+	  if (te == e
+	      && !TREE_OVERFLOW_P (op0)
+	      && !TREE_OVERFLOW_P (op1))
+	    {
+	      tree cond = build2 (code, boolean_type_node, op0, op1);
+	      tree a = build2 (ASSERT_EXPR, TREE_TYPE (op0), op0, cond);
+	      extract_range_from_assert (&vr, a);
+	      if (old_vr->type == VR_RANGE || old_vr->type == VR_ANTI_RANGE)
+		vrp_intersect_ranges (&vr, old_vr);
+	    }
+	  /* Discover VR when condition is false.  */
+	  else if (fe == e
+	      && !TREE_OVERFLOW_P (op0)
+	      && !TREE_OVERFLOW_P (op1))
+	    {
+	      tree_code code
+		= invert_tree_comparison (gimple_cond_code (stmt),
+					  HONOR_NANS (op0));
+	      tree cond = build2 (code, boolean_type_node, op0, op1);
+	      tree a = build2 (ASSERT_EXPR, TREE_TYPE (op0), op0, cond);
+	      extract_range_from_assert (&vr, a);
+	      if (old_vr->type == VR_RANGE || old_vr->type == VR_ANTI_RANGE)
+		vrp_intersect_ranges (&vr, old_vr);
+	    }
+
+	  /* If we found any usable VR, set the VR to ssa_name and create a
+	     restore point in the cond_stack with the  old VR. */
+	  if (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE)
+	    {
+	      value_range *new_vr = XCNEW (value_range);
+	      *new_vr = vr;
+	      cond_stack.safe_push (std::make_pair (bb,
+						    std::make_pair (op0,
+								    old_vr)));
+	      change_value_range (op0, new_vr);
+	    }
+	}
+    }
+
+  /* Visit  stmts and discover any new VRs possible. */
+  gimple_stmt_iterator gsi;
+  for (gphi_iterator gpi = gsi_start_phis (bb);
+       !gsi_end_p (gpi); gsi_next (&gpi))
+    {
+      gphi *phi = gpi.phi ();
+      if (stmt_interesting_for_vrp (phi))
+	vrp_visit_phi_node_local (phi);
+    }
+
+  for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+    {
+      gimple *stmt = gsi_stmt (gsi);
+      edge taken_edge_p;
+      tree output_p;
+      if (stmt_interesting_for_vrp (stmt))
+	vrp_visit_stmt (stmt, &taken_edge_p, &output_p);
+    }
+
+  return NULL;
+}
+
+
+/* Restore the old VRs maintained in the cond_stack.  */
+void evrp_dom_walker::finalize_dom_walker ()
+{
+  while (!cond_stack.is_empty ())
+    {
+      tree var = cond_stack.last ().second.first;
+      value_range *vr_to_del = get_value_range (var);
+      XDELETE (vr_to_del);
+      value_range *vr = cond_stack.last ().second.second;
+      change_value_range (var, vr);
+      cond_stack.pop ();
+    }
+}
+
+static unsigned int
+execute_early_vrp ()
+{
+  basic_block bb;
+  edge e;
+  edge_iterator ei;
+
+  loop_optimizer_init (LOOPS_NORMAL | LOOPS_HAVE_RECORDED_EXITS);
+  rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa);
+  scev_initialize ();
+  calculate_dominance_info (CDI_DOMINATORS);
+  vrp_initialize ();
+  FOR_EACH_BB_FN (bb, cfun)
+    {
+      FOR_EACH_EDGE (e, ei, bb->preds)
+	e->flags |= EDGE_EXECUTABLE;
+    }
+
+  evrp_dom_walker walker;
+  walker.walk (ENTRY_BLOCK_PTR_FOR_FN (cfun));
+  walker.finalize_dom_walker ();
+
+  vrp_finalize (false, false);
+  free_numbers_of_iterations_estimates (cfun);
+
+  scev_finalize ();
+  loop_optimizer_finalize ();
+  return 0;
+}
+
+namespace {
+
+const pass_data pass_data_early_vrp =
+{
+  GIMPLE_PASS, /* type */
+  "evrp", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_TREE_EARLY_VRP, /* tv_id */
+  PROP_ssa, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  ( TODO_cleanup_cfg | TODO_update_ssa | TODO_verify_all),
+};
+
+class pass_early_vrp : public gimple_opt_pass
+{
+public:
+  pass_early_vrp (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_early_vrp, ctxt)
+    {}
+
+  /* opt_pass methods: */
+  opt_pass * clone () { return new pass_early_vrp (m_ctxt); }
+  virtual bool gate (function *) { return flag_tree_early_vrp != 0; }
+  virtual unsigned int execute (function *)
+    { return execute_early_vrp (); }
+
+}; // class pass_vrp
+
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_early_vrp (gcc::context *ctxt)
+{
+  return new pass_early_vrp (ctxt);
+}
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index 36299a6..d836d57 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -440,6 +440,7 @@ extern gimple_opt_pass *make_pass_fre (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_check_data_deps (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_copy_prop (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_isolate_erroneous_paths (gcc::context *ctxt);
+extern gimple_opt_pass *make_pass_early_vrp (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_vrp (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_uncprop (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_return_slot (gcc::context *ctxt);
-- 
1.9.1


^ permalink raw reply	[flat|nested] 67+ messages in thread

* [RFC][IPA-VRP] Teach tree-vrp to use the VR set in params
  2016-07-15  4:41 [RFC][IPA-VRP] IPA VRP Implementation kugan
                   ` (3 preceding siblings ...)
  2016-07-15  4:45 ` [RFC][IPA-VRP] Early VRP Implementation kugan
@ 2016-07-15  4:47 ` kugan
  2016-07-18 11:33   ` Richard Biener
  4 siblings, 1 reply; 67+ messages in thread
From: kugan @ 2016-07-15  4:47 UTC (permalink / raw)
  To: gcc-patches; +Cc: Richard Biener, Jan Hubicka, Martin Jambor

[-- Attachment #1: Type: text/plain, Size: 256 bytes --]

Hi,



This patch teaches tree-vrp to use the VR set in params.



Thanks,

Kugan



gcc/ChangeLog:



2016-07-14  Kugan Vivekanandarajah  <kuganv@linaro.org>



          * tree-vrp.c (get_value_range): Teach PARM_DECL to use ipa-vrp

          results.


[-- Attachment #2: 0006-Teach-tree-vrp-to-use-ipa-vrp-results.patch --]
[-- Type: text/x-patch, Size: 1104 bytes --]

From 1900ff9210f1dd673f815b3a421c6ec1e02f6e05 Mon Sep 17 00:00:00 2001
From: Kugan Vivekanandarajah <kugan.vivekanandarajah@linaro.org>
Date: Thu, 14 Jul 2016 19:28:10 +1000
Subject: [PATCH 6/6] Teach tree-vrp to use ipa-vrp results

---
 gcc/tree-vrp.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index 8c87c06..ad3891c 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -667,6 +667,20 @@ get_value_range (const_tree var)
 	  if (POINTER_TYPE_P (TREE_TYPE (sym))
 	      && nonnull_arg_p (sym))
 	    set_value_range_to_nonnull (vr, TREE_TYPE (sym));
+	  else if (!POINTER_TYPE_P (TREE_TYPE (sym)))
+	    {
+	      wide_int min, max;
+	      value_range_type rtype = get_range_info (var, &min, &max);
+	      if (rtype == VR_RANGE || rtype == VR_ANTI_RANGE)
+		{
+		  vr->type = rtype;
+		  vr->min = wide_int_to_tree (TREE_TYPE (var), min);
+		  vr->max = wide_int_to_tree (TREE_TYPE (var), max);
+		  vr->equiv = NULL;
+		}
+	      else
+		set_value_range_to_varying (vr);
+	    }
 	  else
 	    set_value_range_to_varying (vr);
 	}
-- 
1.9.1


^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Check for POINTER_TYPE_P before accessing SSA_NAME_PTR_INFO in tree-inline
  2016-07-15  4:43 ` [RFC][IPA-VRP] Check for POINTER_TYPE_P before accessing SSA_NAME_PTR_INFO in tree-inline kugan
@ 2016-07-15  4:47   ` Andrew Pinski
  2016-07-15  7:03     ` kugan
  2016-07-15  7:03     ` Jakub Jelinek
  2016-07-15  7:32   ` Richard Biener
  1 sibling, 2 replies; 67+ messages in thread
From: Andrew Pinski @ 2016-07-15  4:47 UTC (permalink / raw)
  To: kugan; +Cc: gcc-patches, Richard Biener, Jan Hubicka, Martin Jambor

On Thu, Jul 14, 2016 at 9:43 PM, kugan
<kugan.vivekanandarajah@linaro.org> wrote:
>
> Hi,
>
>
>
> This patch adds check for POINTER_TYPE_P before accessing SSA_NAME_PTR_INFO
> in remap_ssa_name in gcc/tree-inline.c. This is not related to IPA_VRP but
> was exposed by that.

SSA_NAME_PTR_INFO should be NULL for non POINTER_TYPE ssa names?  Why
is it not null in your case?
In both cases there is a check for SSA_NAME_PTR_INFO being NULL before using it.

Thanks,
Andrew

>
>
>
> Thanks,
>
> Kugan
>
>
>
>
>
> gcc/ChangeLog:
>
>
>
> 2016-07-14  Kugan Vivekanandarajah  <kuganv@linaro.org>
>
>
>
>         * tree-inline.c (remap_ssa_name): Check for POINTER_TYPE_P before
>
>         accessing SSA_NAME_PTR_INFO.
>
>
>
>
>

^ permalink raw reply	[flat|nested] 67+ messages in thread

* [RFC][IPA-VRP] Add support for IPA VRP in ipa-cp/ipa-prop
  2016-07-15  4:44 ` [RFC][IPA-VRP] Re-factor tree-vrp to factor out common code kugan
@ 2016-07-15  4:47   ` kugan
  2016-07-15 12:23     ` Martin Jambor
  2016-07-17 13:24     ` Prathamesh Kulkarni
  2016-07-22 12:27   ` [RFC][IPA-VRP] Re-factor tree-vrp to factor out common code kugan
  1 sibling, 2 replies; 67+ messages in thread
From: kugan @ 2016-07-15  4:47 UTC (permalink / raw)
  To: gcc-patches; +Cc: Richard Biener, Jan Hubicka, Martin Jambor

[-- Attachment #1: Type: text/plain, Size: 1696 bytes --]

Hi,



This patch extends ipa-cp/ipa-prop infrastructure to handle propagation 
of VR.



Thanks,

Kugan





gcc/testsuite/ChangeLog:



2016-07-14  Kugan Vivekanandarajah  <kuganv@linaro.org>



         * gcc.dg/ipa/vrp1.c: New test.

         * gcc.dg/ipa/vrp2.c: New test.

         * gcc.dg/ipa/vrp3.c: New test.





gcc/ChangeLog:



2016-07-14  Kugan Vivekanandarajah  <kuganv@linaro.org>



         * common.opt: New option -fipa-vrp.

         * ipa-cp.c (ipa_get_vr_lat): New.

         (ipcp_vr_lattice::print): Likewise.

         (print_all_lattices): Call ipcp_vr_lattice::print.

         (ipcp_vr_lattice::meet_with): New.

         (ipcp_vr_lattice::meet_with_1): Likewise.

         (ipcp_vr_lattice::top_p): Likewise.

         (ipcp_vr_lattice::bottom_p): Likewsie.

         (ipcp_vr_lattice::set_to_bottom): Likewise.

         (set_all_contains_variable): Call VR set_to_bottom.

         (initialize_node_lattices): Init VR lattices.

         (propagate_vr_accross_jump_function): New.

         (propagate_constants_accross_call): Call

         propagate_vr_accross_jump_function.

         (ipcp_store_alignment_results): Rename to

         ipcp_store_alignment_and_vr_results and handke VR.

         * ipa-prop.c (ipa_set_jf_unknown):

         (ipa_compute_jump_functions_for_edge): Handle Value Range.

         (ipa_node_params_t::duplicate): Likewise.

         (ipa_write_jump_function): Likewise.

         (ipa_read_jump_function): Likewise.

         (write_ipcp_transformation_info): Likewise.

         (read_ipcp_transformation_info): Likewise.

         (ipcp_update_alignments): Rename to ipcp_update_vr_and_alignments

         and handle VR.






[-- Attachment #2: 0005-Add-ipa-vrp.patch --]
[-- Type: text/x-patch, Size: 24497 bytes --]

From 092cbccd79c3859ff24846bb0e1892ef5d8086bc Mon Sep 17 00:00:00 2001
From: Kugan Vivekanandarajah <kugan.vivekanandarajah@linaro.org>
Date: Tue, 21 Jun 2016 12:43:01 +1000
Subject: [PATCH 5/6] Add ipa vrp

---
 gcc/common.opt                  |   4 +
 gcc/ipa-cp.c                    | 220 +++++++++++++++++++++++++++++++++++++++-
 gcc/ipa-prop.c                  | 110 ++++++++++++++++++--
 gcc/ipa-prop.h                  |  16 +++
 gcc/testsuite/gcc.dg/ipa/vrp1.c |  32 ++++++
 gcc/testsuite/gcc.dg/ipa/vrp2.c |  35 +++++++
 gcc/testsuite/gcc.dg/ipa/vrp3.c |  30 ++++++
 7 files changed, 433 insertions(+), 14 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/ipa/vrp1.c
 create mode 100644 gcc/testsuite/gcc.dg/ipa/vrp2.c
 create mode 100644 gcc/testsuite/gcc.dg/ipa/vrp3.c

diff --git a/gcc/common.opt b/gcc/common.opt
index 29d0e4d..7bf7305 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2475,6 +2475,10 @@ ftree-evrp
 Common Report Var(flag_tree_early_vrp) Init(1) Optimization
 Perform Early Value Range Propagation on trees.
 
+fipa-vrp
+ommon Report Var(flag_ipa_vrp) Init(1) Optimization
+Perform IPA Value Range Propagation on trees.
+
 fsplit-paths
 Common Report Var(flag_split_paths) Init(0) Optimization
 Split paths leading to loop backedges.
diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
index 4b7f6bb..97cd04b 100644
--- a/gcc/ipa-cp.c
+++ b/gcc/ipa-cp.c
@@ -120,6 +120,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "params.h"
 #include "ipa-inline.h"
 #include "ipa-utils.h"
+#include "tree-vrp.h"
 
 template <typename valtype> class ipcp_value;
 
@@ -266,6 +267,25 @@ 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);
+};
+
 /* 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 +301,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 +370,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 +489,16 @@ 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)
+{
+  fprintf (f, "         ");
+  dump_value_range (f, &vr);
+  fprintf (f, "\n");
+}
+
 /* Print all ipcp_lattices of all functions to F.  */
 
 static void
@@ -484,6 +525,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 +870,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.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 = vr.min, max = vr.max;
+  value_range_type type = vr.type;
+
+  if (bottom_p ())
+    return false;
+
+  if (other_vr->type == VR_VARYING)
+    return set_to_bottom ();
+
+  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 +1028,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;
 }
 
@@ -985,6 +1099,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->vr.init ();
+    }
+
   if (disable || variable)
     {
       for (i = 0; i < ipa_get_param_count (info) ; i++)
@@ -996,6 +1116,7 @@ initialize_node_lattices (struct cgraph_node *node)
 	      plats->ctxlat.set_to_bottom ();
 	      set_agg_lats_to_bottom (plats);
 	      plats->alignment.set_to_bottom ();
+	      plats->vr.set_to_bottom ();
 	    }
 	  else
 	    set_all_contains_variable (plats);
@@ -1614,7 +1735,62 @@ 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 (cgraph_edge *cs,
+				    ipa_jump_func *jfunc,
+				    struct ipcp_param_lattices *dest_plats)
+{
+  struct ipcp_param_lattices *src_lats;
+  enum availability availability;
+  cgraph_node *callee = cs->callee->function_symbol (&availability);
+  struct ipa_node_params *callee_info = IPA_NODE_REF (callee);
+  ipcp_vr_lattice *dest_lat = &dest_plats->vr;
+
+  if (dest_lat->bottom_p ())
+    return false;
+
+  if (callee_info->versionable)
+    return dest_lat->set_to_bottom ();
+
+  if (jfunc->type == IPA_JF_PASS_THROUGH)
+    {
+      struct ipa_node_params *caller_info = IPA_NODE_REF (cs->caller);
+      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->vr);
+    }
+  else if (jfunc->type == IPA_JF_ANCESTOR)
+    {
+      struct ipa_node_params *caller_info = IPA_NODE_REF (cs->caller);
+      int src_idx = ipa_get_jf_ancestor_formal_id (jfunc);
+      src_lats = ipa_get_parm_lattices (caller_info, src_idx);
+
+      return dest_lat->meet_with (src_lats->vr);
+    }
+  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->vr.type = VR_RANGE;
+	  jfunc->vr.min = val;
+	  jfunc->vr.max = val;
+	  return dest_lat->meet_with (&jfunc->vr);
+	}
+    }
+
+  if (jfunc->vr_known)
+    return dest_lat->meet_with (&jfunc->vr);
+  else
+    return dest_lat->set_to_bottom ();
+}
+
+/* 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.  */
@@ -1963,6 +2139,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 (cs, jump_func, dest_plats);
 	}
     }
   for (; i < parms_count; i++)
@@ -4514,7 +4691,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;
 
@@ -4523,6 +4700,8 @@ ipcp_store_alignment_results (void)
     ipa_node_params *info = IPA_NODE_REF (node);
     bool dumped_sth = false;
     bool found_useful_result = false;
+    bool do_not_update_alignment = false;
+    bool do_not_update_vr = false;
 
     if (!opt_for_fn (node->decl, flag_ipa_cp_alignment))
       {
@@ -4530,7 +4709,16 @@ ipcp_store_alignment_results (void)
 	  fprintf (dump_file, "Not considering %s for alignment discovery "
 		   "and propagate; -fipa-cp-alignment: disabled.\n",
 		   node->name ());
-	continue;
+	do_not_update_alignment = true;
+      }
+
+    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 ());
+	do_not_update_vr = true;
       }
 
    if (info->ipcp_orig_node)
@@ -4540,13 +4728,21 @@ ipcp_store_alignment_results (void)
    for (unsigned i = 0; i < count ; i++)
      {
        ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
-       if (!plats->alignment.bottom_p ()
+       if (!do_not_update_alignment
+	   && !plats->alignment.bottom_p ()
 	   && !plats->alignment.top_p ())
 	 {
 	   gcc_checking_assert (plats->alignment.align > 0);
 	   found_useful_result = true;
 	   break;
 	 }
+       if (!do_not_update_vr
+	   && !plats->vr.bottom_p ()
+	   && !plats->vr.top_p ())
+	 {
+	   found_useful_result = true;
+	   break;
+	 }
      }
    if (!found_useful_result)
      continue;
@@ -4554,11 +4750,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 ())
@@ -4570,7 +4768,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)
@@ -4617,7 +4827,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 132b622..25a4d49 100644
--- a/gcc/ipa-prop.c
+++ b/gcc/ipa-prop.c
@@ -41,6 +41,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimplify-me.h"
 #include "gimple-walk.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "tree-cfg.h"
 #include "tree-dfa.h"
@@ -381,6 +382,7 @@ ipa_set_jf_unknown (struct ipa_jump_func *jfunc)
 {
   jfunc->type = IPA_JF_UNKNOWN;
   jfunc->alignment.known = false;
+  jfunc->vr_known = false;
 }
 
 /* Set JFUNC to be a copy of another jmp (to be used by jump function
@@ -1672,7 +1674,21 @@ 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);
+	    }
+	  else
+	    gcc_assert (!jfunc->vr_known);
+	}
 
       if (is_gimple_ip_invariant (arg)
 	  || (TREE_CODE (arg) == VAR_DECL
@@ -3679,16 +3695,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]);
     }
 }
 
@@ -4609,6 +4633,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.  */
@@ -4685,6 +4717,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
@@ -5027,7 +5070,9 @@ 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 ();
 
@@ -5035,6 +5080,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);
@@ -5046,6 +5092,16 @@ 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
@@ -5085,11 +5141,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);
@@ -5100,6 +5159,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);
+	    }
 	}
     }
 }
@@ -5356,15 +5423,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)
@@ -5374,13 +5443,36 @@ 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 (cgraph_local_p (node)
+	  && vr[i].known
+	  && INTEGRAL_TYPE_P (TREE_TYPE (ddef))
+	  && !POINTER_TYPE_P (TREE_TYPE (ddef))
+	  && (vr[i].type == VR_RANGE || vr[i].type == VR_ANTI_RANGE)
+	  && 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,
@@ -5422,7 +5514,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 e32d078..490be5f 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/testsuite/gcc.dg/ipa/vrp1.c b/gcc/testsuite/gcc.dg/ipa/vrp1.c
new file mode 100644
index 0000000..72a3139
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/vrp1.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-ipa-cp-details" } */
+
+static __attribute__((noinline, noclone))
+int foo (int i)
+{
+  if (i < 5)
+    __builtin_abort ();
+  return 0;
+}
+
+static __attribute__((noinline, noclone))
+int bar (int j)
+{
+  if (j > 8)
+    return foo (j + 2);
+  else if (j > 2)
+    return foo (j + 3);
+
+  return 0;
+}
+
+int main ()
+{
+  for (unsigned int i =0; i < 1000; ++i)
+    bar (i);
+
+  return 0;
+}
+
+/* { dg-final { scan-ipa-dump "Setting value range of param 0 \\\[6," "cp" } } */
+/* { dg-final { scan-ipa-dump "Setting value range of param 0 \\\[0, 999\\\]" "cp" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/vrp2.c b/gcc/testsuite/gcc.dg/ipa/vrp2.c
new file mode 100644
index 0000000..c720e5c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/vrp2.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-ipa-cp-details" } */
+
+static __attribute__((noinline, noclone))
+int foo (int i)
+{
+  if (i < 4)
+    __builtin_abort ();
+  return 0;
+}
+
+static __attribute__((noinline, noclone))
+int bar (int j)
+{
+  if (j > 8)
+    return foo (j + 2);
+  else if (j > 2)
+    return foo (j + 3);
+
+  return 0;
+}
+
+int main ()
+{
+  foo (100);
+  for (unsigned int i = 0; i < 12; ++i)
+    {
+      bar (i);
+    }
+  foo (4);
+  return 0;
+}
+
+/* { dg-final { scan-ipa-dump "Setting value range of param 0 \\\[4," "cp" } } */
+/* { dg-final { scan-ipa-dump "Setting value range of param 0 \\\[0, 11\\\]" "cp" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/vrp3.c b/gcc/testsuite/gcc.dg/ipa/vrp3.c
new file mode 100644
index 0000000..fb5d54a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/vrp3.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-ipa-cp-details" } */
+
+volatile int cond;
+
+static __attribute__((noinline, noclone))
+int foo (int i)
+{
+  if (i < 5)
+    __builtin_abort ();
+  return 0;
+}
+
+static __attribute__((noinline, noclone))
+int bar (int j)
+{
+  if (cond)
+    foo (j);
+  return 0;
+}
+
+int main ()
+{
+  for (unsigned int i = 0; i < 10; ++i)
+    bar (i);
+
+  return 0;
+}
+
+/* { dg-final { scan-ipa-dump-times "Setting value range of param 0 \\\[0, 9\\\]" 2 "cp" } } */
-- 
1.9.1


^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Early VRP Implementation
  2016-07-15  4:45 ` [RFC][IPA-VRP] Early VRP Implementation kugan
@ 2016-07-15  4:52   ` Andrew Pinski
  2016-07-15  7:08     ` kugan
  2016-07-19 16:19     ` Jeff Law
  0 siblings, 2 replies; 67+ messages in thread
From: Andrew Pinski @ 2016-07-15  4:52 UTC (permalink / raw)
  To: kugan; +Cc: gcc-patches, Richard Biener, Jan Hubicka, Martin Jambor

On Thu, Jul 14, 2016 at 9:45 PM, kugan
<kugan.vivekanandarajah@linaro.org> wrote:
>
> Hi,
>
>
>
> This patch adds a very simple early vrp implementation. This visits the
> basic blocks in the dominance order and set the Value Ranges (VR) for
>
> SSA_NAMEs in the scope. Use this VR to discover more VRs. Restore the old VR
> once the scope is exit.


Why separate out early VRP from tree-vrp?  Just a little curious.
Also it seems like if you are going to do that, putting the following
functions in a class would be better:
+extern void vrp_initialize (void);
+extern void vrp_finalize (bool update, bool warn_array_bounds_p);
+extern void vrp_intersect_ranges (value_range *vr0, value_range *vr1);
+extern void vrp_meet (value_range *vr0, value_range *vr1);
+extern enum ssa_prop_result vrp_visit_stmt (gimple *stmt,
+    edge *taken_edge_p,
+    tree *output_p);
+extern enum ssa_prop_result vrp_visit_phi_node (gphi *phi);
+extern bool stmt_interesting_for_vrp (gimple *stmt);
+
+extern void extract_range_from_assert (value_range *vr_p, tree expr);
+extern bool update_value_range (const_tree var, value_range *vr);
+extern value_range *get_value_range (const_tree var);
+extern void set_value_range (value_range *vr, enum value_range_type t,
+     tree min, tree max, bitmap equiv);
+extern void change_value_range (const_tree var, value_range *new_vr);
+
+extern void dump_value_range (FILE *, value_range *);

That is vrp_initialize becomes the constructor and vrp_finalize
becomes the deconstructor.
With both jump_thread and warn_array_bounds_p being variables you set
while running your pass.

Thanks,
Andrew

>
>
>
> Thanks,
>
> Kugan
>
>
>
>
>
> gcc/ChangeLog:
>
>
>
> 2016-07-14  Kugan Vivekanandarajah  <kuganv@linaro.org>
>
>
>
>         * Makefile.in: Add tree-early-vrp.o.
>
>         * common.opt: New option -ftree-evrp.
>
>         * doc/invoke.texi: Document -ftree-evrp.
>
>         * passes.def: Define new pass_early_vrp.
>
>         * timevar.def: Define new TV_TREE_EARLY_VRP.
>
>         * tree-early-vrp.c: New file.
>
>         * tree-pass.h (make_pass_early_vrp): New.
>
>
>
> gcc/testsuite/ChangeLog:
>
>
>
> 2016-07-14  Kugan Vivekanandarajah  <kuganv@linaro.org>
>
>
>
>         * gcc.dg/tree-ssa/evrp1.c: New test.
>
>         * gcc.dg/tree-ssa/evrp2.c: New test.
>
>         * gcc.dg/tree-ssa/evrp3.c: New test.
>
>         * g++.dg/tree-ssa/pr31146-2.C: Run with -fno-tree-evrp as evrp also
>
>         does the same transformation.
>
>         * gcc.dg/tree-ssa/pr20318.c: Check for the pattern in evrp dump.
>
>         * gcc.dg/tree-ssa/pr22117.c: Likewise.
>
>         * gcc.dg/tree-ssa/pr25382.c: Likewise.
>
>         * gcc.dg/tree-ssa/pr68431.c: LIkewise.
>
>         * gcc.dg/tree-ssa/vrp19.c: Likewise.
>
>         * gcc.dg/tree-ssa/vrp23.c: Likewise.
>
>         * gcc.dg/tree-ssa/vrp24.c: Likewise.
>
>         * gcc.dg/tree-ssa/vrp58.c: Likewise.
>
>         * gcc.dg/tree-ssa/vrp67.c: Likewise.
>
>         * gcc.dg/tree-ssa/vrp98.c: Likewise.
>
>
>
>
>

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Check for POINTER_TYPE_P before accessing SSA_NAME_PTR_INFO in tree-inline
  2016-07-15  4:47   ` Andrew Pinski
  2016-07-15  7:03     ` kugan
@ 2016-07-15  7:03     ` Jakub Jelinek
  1 sibling, 0 replies; 67+ messages in thread
From: Jakub Jelinek @ 2016-07-15  7:03 UTC (permalink / raw)
  To: Andrew Pinski
  Cc: kugan, gcc-patches, Richard Biener, Jan Hubicka, Martin Jambor

On Thu, Jul 14, 2016 at 09:47:03PM -0700, Andrew Pinski wrote:
> On Thu, Jul 14, 2016 at 9:43 PM, kugan
> <kugan.vivekanandarajah@linaro.org> wrote:
> > This patch adds check for POINTER_TYPE_P before accessing SSA_NAME_PTR_INFO
> > in remap_ssa_name in gcc/tree-inline.c. This is not related to IPA_VRP but
> > was exposed by that.
> 
> SSA_NAME_PTR_INFO should be NULL for non POINTER_TYPE ssa names?  Why
> is it not null in your case?

??
  /* Value range information.  */
  union ssa_name_info_type {
    /* Pointer attributes used for alias analysis.  */
    struct GTY ((tag ("0"))) ptr_info_def *ptr_info;
    /* Value range attributes used for zero/sign extension elimination.  */
    struct GTY ((tag ("1"))) range_info_def *range_info;
  } GTY ((desc ("%1.typed.type ?" \
                "!POINTER_TYPE_P (TREE_TYPE ((tree)&%1)) : 2"))) info;

SSA_NAME_PTR_INFO and SSA_NAME_RANGE_INFO share space, so all uses of
SSA_NAME_PTR_INFO should be only used for pointer types and
SSA_NAME_RANGE_INFO only for integral types.

	Jakub

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Check for POINTER_TYPE_P before accessing SSA_NAME_PTR_INFO in tree-inline
  2016-07-15  4:47   ` Andrew Pinski
@ 2016-07-15  7:03     ` kugan
  2016-07-15  7:03     ` Jakub Jelinek
  1 sibling, 0 replies; 67+ messages in thread
From: kugan @ 2016-07-15  7:03 UTC (permalink / raw)
  To: Andrew Pinski; +Cc: gcc-patches, Richard Biener, Jan Hubicka, Martin Jambor



Hi Andrew,

>> This patch adds check for POINTER_TYPE_P before accessing SSA_NAME_PTR_INFO
>> in remap_ssa_name in gcc/tree-inline.c. This is not related to IPA_VRP but
>> was exposed by that.
>
> SSA_NAME_PTR_INFO should be NULL for non POINTER_TYPE ssa names?  Why
> is it not null in your case?
> In both cases there is a check for SSA_NAME_PTR_INFO being NULL before using it.

As per tree.h:

#define SSA_NAME_PTR_INFO(N) \
    SSA_NAME_CHECK (N)->ssa_name.info.ptr_info

#define SSA_NAME_RANGE_INFO(N) \
     SSA_NAME_CHECK (N)->ssa_name.info.range_info

ptr_info and range_info are unions (see below). Unless I am missing 
something, now that we set range_info, we should check it is 
POINTER_TYPE_P before accessing.

   /* Value range information.  */
   union ssa_name_info_type {
     /* Pointer attributes used for alias analysis.  */
     struct GTY ((tag ("0"))) ptr_info_def *ptr_info;
     /* Value range attributes used for zero/sign extension elimination.  */
     struct GTY ((tag ("1"))) range_info_def *range_info;
   } GTY ((desc ("%1.typed.type ?" \
		"!POINTER_TYPE_P (TREE_TYPE ((tree)&%1)) : 2"))) info;


Thanks,
Kugan

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Early VRP Implementation
  2016-07-15  4:52   ` Andrew Pinski
@ 2016-07-15  7:08     ` kugan
  2016-07-15  7:28       ` Andrew Pinski
  2016-07-19 16:19     ` Jeff Law
  1 sibling, 1 reply; 67+ messages in thread
From: kugan @ 2016-07-15  7:08 UTC (permalink / raw)
  To: Andrew Pinski; +Cc: gcc-patches, Richard Biener, Jan Hubicka, Martin Jambor

Hi Andrew,

> Why separate out early VRP from tree-vrp?  Just a little curious.

It is based on the discussion in 
https://gcc.gnu.org/ml/gcc/2016-01/msg00069.html.
In summary, conclusion (based on my understanding) was to implement a 
simplified VRP algorithm that doesn't require ASSERT_EXPR insertion.


> Also it seems like if you are going to do that, putting the following
> functions in a class would be better:
> +extern void vrp_initialize (void);
> +extern void vrp_finalize (bool update, bool warn_array_bounds_p);
> +extern void vrp_intersect_ranges (value_range *vr0, value_range *vr1);
> +extern void vrp_meet (value_range *vr0, value_range *vr1);
> +extern enum ssa_prop_result vrp_visit_stmt (gimple *stmt,
> +    edge *taken_edge_p,
> +    tree *output_p);
> +extern enum ssa_prop_result vrp_visit_phi_node (gphi *phi);
> +extern bool stmt_interesting_for_vrp (gimple *stmt);
> +
> +extern void extract_range_from_assert (value_range *vr_p, tree expr);
> +extern bool update_value_range (const_tree var, value_range *vr);
> +extern value_range *get_value_range (const_tree var);
> +extern void set_value_range (value_range *vr, enum value_range_type t,
> +     tree min, tree max, bitmap equiv);
> +extern void change_value_range (const_tree var, value_range *new_vr);
> +
> +extern void dump_value_range (FILE *, value_range *);
>
> That is vrp_initialize becomes the constructor and vrp_finalize
> becomes the deconstructor.
> With both jump_thread and warn_array_bounds_p being variables you set
> while running your pass.

I will give this a try.

Thanks,
Kugan

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Early VRP Implementation
  2016-07-15  7:08     ` kugan
@ 2016-07-15  7:28       ` Andrew Pinski
  2016-07-15  7:33         ` kugan
  0 siblings, 1 reply; 67+ messages in thread
From: Andrew Pinski @ 2016-07-15  7:28 UTC (permalink / raw)
  To: kugan; +Cc: gcc-patches, Richard Biener, Jan Hubicka, Martin Jambor

On Fri, Jul 15, 2016 at 12:08 AM, kugan
<kugan.vivekanandarajah@linaro.org> wrote:
> Hi Andrew,
>
>> Why separate out early VRP from tree-vrp?  Just a little curious.
>
>
> It is based on the discussion in
> https://gcc.gnu.org/ml/gcc/2016-01/msg00069.html.
> In summary, conclusion (based on my understanding) was to implement a
> simplified VRP algorithm that doesn't require ASSERT_EXPR insertion.

But I don't see why you are moving it from tree-vrp.c .  That was my
question, you pointing to that discussion does not say to split it
into a new file and expose these interfaces.

Thanks,
Andrew Pinski

>
>
>> Also it seems like if you are going to do that, putting the following
>> functions in a class would be better:
>> +extern void vrp_initialize (void);
>> +extern void vrp_finalize (bool update, bool warn_array_bounds_p);
>> +extern void vrp_intersect_ranges (value_range *vr0, value_range *vr1);
>> +extern void vrp_meet (value_range *vr0, value_range *vr1);
>> +extern enum ssa_prop_result vrp_visit_stmt (gimple *stmt,
>> +    edge *taken_edge_p,
>> +    tree *output_p);
>> +extern enum ssa_prop_result vrp_visit_phi_node (gphi *phi);
>> +extern bool stmt_interesting_for_vrp (gimple *stmt);
>> +
>> +extern void extract_range_from_assert (value_range *vr_p, tree expr);
>> +extern bool update_value_range (const_tree var, value_range *vr);
>> +extern value_range *get_value_range (const_tree var);
>> +extern void set_value_range (value_range *vr, enum value_range_type t,
>> +     tree min, tree max, bitmap equiv);
>> +extern void change_value_range (const_tree var, value_range *new_vr);
>> +
>> +extern void dump_value_range (FILE *, value_range *);
>>
>> That is vrp_initialize becomes the constructor and vrp_finalize
>> becomes the deconstructor.
>> With both jump_thread and warn_array_bounds_p being variables you set
>> while running your pass.
>
>
> I will give this a try.
>
> Thanks,
> Kugan

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Check for POINTER_TYPE_P before accessing SSA_NAME_PTR_INFO in tree-inline
  2016-07-15  4:43 ` [RFC][IPA-VRP] Check for POINTER_TYPE_P before accessing SSA_NAME_PTR_INFO in tree-inline kugan
  2016-07-15  4:47   ` Andrew Pinski
@ 2016-07-15  7:32   ` Richard Biener
  1 sibling, 0 replies; 67+ messages in thread
From: Richard Biener @ 2016-07-15  7:32 UTC (permalink / raw)
  To: kugan; +Cc: gcc-patches, Jan Hubicka, Martin Jambor

On Fri, Jul 15, 2016 at 6:43 AM, kugan
<kugan.vivekanandarajah@linaro.org> wrote:
>
> Hi,
>
>
>
> This patch adds check for POINTER_TYPE_P before accessing SSA_NAME_PTR_INFO
> in remap_ssa_name in gcc/tree-inline.c. This is not related to IPA_VRP but
> was exposed by that.

Ok.  (before your IPA VRP nothing sets RANGE_INFO on SSA vars before
inlining is complete)

Thanks,
Richard.

>
>
> Thanks,
>
> Kugan
>
>
>
>
>
> gcc/ChangeLog:
>
>
>
> 2016-07-14  Kugan Vivekanandarajah  <kuganv@linaro.org>
>
>
>
>         * tree-inline.c (remap_ssa_name): Check for POINTER_TYPE_P before
>
>         accessing SSA_NAME_PTR_INFO.
>
>
>
>
>

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Early VRP Implementation
  2016-07-15  7:28       ` Andrew Pinski
@ 2016-07-15  7:33         ` kugan
  2016-07-18 11:51           ` Richard Biener
  0 siblings, 1 reply; 67+ messages in thread
From: kugan @ 2016-07-15  7:33 UTC (permalink / raw)
  To: Andrew Pinski; +Cc: gcc-patches, Richard Biener, Jan Hubicka, Martin Jambor

Hi Andrew,

On 15/07/16 17:28, Andrew Pinski wrote:
> On Fri, Jul 15, 2016 at 12:08 AM, kugan
> <kugan.vivekanandarajah@linaro.org> wrote:
>> Hi Andrew,
>>
>>> Why separate out early VRP from tree-vrp?  Just a little curious.
>>
>>
>> It is based on the discussion in
>> https://gcc.gnu.org/ml/gcc/2016-01/msg00069.html.
>> In summary, conclusion (based on my understanding) was to implement a
>> simplified VRP algorithm that doesn't require ASSERT_EXPR insertion.
>
> But I don't see why you are moving it from tree-vrp.c .  That was my
> question, you pointing to that discussion does not say to split it
> into a new file and expose these interfaces.
>

Are you saying that I should keep this part of tree-vrp.c. I am happy to 
do that if this is considered the best approach.

Thanks,
Kugan

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Disable setting param of __builtin_constant_p to null
  2016-07-15  4:42 ` [RFC][IPA-VRP] Disable setting param of __builtin_constant_p to null kugan
@ 2016-07-15  8:43   ` Jan Hubicka
  2016-07-25  6:59     ` kugan
  0 siblings, 1 reply; 67+ messages in thread
From: Jan Hubicka @ 2016-07-15  8:43 UTC (permalink / raw)
  To: kugan; +Cc: gcc-patches, Richard Biener, Jan Hubicka, Martin Jambor

> Hi,
> 
> 
> 
> VRP assumes that it is run after inlining. Therefore, if there is a
> call to __builtin_constant_p with function parameter, it resolve it
> to false to avoid bogus warnings. Since we use this as an early vrp
> before inling, it leads to  wrong code. As a workaround I have
> disabled it for the time being. That is, this patch is not intended
> for committing but just to get the VRP tested.
> 
> 
> 
> Original patch which introduced this also talks about doing it earlier.
> 
> 
> 
> 
> 
> Thanks,
> 
> Kugan

> >From 99f8e7884d582cfae2d7cb50ad59dab7ac6772fc Mon Sep 17 00:00:00 2001
> From: Kugan Vivekanandarajah <kugan.vivekanandarajah@linaro.org>
> Date: Sat, 25 Jun 2016 11:52:57 +1000
> Subject: [PATCH 1/6] Hack-Prevent setting __builtin_constant_p of param to
>  null before inlining in Early VRP
> 
> ---
>  gcc/tree-vrp.c | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
> index ecfab1f..23c12b5 100644
> --- a/gcc/tree-vrp.c
> +++ b/gcc/tree-vrp.c
> @@ -3759,8 +3759,10 @@ extract_range_basic (value_range *vr, gimple *stmt)
>  	      && SSA_NAME_IS_DEFAULT_DEF (arg)
>  	      && TREE_CODE (SSA_NAME_VAR (arg)) == PARM_DECL)
>  	    {
> +#if 0
>  	      set_value_range_to_null (vr, type);
>  	      return;
> +#endif

It is not cleanest either, but better to test cfun->after_inlining

Honza

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Add support for IPA VRP in ipa-cp/ipa-prop
  2016-07-15  4:47   ` [RFC][IPA-VRP] Add support for IPA VRP in ipa-cp/ipa-prop kugan
@ 2016-07-15 12:23     ` Martin Jambor
  2016-07-19  8:22       ` kugan
  2016-07-17 13:24     ` Prathamesh Kulkarni
  1 sibling, 1 reply; 67+ messages in thread
From: Martin Jambor @ 2016-07-15 12:23 UTC (permalink / raw)
  To: kugan; +Cc: gcc-patches, Richard Biener, Jan Hubicka

Hi,

thanks for working on extending IPA-CP in this way.  I do have a few
comments though:

On Fri, Jul 15, 2016 at 02:46:50PM +1000, kugan wrote:
> Hi,
> 
> This patch extends ipa-cp/ipa-prop infrastructure to handle propagation of
> VR.
> Thanks,
> 
> Kugan
> 
> gcc/testsuite/ChangeLog:
> 
> 2016-07-14  Kugan Vivekanandarajah  <kuganv@linaro.org>
> 
>         * gcc.dg/ipa/vrp1.c: New test.
>         * gcc.dg/ipa/vrp2.c: New test.
>         * gcc.dg/ipa/vrp3.c: New test.
> 
> gcc/ChangeLog:
> 
> 2016-07-14  Kugan Vivekanandarajah  <kuganv@linaro.org>
> 
>         * common.opt: New option -fipa-vrp.
>         * ipa-cp.c (ipa_get_vr_lat): New.
>         (ipcp_vr_lattice::print): Likewise.
>         (print_all_lattices): Call ipcp_vr_lattice::print.
>         (ipcp_vr_lattice::meet_with): New.
>         (ipcp_vr_lattice::meet_with_1): Likewise.
>         (ipcp_vr_lattice::top_p): Likewise.
>         (ipcp_vr_lattice::bottom_p): Likewsie.
>         (ipcp_vr_lattice::set_to_bottom): Likewise.
>         (set_all_contains_variable): Call VR set_to_bottom.
>         (initialize_node_lattices): Init VR lattices.
>         (propagate_vr_accross_jump_function): New.
>         (propagate_constants_accross_call): Call
>         propagate_vr_accross_jump_function.
>         (ipcp_store_alignment_results): Rename to
>         ipcp_store_alignment_and_vr_results and handke VR.
>         * ipa-prop.c (ipa_set_jf_unknown):
>         (ipa_compute_jump_functions_for_edge): Handle Value Range.
>         (ipa_node_params_t::duplicate): Likewise.
>         (ipa_write_jump_function): Likewise.
>         (ipa_read_jump_function): Likewise.
>         (write_ipcp_transformation_info): Likewise.
>         (read_ipcp_transformation_info): Likewise.
>         (ipcp_update_alignments): Rename to ipcp_update_vr_and_alignments
>         and handle VR.
> 

> From 092cbccd79c3859ff24846bb0e1892ef5d8086bc Mon Sep 17 00:00:00 2001
> From: Kugan Vivekanandarajah <kugan.vivekanandarajah@linaro.org>
> Date: Tue, 21 Jun 2016 12:43:01 +1000
> Subject: [PATCH 5/6] Add ipa vrp
> 
> ---
>  gcc/common.opt                  |   4 +
>  gcc/ipa-cp.c                    | 220 +++++++++++++++++++++++++++++++++++++++-
>  gcc/ipa-prop.c                  | 110 ++++++++++++++++++--
>  gcc/ipa-prop.h                  |  16 +++
>  gcc/testsuite/gcc.dg/ipa/vrp1.c |  32 ++++++
>  gcc/testsuite/gcc.dg/ipa/vrp2.c |  35 +++++++
>  gcc/testsuite/gcc.dg/ipa/vrp3.c |  30 ++++++
>  7 files changed, 433 insertions(+), 14 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.dg/ipa/vrp1.c
>  create mode 100644 gcc/testsuite/gcc.dg/ipa/vrp2.c
>  create mode 100644 gcc/testsuite/gcc.dg/ipa/vrp3.c
> 
> diff --git a/gcc/common.opt b/gcc/common.opt
> index 29d0e4d..7bf7305 100644
> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -2475,6 +2475,10 @@ ftree-evrp
>  Common Report Var(flag_tree_early_vrp) Init(1) Optimization
>  Perform Early Value Range Propagation on trees.
>  
> +fipa-vrp
> +ommon Report Var(flag_ipa_vrp) Init(1) Optimization

Common

> +Perform IPA Value Range Propagation on trees.

I think that nowadays we should omit the "on trees" part, they are not
particularly useful.

> +
>  fsplit-paths
>  Common Report Var(flag_split_paths) Init(0) Optimization
>  Split paths leading to loop backedges.
> diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
> index 4b7f6bb..97cd04b 100644
> --- a/gcc/ipa-cp.c
> +++ b/gcc/ipa-cp.c
> @@ -120,6 +120,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "params.h"
>  #include "ipa-inline.h"
>  #include "ipa-utils.h"
> +#include "tree-vrp.h"
>  
>  template <typename valtype> class ipcp_value;
>  
> @@ -266,6 +267,25 @@ 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);

Please do not call the parameter the same name as that of a member
variable, that might become very confusing in future.

> +  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);

Likewise.

I know that no other classes in the file do, but if you want to
strictly follow the GCC coding style, member vr should be called m_vr.
Perhaps I should add the m_ prefixes to other classes as well, I am
becoming to appreciate them.

> +};
> +
>  /* 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 +301,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 +370,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.  */

GCC coding style requires (exactly) one blank in between a function
and its preceding comment.

> +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 +489,16 @@ 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)
> +{
> +  fprintf (f, "         ");

Please move the above line to the caller.  It will make the function
much more versatile, for example also reasonably callable from the debugger.

> +  dump_value_range (f, &vr);
> +  fprintf (f, "\n");
> +}
> +
>  /* Print all ipcp_lattices of all functions to F.  */
>  
>  static void
> @@ -484,6 +525,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 +870,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.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);

As I wrote above, the parameter should have a name different from a
member variable.  Moreover, I do not really understand why you need
meet_with_1, why don't you just do the meet here?

> +}
> +
> +/* 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 = vr.min, max = vr.max;
> +  value_range_type type = vr.type;
> +
> +  if (bottom_p ())
> +    return false;
> +
> +  if (other_vr->type == VR_VARYING)
> +    return set_to_bottom ();
> +
> +  vrp_meet (&vr, const_cast<value_range *> (other_vr));

The const cast is bad.  Please try to make the second parameter of
vrp_meet const first.  Only if it for some reason proves to be so big
a task that it would unreasonably delay the IPA-VRP implementation,
then explain why that is so and we might leave the cast here.

> +  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.  */

s/alignment/value range/ or just omit the word completely.

> +
> +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 +1028,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;
>  }
>  
> @@ -985,6 +1099,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->vr.init ();
> +    }
> +
>    if (disable || variable)
>      {
>        for (i = 0; i < ipa_get_param_count (info) ; i++)
> @@ -996,6 +1116,7 @@ initialize_node_lattices (struct cgraph_node *node)
>  	      plats->ctxlat.set_to_bottom ();
>  	      set_agg_lats_to_bottom (plats);
>  	      plats->alignment.set_to_bottom ();
> +	      plats->vr.set_to_bottom ();
>  	    }
>  	  else
>  	    set_all_contains_variable (plats);
> @@ -1614,7 +1735,62 @@ 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

s/alignment/value range/


> +   edge CS and update DEST_LAT 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;
> +  enum availability availability;
> +  cgraph_node *callee = cs->callee->function_symbol (&availability);
> +  struct ipa_node_params *callee_info = IPA_NODE_REF (callee);
> +  ipcp_vr_lattice *dest_lat = &dest_plats->vr;
> +
> +  if (dest_lat->bottom_p ())
> +    return false;
> +
> +  if (callee_info->versionable)
> +    return dest_lat->set_to_bottom ();

Why is this necessary?  You do not seem to be doing any cloning based
on VR information.

> +
> +  if (jfunc->type == IPA_JF_PASS_THROUGH)
> +    {
> +      struct ipa_node_params *caller_info = IPA_NODE_REF (cs->caller);
> +      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->vr);
> +    }
> +  else if (jfunc->type == IPA_JF_ANCESTOR)
> +    {
> +      struct ipa_node_params *caller_info = IPA_NODE_REF (cs->caller);
> +      int src_idx = ipa_get_jf_ancestor_formal_id (jfunc);
> +      src_lats = ipa_get_parm_lattices (caller_info, src_idx);
> +
> +      return dest_lat->meet_with (src_lats->vr);

I do not understand how come that you are fine with IPA_JF_ANCESTOR
and yet refuse IPA_JF_PASS_THROUGH with a non-NOP operation.

IPA_JF_ANCESTOR is basically an arithmetic jump function for pointers
so I believe you need to punt here or adjust the lattices you meet
with by the offset specified in the jump function.

> +    }
> +  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->vr.type = VR_RANGE;
> +	  jfunc->vr.min = val;
> +	  jfunc->vr.max = val;
> +	  return dest_lat->meet_with (&jfunc->vr);
> +	}
> +    }
> +
> +  if (jfunc->vr_known)
> +    return dest_lat->meet_with (&jfunc->vr);
> +  else
> +    return dest_lat->set_to_bottom ();
> +}
> +
> +/* 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.  */
> @@ -1963,6 +2139,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 (cs, jump_func, dest_plats);
>  	}
>      }
>    for (; i < parms_count; i++)
> @@ -4514,7 +4691,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;
>  
> @@ -4523,6 +4700,8 @@ ipcp_store_alignment_results (void)
>      ipa_node_params *info = IPA_NODE_REF (node);
>      bool dumped_sth = false;
>      bool found_useful_result = false;
> +    bool do_not_update_alignment = false;
> +    bool do_not_update_vr = false;

It is usually easier to work with bool flags that do not have a
negative meaning.  So please turn these into update_alignment_p and
update_vr_p.

>  
>      if (!opt_for_fn (node->decl, flag_ipa_cp_alignment))
>        {
> @@ -4530,7 +4709,16 @@ ipcp_store_alignment_results (void)
>  	  fprintf (dump_file, "Not considering %s for alignment discovery "
>  		   "and propagate; -fipa-cp-alignment: disabled.\n",
>  		   node->name ());
> -	continue;
> +	do_not_update_alignment = true;
> +      }
> +
> +    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 ());
> +	do_not_update_vr = true;
>        }
>  
>     if (info->ipcp_orig_node)
> @@ -4540,13 +4728,21 @@ ipcp_store_alignment_results (void)
>     for (unsigned i = 0; i < count ; i++)
>       {
>         ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
> -       if (!plats->alignment.bottom_p ()
> +       if (!do_not_update_alignment
> +	   && !plats->alignment.bottom_p ()
>  	   && !plats->alignment.top_p ())
>  	 {
>  	   gcc_checking_assert (plats->alignment.align > 0);
>  	   found_useful_result = true;
>  	   break;
>  	 }
> +       if (!do_not_update_vr
> +	   && !plats->vr.bottom_p ()
> +	   && !plats->vr.top_p ())
> +	 {
> +	   found_useful_result = true;
> +	   break;
> +	 }
>       }
>     if (!found_useful_result)
>       continue;
> @@ -4554,11 +4750,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);

And here you need to respect update_alignment_p and update_vr_p too
and only create and store results if indicated by them.

>  
>     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 ())
> @@ -4570,7 +4768,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)
> @@ -4617,7 +4827,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 132b622..25a4d49 100644
> --- a/gcc/ipa-prop.c
> +++ b/gcc/ipa-prop.c
> @@ -41,6 +41,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "gimplify-me.h"
>  #include "gimple-walk.h"
>  #include "symbol-summary.h"
> +#include "tree-vrp.h"
>  #include "ipa-prop.h"
>  #include "tree-cfg.h"
>  #include "tree-dfa.h"
> @@ -381,6 +382,7 @@ ipa_set_jf_unknown (struct ipa_jump_func *jfunc)
>  {
>    jfunc->type = IPA_JF_UNKNOWN;
>    jfunc->alignment.known = false;
> +  jfunc->vr_known = false;
>  }
>  
>  /* Set JFUNC to be a copy of another jmp (to be used by jump function
> @@ -1672,7 +1674,21 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
>  	    gcc_assert (!jfunc->alignment.known);
>  	}
>        else
> -	gcc_assert (!jfunc->alignment.known);

It seems that this assert was removed by accident?  (It is not
particularly useful and should probably be turned into a gcc_checking
assert but anyway...)

> +	{
> +	  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);

Well, if you do these conversions anyway, it might make sense to do
the whole IPA part in wide_int and convert back to trees only in the
transformation phase?  I acknowledge that I do not know how friendly
wide_int is to streaming.  Or is there any other reason to do it on
trees?

> +	    }
> +	  else
> +	    gcc_assert (!jfunc->vr_known);

You are putting in the jump function creation here, into a non-pointer
branch.  Does that mean the IPA-VRP is not supposed to work for
pointers?  That would be a shame because I hoped it would also
propagate non-NULL information which should be particularly useful.

In any event, consider moving this code to the
"if (TREE_CODE (arg) == SSA_NAME)" branch slightly below this.

> +	}
>  
>        if (is_gimple_ip_invariant (arg)
>  	  || (TREE_CODE (arg) == VAR_DECL
> @@ -3679,16 +3695,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]);
>      }
>  }
>  
> @@ -4609,6 +4633,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.  */
> @@ -4685,6 +4717,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
> @@ -5027,7 +5070,9 @@ 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 ();
>  
> @@ -5035,6 +5080,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);
> @@ -5046,6 +5092,16 @@ 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
> @@ -5085,11 +5141,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);
> @@ -5100,6 +5159,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);
> +	    }
>  	}
>      }
>  }
> @@ -5356,15 +5423,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)
> @@ -5374,13 +5443,36 @@ 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;

Please leave the is_gimple_reg check here.  I suppose that if parm is
not a gimple register, the following will always return a NULL ddef,
but non-registers do not have SSA names so let's not even try.

>        tree ddef = ssa_default_def (DECL_STRUCT_FUNCTION (node->decl), parm);
>        if (!ddef)
>  	continue;
>  
> +      if (cgraph_local_p (node)
> +	  && vr[i].known
> +	  && INTEGRAL_TYPE_P (TREE_TYPE (ddef))
> +	  && !POINTER_TYPE_P (TREE_TYPE (ddef))
> +	  && (vr[i].type == VR_RANGE || vr[i].type == VR_ANTI_RANGE)
> +	  && 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));

I don't understand, vr is a vector containing ipa_vr elements which is
a structure in which min and max fields are already trees.  So why the
convert?  (And how can this even compile?  I suppose I am missing
something obvious here but again, if you only work with integers and
go through a wide-int anyway, I suppose ipa_vr should just contain
wide-ints, if we can stream them).


> +
> +	}
> +
> +      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,
> @@ -5422,7 +5514,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 e32d078..490be5f 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. */

Missing newline.

> +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;

The GTY((skip)) seems wrong to me.  What are the other places the
values are referenced from or why did you decide to put it there?

> +};
> +
>  /* 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;
>  };


Thanks,

Martin

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Add support for IPA VRP in ipa-cp/ipa-prop
  2016-07-15  4:47   ` [RFC][IPA-VRP] Add support for IPA VRP in ipa-cp/ipa-prop kugan
  2016-07-15 12:23     ` Martin Jambor
@ 2016-07-17 13:24     ` Prathamesh Kulkarni
  1 sibling, 0 replies; 67+ messages in thread
From: Prathamesh Kulkarni @ 2016-07-17 13:24 UTC (permalink / raw)
  To: kugan; +Cc: gcc-patches, Richard Biener, Jan Hubicka, Martin Jambor

On 15 July 2016 at 05:46, kugan <kugan.vivekanandarajah@linaro.org> wrote:
> Hi,
>
>
>
> This patch extends ipa-cp/ipa-prop infrastructure to handle propagation of
> VR.
Hi Kugan,
Just a small nit - perhaps you should modify
ipa_print_node_jump_functions_for_edge () to pretty-print
value ranges associated with the jump function.

Thanks,
Prathamesh
>
>
>
> Thanks,
>
> Kugan
>
>
>
>
>
> gcc/testsuite/ChangeLog:
>
>
>
> 2016-07-14  Kugan Vivekanandarajah  <kuganv@linaro.org>
>
>
>
>         * gcc.dg/ipa/vrp1.c: New test.
>
>         * gcc.dg/ipa/vrp2.c: New test.
>
>         * gcc.dg/ipa/vrp3.c: New test.
>
>
>
>
>
> gcc/ChangeLog:
>
>
>
> 2016-07-14  Kugan Vivekanandarajah  <kuganv@linaro.org>
>
>
>
>         * common.opt: New option -fipa-vrp.
>
>         * ipa-cp.c (ipa_get_vr_lat): New.
>
>         (ipcp_vr_lattice::print): Likewise.
>
>         (print_all_lattices): Call ipcp_vr_lattice::print.
>
>         (ipcp_vr_lattice::meet_with): New.
>
>         (ipcp_vr_lattice::meet_with_1): Likewise.
>
>         (ipcp_vr_lattice::top_p): Likewise.
>
>         (ipcp_vr_lattice::bottom_p): Likewsie.
>
>         (ipcp_vr_lattice::set_to_bottom): Likewise.
>
>         (set_all_contains_variable): Call VR set_to_bottom.
>
>         (initialize_node_lattices): Init VR lattices.
>
>         (propagate_vr_accross_jump_function): New.
>
>         (propagate_constants_accross_call): Call
>
>         propagate_vr_accross_jump_function.
>
>         (ipcp_store_alignment_results): Rename to
>
>         ipcp_store_alignment_and_vr_results and handke VR.
>
>         * ipa-prop.c (ipa_set_jf_unknown):
>
>         (ipa_compute_jump_functions_for_edge): Handle Value Range.
>
>         (ipa_node_params_t::duplicate): Likewise.
>
>         (ipa_write_jump_function): Likewise.
>
>         (ipa_read_jump_function): Likewise.
>
>         (write_ipcp_transformation_info): Likewise.
>
>         (read_ipcp_transformation_info): Likewise.
>
>         (ipcp_update_alignments): Rename to ipcp_update_vr_and_alignments
>
>         and handle VR.
>
>
>
>
>

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Teach tree-vrp to use the VR set in params
  2016-07-15  4:47 ` [RFC][IPA-VRP] Teach tree-vrp to use the VR set in params kugan
@ 2016-07-18 11:33   ` Richard Biener
  0 siblings, 0 replies; 67+ messages in thread
From: Richard Biener @ 2016-07-18 11:33 UTC (permalink / raw)
  To: kugan; +Cc: gcc-patches, Jan Hubicka, Martin Jambor

On Fri, Jul 15, 2016 at 6:47 AM, kugan
<kugan.vivekanandarajah@linaro.org> wrote:
> Hi,
>
>
>
> This patch teaches tree-vrp to use the VR set in params.

diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index 8c87c06..ad3891c 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -667,6 +667,20 @@ get_value_range (const_tree var)
          if (POINTER_TYPE_P (TREE_TYPE (sym))
              && nonnull_arg_p (sym))
            set_value_range_to_nonnull (vr, TREE_TYPE (sym));
+         else if (!POINTER_TYPE_P (TREE_TYPE (sym)))

Please use INTEGRAL_TYPE_P

+           {
+             wide_int min, max;
+             value_range_type rtype = get_range_info (var, &min, &max);
+             if (rtype == VR_RANGE || rtype == VR_ANTI_RANGE)
+               {
+                 vr->type = rtype;
+                 vr->min = wide_int_to_tree (TREE_TYPE (var), min);
+                 vr->max = wide_int_to_tree (TREE_TYPE (var), max);
+                 vr->equiv = NULL;

Use

     set_value_range (vr, rtype, wide_int..., ..., NULL);

+               }
+             else
+               set_value_range_to_varying (vr);
+           }


Ok with that change.

Thanks,
Richard.

>
>
> Thanks,
>
> Kugan
>
>
>
> gcc/ChangeLog:
>
>
>
> 2016-07-14  Kugan Vivekanandarajah  <kuganv@linaro.org>
>
>
>
>          * tree-vrp.c (get_value_range): Teach PARM_DECL to use ipa-vrp
>
>          results.
>

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Early VRP Implementation
  2016-07-15  7:33         ` kugan
@ 2016-07-18 11:51           ` Richard Biener
  2016-07-22 12:10             ` kugan
  0 siblings, 1 reply; 67+ messages in thread
From: Richard Biener @ 2016-07-18 11:51 UTC (permalink / raw)
  To: kugan; +Cc: Andrew Pinski, gcc-patches, Jan Hubicka, Martin Jambor

On Fri, Jul 15, 2016 at 9:33 AM, kugan
<kugan.vivekanandarajah@linaro.org> wrote:
> Hi Andrew,
>
> On 15/07/16 17:28, Andrew Pinski wrote:
>>
>> On Fri, Jul 15, 2016 at 12:08 AM, kugan
>> <kugan.vivekanandarajah@linaro.org> wrote:
>>>
>>> Hi Andrew,
>>>
>>>> Why separate out early VRP from tree-vrp?  Just a little curious.
>>>
>>>
>>>
>>> It is based on the discussion in
>>> https://gcc.gnu.org/ml/gcc/2016-01/msg00069.html.
>>> In summary, conclusion (based on my understanding) was to implement a
>>> simplified VRP algorithm that doesn't require ASSERT_EXPR insertion.
>>
>>
>> But I don't see why you are moving it from tree-vrp.c .  That was my
>> question, you pointing to that discussion does not say to split it
>> into a new file and expose these interfaces.
>>
>
> Are you saying that I should keep this part of tree-vrp.c. I am happy to do
> that if this is considered the best approach.

Yes, I think that's the best approach.

Can you, as a refactoring before your patch, please change VRP to use
an alloc-pool
for allocating value_range?  The DOM-based VRP will add a lot of
malloc/free churn
otherwise.

Generally watch coding-style such as  missed function comments.

As you do a non-iterating VRP and thus do not visit back-edges you don't need
to initialize loops or SCEV nor do you need loop-closed SSA.

As you do a DOM-based VRP using SSA propagator stuff like ssa_prop_result
doesn't make any sense.

+edge evrp_dom_walker::before_dom_children (basic_block bb)
+{
+  /* If we are going out of scope, restore the old VR.  */
+  while (!cond_stack.is_empty ()
+        && !dominated_by_p (CDI_DOMINATORS, bb, cond_stack.last ().first))
+    {
+      tree var = cond_stack.last ().second.first;
+      value_range *vr = cond_stack.last ().second.second;
+      value_range *vr_to_del = get_value_range (var);
+      XDELETE (vr_to_del);
+      change_value_range (var, vr);
+      cond_stack.pop ();
+    }

that should be in after_dom_children I think and use a marker instead
of a DOM query.
See other examples like DOM itself or SCCVN.

+         /* Discover VR when condition is true.  */
+         if (te == e
+             && !TREE_OVERFLOW_P (op0)
+             && !TREE_OVERFLOW_P (op1))

you can use e->flags & EDGE_TRUE_VALUE/EDGE_FALSE_VALUE

why do you need those TREE_OVERFLOW checks?

+             tree cond = build2 (code, boolean_type_node, op0, op1);
+             tree a = build2 (ASSERT_EXPR, TREE_TYPE (op0), op0, cond);
+             extract_range_from_assert (&vr, a);

so I was hoping that the "refactoring" patch in the series would expose a more
useful interface than extract_range_from_assert ... namely one that can
extract a range from the comparison directly and does not require building
a scratch ASSERT_EXPR.

+         /* If we found any usable VR, set the VR to ssa_name and create a
+            restore point in the cond_stack with the  old VR. */
+         if (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE)
+           {
+             value_range *new_vr = XCNEW (value_range);
+             *new_vr = vr;
+             cond_stack.safe_push (std::make_pair (bb,
+                                                   std::make_pair (op0,
+                                                                   old_vr)));
+             change_value_range (op0, new_vr);

I don't like 'change_value_range' as interface, please integrate that into
a push/pop_value_range style interface instead.

+       vrp_visit_stmt (stmt, &taken_edge_p, &output_p);
+    }
+
+  return NULL;

you should return taken_edge_p (misnamed as it isn't a pointer) and take
advantage of EDGE_EXECUTABLE.  Again see DOM/SCCVN (might want to
defer this as a followup improvement).

Note that the advantage of a DOM-based VRP is that backtracking is easy
to implement (you don't do that yet).  That is, after DEF got a (better)
value-range you can simply re-visit all the defs of its uses (and recursively).
I think you have to be careful with stmts that might prematurely leave a BB
though (like via EH).  So sth for a followup as well.

Thanks,
Richard.


> Thanks,
> Kugan

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Add support for IPA VRP in ipa-cp/ipa-prop
  2016-07-15 12:23     ` Martin Jambor
@ 2016-07-19  8:22       ` kugan
  2016-07-19 21:27         ` kugan
  0 siblings, 1 reply; 67+ messages in thread
From: kugan @ 2016-07-19  8:22 UTC (permalink / raw)
  To: gcc-patches, Richard Biener, Jan Hubicka

[-- Attachment #1: Type: text/plain, Size: 30933 bytes --]

Hi Martin,

Thanks for the review.  I have revised the patch based on the review. 
Please see the comments below.

On 15/07/16 22:23, Martin Jambor wrote:
> Hi,
>
> thanks for working on extending IPA-CP in this way.  I do have a few
> comments though:
>
> On Fri, Jul 15, 2016 at 02:46:50PM +1000, kugan wrote:
>> Hi,
>>
>> This patch extends ipa-cp/ipa-prop infrastructure to handle propagation of
>> VR.
>> Thanks,
>>
>> Kugan
>>
>> gcc/testsuite/ChangeLog:
>>
>> 2016-07-14  Kugan Vivekanandarajah  <kuganv@linaro.org>
>>
>>          * gcc.dg/ipa/vrp1.c: New test.
>>          * gcc.dg/ipa/vrp2.c: New test.
>>          * gcc.dg/ipa/vrp3.c: New test.
>>
>> gcc/ChangeLog:
>>
>> 2016-07-14  Kugan Vivekanandarajah  <kuganv@linaro.org>
>>
>>          * common.opt: New option -fipa-vrp.
>>          * ipa-cp.c (ipa_get_vr_lat): New.
>>          (ipcp_vr_lattice::print): Likewise.
>>          (print_all_lattices): Call ipcp_vr_lattice::print.
>>          (ipcp_vr_lattice::meet_with): New.
>>          (ipcp_vr_lattice::meet_with_1): Likewise.
>>          (ipcp_vr_lattice::top_p): Likewise.
>>          (ipcp_vr_lattice::bottom_p): Likewsie.
>>          (ipcp_vr_lattice::set_to_bottom): Likewise.
>>          (set_all_contains_variable): Call VR set_to_bottom.
>>          (initialize_node_lattices): Init VR lattices.
>>          (propagate_vr_accross_jump_function): New.
>>          (propagate_constants_accross_call): Call
>>          propagate_vr_accross_jump_function.
>>          (ipcp_store_alignment_results): Rename to
>>          ipcp_store_alignment_and_vr_results and handke VR.
>>          * ipa-prop.c (ipa_set_jf_unknown):
>>          (ipa_compute_jump_functions_for_edge): Handle Value Range.
>>          (ipa_node_params_t::duplicate): Likewise.
>>          (ipa_write_jump_function): Likewise.
>>          (ipa_read_jump_function): Likewise.
>>          (write_ipcp_transformation_info): Likewise.
>>          (read_ipcp_transformation_info): Likewise.
>>          (ipcp_update_alignments): Rename to ipcp_update_vr_and_alignments
>>          and handle VR.
>>
>
>>  From 092cbccd79c3859ff24846bb0e1892ef5d8086bc Mon Sep 17 00:00:00 2001
>> From: Kugan Vivekanandarajah <kugan.vivekanandarajah@linaro.org>
>> Date: Tue, 21 Jun 2016 12:43:01 +1000
>> Subject: [PATCH 5/6] Add ipa vrp
>>
>> ---
>>   gcc/common.opt                  |   4 +
>>   gcc/ipa-cp.c                    | 220 +++++++++++++++++++++++++++++++++++++++-
>>   gcc/ipa-prop.c                  | 110 ++++++++++++++++++--
>>   gcc/ipa-prop.h                  |  16 +++
>>   gcc/testsuite/gcc.dg/ipa/vrp1.c |  32 ++++++
>>   gcc/testsuite/gcc.dg/ipa/vrp2.c |  35 +++++++
>>   gcc/testsuite/gcc.dg/ipa/vrp3.c |  30 ++++++
>>   7 files changed, 433 insertions(+), 14 deletions(-)
>>   create mode 100644 gcc/testsuite/gcc.dg/ipa/vrp1.c
>>   create mode 100644 gcc/testsuite/gcc.dg/ipa/vrp2.c
>>   create mode 100644 gcc/testsuite/gcc.dg/ipa/vrp3.c
>>
>> diff --git a/gcc/common.opt b/gcc/common.opt
>> index 29d0e4d..7bf7305 100644
>> --- a/gcc/common.opt
>> +++ b/gcc/common.opt
>> @@ -2475,6 +2475,10 @@ ftree-evrp
>>   Common Report Var(flag_tree_early_vrp) Init(1) Optimization
>>   Perform Early Value Range Propagation on trees.
>>
>> +fipa-vrp
>> +ommon Report Var(flag_ipa_vrp) Init(1) Optimization
>
> Common

Done.

>
>> +Perform IPA Value Range Propagation on trees.
>
> I think that nowadays we should omit the "on trees" part, they are not
> particularly useful.
>

Done.

>> +
>>   fsplit-paths
>>   Common Report Var(flag_split_paths) Init(0) Optimization
>>   Split paths leading to loop backedges.
>> diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
>> index 4b7f6bb..97cd04b 100644
>> --- a/gcc/ipa-cp.c
>> +++ b/gcc/ipa-cp.c
>> @@ -120,6 +120,7 @@ along with GCC; see the file COPYING3.  If not see
>>   #include "params.h"
>>   #include "ipa-inline.h"
>>   #include "ipa-utils.h"
>> +#include "tree-vrp.h"
>>
>>   template <typename valtype> class ipcp_value;
>>
>> @@ -266,6 +267,25 @@ 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);
>
> Please do not call the parameter the same name as that of a member
> variable, that might become very confusing in future.
>
Done.

>> +  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);
>
> Likewise.
>
> I know that no other classes in the file do, but if you want to
> strictly follow the GCC coding style, member vr should be called m_vr.
> Perhaps I should add the m_ prefixes to other classes as well, I am
> becoming to appreciate them.
>

Done.

>> +};
>> +
>>   /* 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 +301,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 +370,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.  */
>
> GCC coding style requires (exactly) one blank in between a function
> and its preceding comment.
>
Done.

>> +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 +489,16 @@ 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)
>> +{
>> +  fprintf (f, "         ");
>
> Please move the above line to the caller.  It will make the function
> much more versatile, for example also reasonably callable from the debugger.
>
Done.

>> +  dump_value_range (f, &vr);
>> +  fprintf (f, "\n");
>> +}
>> +
>>   /* Print all ipcp_lattices of all functions to F.  */
>>
>>   static void
>> @@ -484,6 +525,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 +870,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.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);
>
> As I wrote above, the parameter should have a name different from a
> member variable.  Moreover, I do not really understand why you need
> meet_with_1, why don't you just do the meet here?
>
Done.

>> +}
>> +
>> +/* 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 = vr.min, max = vr.max;
>> +  value_range_type type = vr.type;
>> +
>> +  if (bottom_p ())
>> +    return false;
>> +
>> +  if (other_vr->type == VR_VARYING)
>> +    return set_to_bottom ();
>> +
>> +  vrp_meet (&vr, const_cast<value_range *> (other_vr));
>
> The const cast is bad.  Please try to make the second parameter of
> vrp_meet const first.  Only if it for some reason proves to be so big
> a task that it would unreasonably delay the IPA-VRP implementation,
> then explain why that is so and we might leave the cast here.
>
Done. This also means I am changing tree-vrp. I will send that part of 
the patch later.

>> +  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.  */
>
> s/alignment/value range/ or just omit the word completely.
>
Done.

>> +
>> +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 +1028,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;
>>   }
>>
>> @@ -985,6 +1099,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->vr.init ();
>> +    }
>> +
>>     if (disable || variable)
>>       {
>>         for (i = 0; i < ipa_get_param_count (info) ; i++)
>> @@ -996,6 +1116,7 @@ initialize_node_lattices (struct cgraph_node *node)
>>   	      plats->ctxlat.set_to_bottom ();
>>   	      set_agg_lats_to_bottom (plats);
>>   	      plats->alignment.set_to_bottom ();
>> +	      plats->vr.set_to_bottom ();
>>   	    }
>>   	  else
>>   	    set_all_contains_variable (plats);
>> @@ -1614,7 +1735,62 @@ 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
>
> s/alignment/value range/
>
Done.

>
>> +   edge CS and update DEST_LAT 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;
>> +  enum availability availability;
>> +  cgraph_node *callee = cs->callee->function_symbol (&availability);
>> +  struct ipa_node_params *callee_info = IPA_NODE_REF (callee);
>> +  ipcp_vr_lattice *dest_lat = &dest_plats->vr;
>> +
>> +  if (dest_lat->bottom_p ())
>> +    return false;
>> +
>> +  if (callee_info->versionable)
>> +    return dest_lat->set_to_bottom ();
>
> Why is this necessary?  You do not seem to be doing any cloning based
> on VR information.
>

Well I dont do cloning based on VR. I was trying to be safe here. But, 
as you mentioned, this is not needed and. I have removed it.


>> +
>> +  if (jfunc->type == IPA_JF_PASS_THROUGH)
>> +    {
>> +      struct ipa_node_params *caller_info = IPA_NODE_REF (cs->caller);
>> +      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->vr);
>> +    }
>> +  else if (jfunc->type == IPA_JF_ANCESTOR)
>> +    {
>> +      struct ipa_node_params *caller_info = IPA_NODE_REF (cs->caller);
>> +      int src_idx = ipa_get_jf_ancestor_formal_id (jfunc);
>> +      src_lats = ipa_get_parm_lattices (caller_info, src_idx);
>> +
>> +      return dest_lat->meet_with (src_lats->vr);
>
> I do not understand how come that you are fine with IPA_JF_ANCESTOR
> and yet refuse IPA_JF_PASS_THROUGH with a non-NOP operation.
>
> IPA_JF_ANCESTOR is basically an arithmetic jump function for pointers
> so I believe you need to punt here or adjust the lattices you meet
> with by the offset specified in the jump function.

I have removed the IPA_JF_ANCESTOR part.


>
>> +    }
>> +  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->vr.type = VR_RANGE;
>> +	  jfunc->vr.min = val;
>> +	  jfunc->vr.max = val;
>> +	  return dest_lat->meet_with (&jfunc->vr);
>> +	}
>> +    }
>> +
>> +  if (jfunc->vr_known)
>> +    return dest_lat->meet_with (&jfunc->vr);
>> +  else
>> +    return dest_lat->set_to_bottom ();
>> +}
>> +
>> +/* 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.  */
>> @@ -1963,6 +2139,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 (cs, jump_func, dest_plats);
>>   	}
>>       }
>>     for (; i < parms_count; i++)
>> @@ -4514,7 +4691,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;
>>
>> @@ -4523,6 +4700,8 @@ ipcp_store_alignment_results (void)
>>       ipa_node_params *info = IPA_NODE_REF (node);
>>       bool dumped_sth = false;
>>       bool found_useful_result = false;
>> +    bool do_not_update_alignment = false;
>> +    bool do_not_update_vr = false;
>
> It is usually easier to work with bool flags that do not have a
> negative meaning.  So please turn these into update_alignment_p and
> update_vr_p.

Done.

>
>>
>>       if (!opt_for_fn (node->decl, flag_ipa_cp_alignment))
>>         {
>> @@ -4530,7 +4709,16 @@ ipcp_store_alignment_results (void)
>>   	  fprintf (dump_file, "Not considering %s for alignment discovery "
>>   		   "and propagate; -fipa-cp-alignment: disabled.\n",
>>   		   node->name ());
>> -	continue;
>> +	do_not_update_alignment = true;
>> +      }
>> +
>> +    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 ());
>> +	do_not_update_vr = true;
>>         }
>>
>>      if (info->ipcp_orig_node)
>> @@ -4540,13 +4728,21 @@ ipcp_store_alignment_results (void)
>>      for (unsigned i = 0; i < count ; i++)
>>        {
>>          ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
>> -       if (!plats->alignment.bottom_p ()
>> +       if (!do_not_update_alignment
>> +	   && !plats->alignment.bottom_p ()
>>   	   && !plats->alignment.top_p ())
>>   	 {
>>   	   gcc_checking_assert (plats->alignment.align > 0);
>>   	   found_useful_result = true;
>>   	   break;
>>   	 }
>> +       if (!do_not_update_vr
>> +	   && !plats->vr.bottom_p ()
>> +	   && !plats->vr.top_p ())
>> +	 {
>> +	   found_useful_result = true;
>> +	   break;
>> +	 }
>>        }
>>      if (!found_useful_result)
>>        continue;
>> @@ -4554,11 +4750,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);
>
> And here you need to respect update_alignment_p and update_vr_p too
> and only create and store results if indicated by them.
>
Done.

>>
>>      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 ())
>> @@ -4570,7 +4768,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)
>> @@ -4617,7 +4827,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 132b622..25a4d49 100644
>> --- a/gcc/ipa-prop.c
>> +++ b/gcc/ipa-prop.c
>> @@ -41,6 +41,7 @@ along with GCC; see the file COPYING3.  If not see
>>   #include "gimplify-me.h"
>>   #include "gimple-walk.h"
>>   #include "symbol-summary.h"
>> +#include "tree-vrp.h"
>>   #include "ipa-prop.h"
>>   #include "tree-cfg.h"
>>   #include "tree-dfa.h"
>> @@ -381,6 +382,7 @@ ipa_set_jf_unknown (struct ipa_jump_func *jfunc)
>>   {
>>     jfunc->type = IPA_JF_UNKNOWN;
>>     jfunc->alignment.known = false;
>> +  jfunc->vr_known = false;
>>   }
>>
>>   /* Set JFUNC to be a copy of another jmp (to be used by jump function
>> @@ -1672,7 +1674,21 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
>>   	    gcc_assert (!jfunc->alignment.known);
>>   	}
>>         else
>> -	gcc_assert (!jfunc->alignment.known);
>
> It seems that this assert was removed by accident?  (It is not
> particularly useful and should probably be turned into a gcc_checking
> assert but anyway...)
>
Done.

>> +	{
>> +	  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);
>
> Well, if you do these conversions anyway, it might make sense to do
> the whole IPA part in wide_int and convert back to trees only in the
> transformation phase?  I acknowledge that I do not know how friendly
> wide_int is to streaming.  Or is there any other reason to do it on
> trees?
>

wide_int streaming is not handled now. Once that is the case, I can 
change it to wide_int.
I can add a TODO and implement it as follow up if you prefer that.


>> +	    }
>> +	  else
>> +	    gcc_assert (!jfunc->vr_known);
>
> You are putting in the jump function creation here, into a non-pointer
> branch.  Does that mean the IPA-VRP is not supposed to work for
> pointers?  That would be a shame because I hoped it would also
> propagate non-NULL information which should be particularly useful.

As of now SSA_NAMEs set value range for non-pointers as range_info and 
ptr_info are unions. If we can find a spare bit in ptr_info, we can 
infact propagate non-null info. I will look into it once this part is done.

>
> In any event, consider moving this code to the
> "if (TREE_CODE (arg) == SSA_NAME)" branch slightly below this.
>
>> +	}
>>
>>         if (is_gimple_ip_invariant (arg)
>>   	  || (TREE_CODE (arg) == VAR_DECL
>> @@ -3679,16 +3695,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]);
>>       }
>>   }
>>
>> @@ -4609,6 +4633,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.  */
>> @@ -4685,6 +4717,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
>> @@ -5027,7 +5070,9 @@ 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 ();
>>
>> @@ -5035,6 +5080,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);
>> @@ -5046,6 +5092,16 @@ 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
>> @@ -5085,11 +5141,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);
>> @@ -5100,6 +5159,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);
>> +	    }
>>   	}
>>       }
>>   }
>> @@ -5356,15 +5423,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)
>> @@ -5374,13 +5443,36 @@ 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;
>
> Please leave the is_gimple_reg check here.  I suppose that if parm is
> not a gimple register, the following will always return a NULL ddef,
> but non-registers do not have SSA names so let's not even try.

Done.

>
>>         tree ddef = ssa_default_def (DECL_STRUCT_FUNCTION (node->decl), parm);
>>         if (!ddef)
>>   	continue;
>>
>> +      if (cgraph_local_p (node)
>> +	  && vr[i].known
>> +	  && INTEGRAL_TYPE_P (TREE_TYPE (ddef))
>> +	  && !POINTER_TYPE_P (TREE_TYPE (ddef))
>> +	  && (vr[i].type == VR_RANGE || vr[i].type == VR_ANTI_RANGE)
>> +	  && 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));
>
> I don't understand, vr is a vector containing ipa_vr elements which is
> a structure in which min and max fields are already trees.  So why the
> convert?  (And how can this even compile?  I suppose I am missing
> something obvious here but again, if you only work with integers and
> go through a wide-int anyway, I suppose ipa_vr should just contain
> wide-ints, if we can stream them).
>
SSA_NAMEs have range into in wide_int. To convert tree into the right 
precision, I am doing this. I have seen similar uses elsewhere.

>
>> +
>> +	}
>> +
>> +      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,
>> @@ -5422,7 +5514,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 e32d078..490be5f 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. */
>
> Missing newline.

Done.
>
>> +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;
>
> The GTY((skip)) seems wrong to me.  What are the other places the
> values are referenced from or why did you decide to put it there?
>
Indeed. Removed it.

>> +};
>> +
>>   /* 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;
>>   };

Thanks,
Kugan

>
>
> Thanks,
>
> Martin
>

[-- Attachment #2: 0005-Add-ipa-vrp.patch --]
[-- Type: text/x-patch, Size: 25482 bytes --]

From 8613b15365e4ce224d4f660d832d22997662da8c Mon Sep 17 00:00:00 2001
From: Kugan Vivekanandarajah <kugan.vivekanandarajah@linaro.org>
Date: Tue, 21 Jun 2016 12:43:01 +1000
Subject: [PATCH 5/6] Add ipa vrp

---
 gcc/common.opt                  |   4 +
 gcc/ipa-cp.c                    | 241 +++++++++++++++++++++++++++++++++++++---
 gcc/ipa-prop.c                  | 126 +++++++++++++++++++--
 gcc/ipa-prop.h                  |  17 +++
 gcc/testsuite/gcc.dg/ipa/vrp1.c |  32 ++++++
 gcc/testsuite/gcc.dg/ipa/vrp2.c |  35 ++++++
 gcc/testsuite/gcc.dg/ipa/vrp3.c |  30 +++++
 7 files changed, 461 insertions(+), 24 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/ipa/vrp1.c
 create mode 100644 gcc/testsuite/gcc.dg/ipa/vrp2.c
 create mode 100644 gcc/testsuite/gcc.dg/ipa/vrp3.c

diff --git a/gcc/common.opt b/gcc/common.opt
index 29d0e4d..7e3ab5f 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2475,6 +2475,10 @@ ftree-evrp
 Common Report Var(flag_tree_early_vrp) Init(1) Optimization
 Perform Early Value Range Propagation on trees.
 
+fipa-vrp
+Common Report Var(flag_ipa_vrp) Init(1) Optimization
+Perform IPA Value Range Propagation.
+
 fsplit-paths
 Common Report Var(flag_split_paths) Init(0) Optimization
 Split paths leading to loop backedges.
diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
index 4b7f6bb..30b1f2e 100644
--- a/gcc/ipa-cp.c
+++ b/gcc/ipa-cp.c
@@ -120,6 +120,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "params.h"
 #include "ipa-inline.h"
 #include "ipa-utils.h"
+#include "tree-vrp.h"
 
 template <typename valtype> class ipcp_value;
 
@@ -266,6 +267,25 @@ private:
   bool meet_with_1 (unsigned new_align, unsigned new_misalign);
 };
 
+/* 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.  */
@@ -281,6 +301,8 @@ public:
   ipcp_agg_lattice *aggs;
   /* Lattice describing known alignment.  */
   ipcp_alignment_lattice alignment;
+  /* 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
@@ -348,6 +370,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.  */
 
@@ -458,6 +490,14 @@ ipcp_alignment_lattice::print (FILE * f)
     fprintf (f, "         Alignment %u, misalignment %u\n", align, misalign);
 }
 
+/* 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
@@ -484,6 +524,9 @@ 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);
+	  fprintf (f, "         ");
+	  plats->m_value_range.print (f);
+	  fprintf (f, "\n");
 	  if (plats->virt_call)
 	    fprintf (f, "        virt_call flag set\n");
 
@@ -828,6 +871,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.  */
@@ -915,6 +1029,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->m_value_range.set_to_bottom ();
   return ret;
 }
 
@@ -985,6 +1100,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++)
@@ -996,6 +1117,7 @@ initialize_node_lattices (struct cgraph_node *node)
 	      plats->ctxlat.set_to_bottom ();
 	      set_agg_lats_to_bottom (plats);
 	      plats->alignment.set_to_bottom ();
+	      plats->m_value_range.set_to_bottom ();
 	    }
 	  else
 	    set_all_contains_variable (plats);
@@ -1614,7 +1736,49 @@ propagate_alignment_accross_jump_function (cgraph_edge *cs,
     }
 }
 
-/* If DEST_PLATS already has aggregate items, check that aggs_by_ref matches
+/* 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);
+      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 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.  */
@@ -1963,6 +2127,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 (cs, jump_func, dest_plats);
 	}
     }
   for (; i < parms_count; i++)
@@ -4514,7 +4679,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;
 
@@ -4523,6 +4688,8 @@ ipcp_store_alignment_results (void)
     ipa_node_params *info = IPA_NODE_REF (node);
     bool dumped_sth = false;
     bool found_useful_result = false;
+    bool update_alignment_p = true;
+    bool update_vr_p = true;
 
     if (!opt_for_fn (node->decl, flag_ipa_cp_alignment))
       {
@@ -4530,7 +4697,16 @@ ipcp_store_alignment_results (void)
 	  fprintf (dump_file, "Not considering %s for alignment discovery "
 		   "and propagate; -fipa-cp-alignment: disabled.\n",
 		   node->name ());
-	continue;
+	update_alignment_p = 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 ());
+	update_vr_p = false;
       }
 
    if (info->ipcp_orig_node)
@@ -4540,37 +4716,72 @@ ipcp_store_alignment_results (void)
    for (unsigned i = 0; i < count ; i++)
      {
        ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
-       if (!plats->alignment.bottom_p ()
+       if (update_alignment_p
+	   && !plats->alignment.bottom_p ()
 	   && !plats->alignment.top_p ())
 	 {
 	   gcc_checking_assert (plats->alignment.align > 0);
 	   found_useful_result = true;
 	   break;
 	 }
+       if (update_vr_p
+	   && !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->alignments, count);
+   if (update_alignment_p)
+     vec_safe_reserve_exact (ts->alignments, count);
+   if (update_vr_p)
+     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_alignment al;
+       ipa_vr vr;
 
-       if (!plats->alignment.bottom_p ()
-	   && !plats->alignment.top_p ())
+       if (update_alignment_p)
+	 {
+	   if (!plats->alignment.bottom_p ()
+	       && !plats->alignment.top_p ())
+	     {
+	       al.known = true;
+	       al.align = plats->alignment.align;
+	       al.misalign = plats->alignment.misalign;
+	     }
+	   else
+	     al.known = false;
+	   ts->alignments->quick_push (al);
+	 }
+
+       if (update_vr_p)
 	 {
-	   al.known = true;
-	   al.align = plats->alignment.align;
-	   al.misalign = plats->alignment.misalign;
+	   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
+	     {
+	       vr.known = false;
+	       vr.type = VR_VARYING;
+	       vr.min = NULL_TREE;
+	       vr.max = NULL_TREE;
+	     }
+	   ts->m_vr->quick_push (vr);
 	 }
-       else
-	 al.known = false;
 
-       ts->alignments->quick_push (al);
        if (!dump_file || !al.known)
 	 continue;
        if (!dumped_sth)
@@ -4616,8 +4827,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 ();
+  /* Store results of alignment and value range propagation.  */
+  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 132b622..a8f6b23 100644
--- a/gcc/ipa-prop.c
+++ b/gcc/ipa-prop.c
@@ -41,6 +41,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimplify-me.h"
 #include "gimple-walk.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "tree-cfg.h"
 #include "tree-dfa.h"
@@ -302,6 +303,18 @@ ipa_print_node_jump_functions_for_edge (FILE *f, struct cgraph_edge *cs)
 	}
       else
 	fprintf (f, "         Unknown alignment\n");
+
+      if (jump_func->vr_known)
+	{
+	  fprintf (f, "         VR  ");
+	  fprintf (f, "%s[", (jump_func->m_vr.type == VR_ANTI_RANGE) ? "~" : "");
+	  print_generic_expr (f, jump_func->m_vr.min, 0);
+	  fprintf (f, ", ");
+	  print_generic_expr (f, jump_func->m_vr.max, 0);
+	  fprintf (f, "]\n");
+	}
+      else
+	fprintf (f, "         Unknown VR\n");
     }
 }
 
@@ -381,6 +394,7 @@ ipa_set_jf_unknown (struct ipa_jump_func *jfunc)
 {
   jfunc->type = IPA_JF_UNKNOWN;
   jfunc->alignment.known = false;
+  jfunc->vr_known = false;
 }
 
 /* Set JFUNC to be a copy of another jmp (to be used by jump function
@@ -1670,9 +1684,25 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
 	    }
 	  else
 	    gcc_assert (!jfunc->alignment.known);
+	  gcc_assert (!jfunc->vr_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->m_vr.type = type;
+	      jfunc->m_vr.min = wide_int_to_tree (TREE_TYPE (arg), min);
+	      jfunc->m_vr.max = wide_int_to_tree (TREE_TYPE (arg), max);
+	    }
+	  else
+	    gcc_assert (!jfunc->vr_known);
+	  gcc_assert (!jfunc->alignment.known);
+	}
 
       if (is_gimple_ip_invariant (arg)
 	  || (TREE_CODE (arg) == VAR_DECL
@@ -3679,16 +3709,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->m_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->m_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)->m_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]);
     }
 }
 
@@ -4609,6 +4647,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->m_vr.type);
+      stream_write_tree (ob, jump_func->m_vr.min, true);
+      stream_write_tree (ob, jump_func->m_vr.max, true);
+    }
 }
 
 /* Read in jump function JUMP_FUNC from IB.  */
@@ -4685,6 +4731,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->m_vr.type = streamer_read_enum (ib, value_range_type, VR_LAST);
+      jump_func->m_vr.min = stream_read_tree (ib, data_in);
+      jump_func->m_vr.max = stream_read_tree (ib, data_in);
+    }
+  else
+    jump_func->vr_known = false;
 }
 
 /* Stream out parts of cgraph_indirect_call_info corresponding to CS that are
@@ -5027,7 +5084,9 @@ 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
+      && ((ts->alignments && vec_safe_length (ts->alignments) > 0)
+	  || (ts->m_vr && vec_safe_length (ts->m_vr) > 0)))
     {
       count = ts->alignments->length ();
 
@@ -5035,6 +5094,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->m_vr)[i];
 
 	  struct bitpack_d bp;
 	  bp = bitpack_create (ob->main_stream);
@@ -5046,6 +5106,16 @@ 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
@@ -5085,11 +5155,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->m_vr, count);
 
       for (i = 0; i < count; i++)
 	{
 	  ipa_alignment *parm_al;
+	  ipa_vr *parm_vr;
 	  parm_al = &(*ts->alignments)[i];
+	  parm_vr = &(*ts->m_vr)[i];
 	  struct bitpack_d bp;
 	  bp = streamer_read_bitpack (ib);
 	  parm_al->known = bp_unpack_value (&bp, 1);
@@ -5100,6 +5173,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);
+	    }
 	}
     }
 }
@@ -5356,15 +5437,18 @@ 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
+      || ((!ts->alignments || vec_safe_length (ts->alignments) == 0)
+	  && (!ts->m_vr || vec_safe_length (ts->m_vr) == 0)))
     return;
   const vec<ipa_alignment, va_gc> &alignments = *ts->alignments;
+  const vec<ipa_vr, va_gc> &vr = *ts->m_vr;
   unsigned count = alignments.length ();
 
   for (unsigned i = 0; i < count; ++i, parm = next_parm)
@@ -5374,11 +5458,35 @@ ipcp_update_alignments (struct cgraph_node *node)
 	continue;
       gcc_checking_assert (parm);
       next_parm = DECL_CHAIN (parm);
+      tree ddef = ssa_default_def (DECL_STRUCT_FUNCTION (node->decl), parm);
 
-      if (!alignments[i].known || !is_gimple_reg (parm))
+      if (!ddef || !is_gimple_reg (parm))
 	continue;
-      tree ddef = ssa_default_def (DECL_STRUCT_FUNCTION (node->decl), parm);
-      if (!ddef)
+
+      if (cgraph_local_p (node)
+	  && vr[i].known
+	  && INTEGRAL_TYPE_P (TREE_TYPE (ddef))
+	  && !POINTER_TYPE_P (TREE_TYPE (ddef))
+	  && (vr[i].type == VR_RANGE || vr[i].type == VR_ANTI_RANGE)
+	  && 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)
 	continue;
 
       if (dump_file)
@@ -5422,7 +5530,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 e32d078..82c1086 100644
--- a/gcc/ipa-prop.h
+++ b/gcc/ipa-prop.h
@@ -154,6 +154,17 @@ 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 min;
+  tree 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 +177,10 @@ struct GTY (()) ipa_jump_func
   /* Information about alignment of pointers. */
   struct ipa_alignment alignment;
 
+  /* Information about value range.  */
+  bool vr_known;
+  value_range m_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 +497,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> *m_vr;
 };
 
 void ipa_set_node_agg_value_chain (struct cgraph_node *node,
diff --git a/gcc/testsuite/gcc.dg/ipa/vrp1.c b/gcc/testsuite/gcc.dg/ipa/vrp1.c
new file mode 100644
index 0000000..72a3139
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/vrp1.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-ipa-cp-details" } */
+
+static __attribute__((noinline, noclone))
+int foo (int i)
+{
+  if (i < 5)
+    __builtin_abort ();
+  return 0;
+}
+
+static __attribute__((noinline, noclone))
+int bar (int j)
+{
+  if (j > 8)
+    return foo (j + 2);
+  else if (j > 2)
+    return foo (j + 3);
+
+  return 0;
+}
+
+int main ()
+{
+  for (unsigned int i =0; i < 1000; ++i)
+    bar (i);
+
+  return 0;
+}
+
+/* { dg-final { scan-ipa-dump "Setting value range of param 0 \\\[6," "cp" } } */
+/* { dg-final { scan-ipa-dump "Setting value range of param 0 \\\[0, 999\\\]" "cp" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/vrp2.c b/gcc/testsuite/gcc.dg/ipa/vrp2.c
new file mode 100644
index 0000000..c720e5c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/vrp2.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-ipa-cp-details" } */
+
+static __attribute__((noinline, noclone))
+int foo (int i)
+{
+  if (i < 4)
+    __builtin_abort ();
+  return 0;
+}
+
+static __attribute__((noinline, noclone))
+int bar (int j)
+{
+  if (j > 8)
+    return foo (j + 2);
+  else if (j > 2)
+    return foo (j + 3);
+
+  return 0;
+}
+
+int main ()
+{
+  foo (100);
+  for (unsigned int i = 0; i < 12; ++i)
+    {
+      bar (i);
+    }
+  foo (4);
+  return 0;
+}
+
+/* { dg-final { scan-ipa-dump "Setting value range of param 0 \\\[4," "cp" } } */
+/* { dg-final { scan-ipa-dump "Setting value range of param 0 \\\[0, 11\\\]" "cp" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/vrp3.c b/gcc/testsuite/gcc.dg/ipa/vrp3.c
new file mode 100644
index 0000000..fb5d54a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/vrp3.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-ipa-cp-details" } */
+
+volatile int cond;
+
+static __attribute__((noinline, noclone))
+int foo (int i)
+{
+  if (i < 5)
+    __builtin_abort ();
+  return 0;
+}
+
+static __attribute__((noinline, noclone))
+int bar (int j)
+{
+  if (cond)
+    foo (j);
+  return 0;
+}
+
+int main ()
+{
+  for (unsigned int i = 0; i < 10; ++i)
+    bar (i);
+
+  return 0;
+}
+
+/* { dg-final { scan-ipa-dump-times "Setting value range of param 0 \\\[0, 9\\\]" 2 "cp" } } */
-- 
1.9.1


^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Early VRP Implementation
  2016-07-15  4:52   ` Andrew Pinski
  2016-07-15  7:08     ` kugan
@ 2016-07-19 16:19     ` Jeff Law
  2016-07-19 18:35       ` Richard Biener
  1 sibling, 1 reply; 67+ messages in thread
From: Jeff Law @ 2016-07-19 16:19 UTC (permalink / raw)
  To: Andrew Pinski, kugan
  Cc: gcc-patches, Richard Biener, Jan Hubicka, Martin Jambor

On 07/14/2016 10:52 PM, Andrew Pinski wrote:
> On Thu, Jul 14, 2016 at 9:45 PM, kugan
> <kugan.vivekanandarajah@linaro.org> wrote:
>>
>> Hi,
>>
>>
>>
>> This patch adds a very simple early vrp implementation. This visits the
>> basic blocks in the dominance order and set the Value Ranges (VR) for
>>
>> SSA_NAMEs in the scope. Use this VR to discover more VRs. Restore the old VR
>> once the scope is exit.
>
>
> Why separate out early VRP from tree-vrp?  Just a little curious.
I wouldn't mind seeing tree-vrp broken down a little -- it's quite large 
and there's at least 4 distinct things going on in that file.

1. ASSERT_EXPR handling.

2. Arithmetic on ranges

3. Propagation engine setup, callbacks, etc

4. Range management

There may be others, but it seems at least some of that ought to be 
factored out.

Jeff

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Early VRP Implementation
  2016-07-19 16:19     ` Jeff Law
@ 2016-07-19 18:35       ` Richard Biener
  2016-07-19 20:14         ` Jeff Law
  0 siblings, 1 reply; 67+ messages in thread
From: Richard Biener @ 2016-07-19 18:35 UTC (permalink / raw)
  To: Jeff Law, Andrew Pinski, kugan; +Cc: gcc-patches, Jan Hubicka, Martin Jambor

On July 19, 2016 6:19:23 PM GMT+02:00, Jeff Law <law@redhat.com> wrote:
>On 07/14/2016 10:52 PM, Andrew Pinski wrote:
>> On Thu, Jul 14, 2016 at 9:45 PM, kugan
>> <kugan.vivekanandarajah@linaro.org> wrote:
>>>
>>> Hi,
>>>
>>>
>>>
>>> This patch adds a very simple early vrp implementation. This visits
>the
>>> basic blocks in the dominance order and set the Value Ranges (VR)
>for
>>>
>>> SSA_NAMEs in the scope. Use this VR to discover more VRs. Restore
>the old VR
>>> once the scope is exit.
>>
>>
>> Why separate out early VRP from tree-vrp?  Just a little curious.
>I wouldn't mind seeing tree-vrp broken down a little -- it's quite
>large 
>and there's at least 4 distinct things going on in that file.
>
>1. ASSERT_EXPR handling.
>
>2. Arithmetic on ranges
>
>3. Propagation engine setup, callbacks, etc
>
>4. Range management
>
>There may be others, but it seems at least some of that ought to be 
>factored out.

Possibly, but not necessarily because of the proposed pass.

I'd like to see lattices and lattice entries becoming classes and the arithmetic on it being templated on it.

I do have some preliminary patches implementing a aggressive on-drmand VRP for the use in niter analysis and the
Lattice is what makes sharing code difficult (it's a hash-map instead of an array there).

Richard.


>
>Jeff


^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Early VRP Implementation
  2016-07-19 18:35       ` Richard Biener
@ 2016-07-19 20:14         ` Jeff Law
  0 siblings, 0 replies; 67+ messages in thread
From: Jeff Law @ 2016-07-19 20:14 UTC (permalink / raw)
  To: Richard Biener, Andrew Pinski, kugan
  Cc: gcc-patches, Jan Hubicka, Martin Jambor

On 07/19/2016 12:35 PM, Richard Biener wrote:
>> I wouldn't mind seeing tree-vrp broken down a little -- it's quite
>> large and there's at least 4 distinct things going on in that
>> file.
>>
>> 1. ASSERT_EXPR handling.
>>
>> 2. Arithmetic on ranges
>>
>> 3. Propagation engine setup, callbacks, etc
>>
>> 4. Range management
>>
>> There may be others, but it seems at least some of that ought to be
>>  factored out.
>
> Possibly, but not necessarily because of the proposed pass.
Right.  These are things that, in my mind ought to be done regardless of 
the introduction of IPA-VRP.

>
> I'd like to see lattices and lattice entries becoming classes and the
> arithmetic on it being templated on it.
Seems reasonable as well.

>
> I do have some preliminary patches implementing a aggressive
> on-drmand VRP for the use in niter analysis and the Lattice is what
> makes sharing code difficult (it's a hash-map instead of an array
> there).
It's interesting you mention an on-demand VRP.  I've asked Andrew to 
poke that that some too.  It's for a different need, but interesting 
that we're both looking to take things in that direction.

Jeff

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Add support for IPA VRP in ipa-cp/ipa-prop
  2016-07-19  8:22       ` kugan
@ 2016-07-19 21:27         ` kugan
  2016-07-21 12:54           ` Jan Hubicka
  0 siblings, 1 reply; 67+ messages in thread
From: kugan @ 2016-07-19 21:27 UTC (permalink / raw)
  To: gcc-patches, Richard Biener, Jan Hubicka

[-- Attachment #1: Type: text/plain, Size: 1520 bytes --]

Hi Martin,


On 19/07/16 18:22, kugan wrote:
> Hi Martin,
>
> Thanks for the review.  I have revised the patch based on the review.
> Please see the comments below.
>

Maybe it is better to separate value range and alignment summary 
writing/reading to different functions. Here is another updated version 
which does this.
This should be more readable and easy to maintain. Bootstrapped (LTO and 
normal) and regression tested on x86-64-linux. There are few test-case 
regressions which I am looking int:

Tests that now fail, but worked before:

27_io/basic_istream/get/char/1.cc execution test
g++.dg/ipa/pure-const-3.C  -std=gnu++11  scan-tree-dump optimized "barvar"
g++.dg/ipa/pure-const-3.C  -std=gnu++14  scan-tree-dump optimized "barvar"
g++.dg/ipa/pure-const-3.C  -std=gnu++98  scan-tree-dump optimized "barvar"
gcc.dg/guality/pr54519-1.c   -O2 -flto -fuse-linker-plugin 
-fno-fat-lto-objects  line 20 y == 25
gcc.dg/guality/pr54519-1.c   -O2 -flto -fuse-linker-plugin 
-fno-fat-lto-objects  line 23 y == 117
gcc.dg/torture/ftrapv-1.c   -O2 -flto -fuse-linker-plugin 
-fno-fat-lto-objects  execution test

New tests that FAIL:

gcc.dg/guality/pr54519-1.c   -O2 -flto -fuse-linker-plugin 
-fno-fat-lto-objects  line 20 z == 6
gcc.dg/guality/pr54519-1.c   -O2 -flto -fuse-linker-plugin 
-fno-fat-lto-objects  line 23 z == 8
gcc.dg/tree-ssa/pr22117.c scan-tree-dump-times evrp "Folding predicate 
r_.* != 0B to 0" 1

I will send the patch with testcase fix and Changelog based on the 
preference.


Thanks,
Kugan

[-- Attachment #2: 0005-Add-ipa-vrp.patch --]
[-- Type: text/x-patch, Size: 24485 bytes --]

From 7fe2e29a6ade143c6826a5738e1430fcbe09b05e Mon Sep 17 00:00:00 2001
From: Kugan Vivekanandarajah <kugan.vivekanandarajah@linaro.org>
Date: Tue, 21 Jun 2016 12:43:01 +1000
Subject: [PATCH 5/6] Add ipa vrp

---
 gcc/common.opt                  |   4 +
 gcc/ipa-cp.c                    | 237 +++++++++++++++++++++++++++++++++++++++-
 gcc/ipa-prop.c                  | 214 ++++++++++++++++++++++++++++++++----
 gcc/ipa-prop.h                  |  17 +++
 gcc/testsuite/gcc.dg/ipa/vrp1.c |  32 ++++++
 gcc/testsuite/gcc.dg/ipa/vrp2.c |  35 ++++++
 gcc/testsuite/gcc.dg/ipa/vrp3.c |  30 +++++
 7 files changed, 548 insertions(+), 21 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/ipa/vrp1.c
 create mode 100644 gcc/testsuite/gcc.dg/ipa/vrp2.c
 create mode 100644 gcc/testsuite/gcc.dg/ipa/vrp3.c

diff --git a/gcc/common.opt b/gcc/common.opt
index 29d0e4d..7e3ab5f 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2475,6 +2475,10 @@ ftree-evrp
 Common Report Var(flag_tree_early_vrp) Init(1) Optimization
 Perform Early Value Range Propagation on trees.
 
+fipa-vrp
+Common Report Var(flag_ipa_vrp) Init(1) Optimization
+Perform IPA Value Range Propagation.
+
 fsplit-paths
 Common Report Var(flag_split_paths) Init(0) Optimization
 Split paths leading to loop backedges.
diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
index 4b7f6bb..760e9da 100644
--- a/gcc/ipa-cp.c
+++ b/gcc/ipa-cp.c
@@ -120,6 +120,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "params.h"
 #include "ipa-inline.h"
 #include "ipa-utils.h"
+#include "tree-vrp.h"
 
 template <typename valtype> class ipcp_value;
 
@@ -266,6 +267,25 @@ private:
   bool meet_with_1 (unsigned new_align, unsigned new_misalign);
 };
 
+/* 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.  */
@@ -281,6 +301,8 @@ public:
   ipcp_agg_lattice *aggs;
   /* Lattice describing known alignment.  */
   ipcp_alignment_lattice alignment;
+  /* 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
@@ -348,6 +370,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.  */
 
@@ -458,6 +490,14 @@ ipcp_alignment_lattice::print (FILE * f)
     fprintf (f, "         Alignment %u, misalignment %u\n", align, misalign);
 }
 
+/* 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
@@ -484,6 +524,9 @@ 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);
+	  fprintf (f, "         ");
+	  plats->m_value_range.print (f);
+	  fprintf (f, "\n");
 	  if (plats->virt_call)
 	    fprintf (f, "        virt_call flag set\n");
 
@@ -828,6 +871,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.  */
@@ -915,6 +1029,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->m_value_range.set_to_bottom ();
   return ret;
 }
 
@@ -985,6 +1100,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++)
@@ -996,6 +1117,7 @@ initialize_node_lattices (struct cgraph_node *node)
 	      plats->ctxlat.set_to_bottom ();
 	      set_agg_lats_to_bottom (plats);
 	      plats->alignment.set_to_bottom ();
+	      plats->m_value_range.set_to_bottom ();
 	    }
 	  else
 	    set_all_contains_variable (plats);
@@ -1614,7 +1736,49 @@ propagate_alignment_accross_jump_function (cgraph_edge *cs,
     }
 }
 
-/* If DEST_PLATS already has aggregate items, check that aggs_by_ref matches
+/* 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);
+      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 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.  */
@@ -1963,6 +2127,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 (cs, jump_func, dest_plats);
 	}
     }
   for (; i < parms_count; i++)
@@ -4585,6 +4750,74 @@ ipcp_store_alignment_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
+	 {
+	   vr.known = false;
+	   vr.type = VR_VARYING;
+	   vr.min = NULL_TREE;
+	   vr.max = NULL_TREE;
+	 }
+       ts->m_vr->quick_push (vr);
+     }
+  }
+}
+
 /* The IPCP driver.  */
 
 static unsigned int
@@ -4618,6 +4851,8 @@ ipcp_driver (void)
   ipcp_decision_stage (&topo);
   /* Store results of alignment propagation. */
   ipcp_store_alignment_results ();
+  /* Store results of value range propagation.  */
+  ipcp_store_vr_results ();
 
   /* Free all IPCP structures.  */
   free_toporder_info (&topo);
diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c
index 132b622..de47d3b 100644
--- a/gcc/ipa-prop.c
+++ b/gcc/ipa-prop.c
@@ -41,6 +41,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimplify-me.h"
 #include "gimple-walk.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "tree-cfg.h"
 #include "tree-dfa.h"
@@ -302,6 +303,19 @@ ipa_print_node_jump_functions_for_edge (FILE *f, struct cgraph_edge *cs)
 	}
       else
 	fprintf (f, "         Unknown alignment\n");
+
+      if (jump_func->vr_known)
+	{
+	  fprintf (f, "         VR  ");
+	  fprintf (f, "%s[",
+		   (jump_func->m_vr.type == VR_ANTI_RANGE) ? "~" : "");
+	  print_generic_expr (f, jump_func->m_vr.min, 0);
+	  fprintf (f, ", ");
+	  print_generic_expr (f, jump_func->m_vr.max, 0);
+	  fprintf (f, "]\n");
+	}
+      else
+	fprintf (f, "         Unknown VR\n");
     }
 }
 
@@ -381,6 +395,7 @@ ipa_set_jf_unknown (struct ipa_jump_func *jfunc)
 {
   jfunc->type = IPA_JF_UNKNOWN;
   jfunc->alignment.known = false;
+  jfunc->vr_known = false;
 }
 
 /* Set JFUNC to be a copy of another jmp (to be used by jump function
@@ -1670,9 +1685,25 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
 	    }
 	  else
 	    gcc_assert (!jfunc->alignment.known);
+	  gcc_assert (!jfunc->vr_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->m_vr.type = type;
+	      jfunc->m_vr.min = wide_int_to_tree (TREE_TYPE (arg), min);
+	      jfunc->m_vr.max = wide_int_to_tree (TREE_TYPE (arg), max);
+	    }
+	  else
+	    gcc_assert (!jfunc->vr_known);
+	  gcc_assert (!jfunc->alignment.known);
+	}
 
       if (is_gimple_ip_invariant (arg)
 	  || (TREE_CODE (arg) == VAR_DECL
@@ -3679,16 +3710,28 @@ 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)
     {
       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->m_vr;
       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]);
+      vec<ipa_vr, va_gc> *&dst_vr
+	= ipcp_get_transformation_summary (dst)->m_vr;
+      if (vec_safe_length (src_trans->alignments) > 0)
+	{
+	  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]);
+	}
+      if (vec_safe_length (src_trans->m_vr) > 0)
+	{
+	  vec_safe_reserve_exact (dst_vr, src_vr->length ());
+	  for (unsigned i = 0; i < src_vr->length (); ++i)
+	    dst_vr->quick_push ((*src_vr)[i]);
+	}
     }
 }
 
@@ -4609,6 +4652,15 @@ 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->m_vr.type);
+      stream_write_tree (ob, jump_func->m_vr.min, true);
+      stream_write_tree (ob, jump_func->m_vr.max, true);
+    }
 }
 
 /* Read in jump function JUMP_FUNC from IB.  */
@@ -4685,6 +4737,19 @@ 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->m_vr.type = streamer_read_enum (ib,
+						 value_range_type,
+						 VR_LAST);
+      jump_func->m_vr.min = stream_read_tree (ib, data_in);
+      jump_func->m_vr.max = stream_read_tree (ib, data_in);
+    }
+  else
+    jump_func->vr_known = false;
 }
 
 /* Stream out parts of cgraph_indirect_call_info corresponding to CS that are
@@ -5027,29 +5092,59 @@ 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)
     {
-      count = ts->alignments->length ();
-
-      streamer_write_uhwi (ob, count);
-      for (unsigned i = 0; i < count; ++i)
+      if (vec_safe_length (ts->alignments) > 0)
 	{
-	  ipa_alignment *parm_al = &(*ts->alignments)[i];
+	  count = ts->alignments->length ();
+	  streamer_write_uhwi (ob, count);
+	  for (unsigned i = 0; i < count; ++i)
+	    {
+	      struct bitpack_d bp;
+	      ipa_alignment *parm_al = &(*ts->alignments)[i];
+	      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_hwi_in_range (ob->main_stream, 0,
+					       parm_al->align,
+					       parm_al->misalign);
+		}
+	    }
+	}
+      else
+	streamer_write_uhwi (ob, 0);
 
-	  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)
+      if (vec_safe_length (ts->m_vr) > 0)
+	{
+	  count = ts->m_vr->length ();
+	  streamer_write_uhwi (ob, count);
+	  for (unsigned i = 0; i < count; ++i)
 	    {
-	      streamer_write_uhwi (ob, parm_al->align);
-	      streamer_write_hwi_in_range (ob->main_stream, 0, parm_al->align,
-					   parm_al->misalign);
+	      struct bitpack_d bp;
+	      ipa_vr *parm_vr = &(*ts->m_vr)[i];
+	      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
+	streamer_write_uhwi (ob, 0);
     }
   else
-    streamer_write_uhwi (ob, 0);
+    {
+      streamer_write_uhwi (ob, 0);
+      streamer_write_uhwi (ob, 0);
+    }
 }
 
 /* Stream in the aggregate value replacement chain for NODE from IB.  */
@@ -5102,6 +5197,30 @@ read_ipcp_transformation_info (lto_input_block *ib, cgraph_node *node,
 	    }
 	}
     }
+
+  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->m_vr, count);
+      for (i = 0; i < count; i++)
+	{
+	  ipa_vr *parm_vr;
+	  parm_vr = &(*ts->m_vr)[i];
+	  struct bitpack_d bp;
+	  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);
+	    }
+	}
+    }
 }
 
 /* Write all aggregate replacement for nodes in set.  */
@@ -5404,6 +5523,60 @@ ipcp_update_alignments (struct cgraph_node *node)
     }
 }
 
+
+/* Update value range of formal parameters as described in
+   ipcp_transformation_summary.  */
+
+static void
+ipcp_update_vr (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->m_vr) == 0)
+    return;
+  const vec<ipa_vr, va_gc> &vr = *ts->m_vr;
+  unsigned count = vr.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);
+      tree ddef = ssa_default_def (DECL_STRUCT_FUNCTION (node->decl), parm);
+
+      if (!ddef || !is_gimple_reg (parm))
+	continue;
+
+      if (cgraph_local_p (node)
+	  && vr[i].known
+	  && INTEGRAL_TYPE_P (TREE_TYPE (ddef))
+	  && !POINTER_TYPE_P (TREE_TYPE (ddef))
+	  && (vr[i].type == VR_RANGE || vr[i].type == VR_ANTI_RANGE)
+	  && 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));
+
+	}
+    }
+}
+
 /* IPCP transformation phase doing propagation of aggregate values.  */
 
 unsigned int
@@ -5423,6 +5596,7 @@ ipcp_transform_function (struct cgraph_node *node)
 	     node->name (), node->order);
 
   ipcp_update_alignments (node);
+  ipcp_update_vr (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 e32d078..82c1086 100644
--- a/gcc/ipa-prop.h
+++ b/gcc/ipa-prop.h
@@ -154,6 +154,17 @@ 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 min;
+  tree 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 +177,10 @@ struct GTY (()) ipa_jump_func
   /* Information about alignment of pointers. */
   struct ipa_alignment alignment;
 
+  /* Information about value range.  */
+  bool vr_known;
+  value_range m_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 +497,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> *m_vr;
 };
 
 void ipa_set_node_agg_value_chain (struct cgraph_node *node,
diff --git a/gcc/testsuite/gcc.dg/ipa/vrp1.c b/gcc/testsuite/gcc.dg/ipa/vrp1.c
new file mode 100644
index 0000000..72a3139
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/vrp1.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-ipa-cp-details" } */
+
+static __attribute__((noinline, noclone))
+int foo (int i)
+{
+  if (i < 5)
+    __builtin_abort ();
+  return 0;
+}
+
+static __attribute__((noinline, noclone))
+int bar (int j)
+{
+  if (j > 8)
+    return foo (j + 2);
+  else if (j > 2)
+    return foo (j + 3);
+
+  return 0;
+}
+
+int main ()
+{
+  for (unsigned int i =0; i < 1000; ++i)
+    bar (i);
+
+  return 0;
+}
+
+/* { dg-final { scan-ipa-dump "Setting value range of param 0 \\\[6," "cp" } } */
+/* { dg-final { scan-ipa-dump "Setting value range of param 0 \\\[0, 999\\\]" "cp" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/vrp2.c b/gcc/testsuite/gcc.dg/ipa/vrp2.c
new file mode 100644
index 0000000..c720e5c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/vrp2.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-ipa-cp-details" } */
+
+static __attribute__((noinline, noclone))
+int foo (int i)
+{
+  if (i < 4)
+    __builtin_abort ();
+  return 0;
+}
+
+static __attribute__((noinline, noclone))
+int bar (int j)
+{
+  if (j > 8)
+    return foo (j + 2);
+  else if (j > 2)
+    return foo (j + 3);
+
+  return 0;
+}
+
+int main ()
+{
+  foo (100);
+  for (unsigned int i = 0; i < 12; ++i)
+    {
+      bar (i);
+    }
+  foo (4);
+  return 0;
+}
+
+/* { dg-final { scan-ipa-dump "Setting value range of param 0 \\\[4," "cp" } } */
+/* { dg-final { scan-ipa-dump "Setting value range of param 0 \\\[0, 11\\\]" "cp" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/vrp3.c b/gcc/testsuite/gcc.dg/ipa/vrp3.c
new file mode 100644
index 0000000..fb5d54a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/vrp3.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-ipa-cp-details" } */
+
+volatile int cond;
+
+static __attribute__((noinline, noclone))
+int foo (int i)
+{
+  if (i < 5)
+    __builtin_abort ();
+  return 0;
+}
+
+static __attribute__((noinline, noclone))
+int bar (int j)
+{
+  if (cond)
+    foo (j);
+  return 0;
+}
+
+int main ()
+{
+  for (unsigned int i = 0; i < 10; ++i)
+    bar (i);
+
+  return 0;
+}
+
+/* { dg-final { scan-ipa-dump-times "Setting value range of param 0 \\\[0, 9\\\]" 2 "cp" } } */
-- 
1.9.1


^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Add support for IPA VRP in ipa-cp/ipa-prop
  2016-07-19 21:27         ` kugan
@ 2016-07-21 12:54           ` Jan Hubicka
  2016-08-30  5:21             ` Kugan Vivekanandarajah
  0 siblings, 1 reply; 67+ messages in thread
From: Jan Hubicka @ 2016-07-21 12:54 UTC (permalink / raw)
  To: kugan; +Cc: gcc-patches, Richard Biener, Jan Hubicka

> Maybe it is better to separate value range and alignment summary
> writing/reading to different functions. Here is another updated
> version which does this.

Makes sense to me. Note that the alignment summary propagation can be either
handled by doing bitwise constant propagation and/or extending our value ranges
by stride (as described in
http://www.lighterra.com/papers/valuerangeprop/Patterson1995-ValueRangeProp.pdf
I would like it to go eventually away in favour of more generic solution.

> -/* If DEST_PLATS already has aggregate items, check that aggs_by_ref matches
> +/* 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);
> +      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);

Clearly we can propagate thorugh expressions here (PLUS_EXPR). I have run
into similar issue in loop code that builds simple generic expresisons
(like (int)ssa_name+10) and it would be nice to have easy way to deterine
their value range based on the knowledge of SSA_NAME's valur range.

Bit this is fine for initial implementaiotn for sure.
>  
> +/* 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;

I belive you need to also prevent propagation through functions copmiled with
-fno-ipa-vrp, not only prevent any transformations.
> +/* Update value range of formal parameters as described in
> +   ipcp_transformation_summary.  */
> +
> +static void
> +ipcp_update_vr (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->m_vr) == 0)
> +    return;
> +  const vec<ipa_vr, va_gc> &vr = *ts->m_vr;
> +  unsigned count = vr.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);
> +      tree ddef = ssa_default_def (DECL_STRUCT_FUNCTION (node->decl), parm);
> +
> +      if (!ddef || !is_gimple_reg (parm))
> +	continue;
> +
> +      if (cgraph_local_p (node)
The test of cgraph_local_p seems redundant here. The analysis phase should not determine
anything if function is reachable non-locally.
> +/* 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 min;
> +  tree max;
What is the point of representing range as trees rather than wide ints. Can they
be non-constant integer?

The patch looks good to me otherwise!
Honza

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Early VRP Implementation
  2016-07-18 11:51           ` Richard Biener
@ 2016-07-22 12:10             ` kugan
  2016-07-25 11:18               ` Richard Biener
  0 siblings, 1 reply; 67+ messages in thread
From: kugan @ 2016-07-22 12:10 UTC (permalink / raw)
  To: Richard Biener; +Cc: Andrew Pinski, gcc-patches, Jan Hubicka, Martin Jambor

[-- Attachment #1: Type: text/plain, Size: 6698 bytes --]

Hi Richard,

Thanks for the review.

On 18/07/16 21:51, Richard Biener wrote:
> On Fri, Jul 15, 2016 at 9:33 AM, kugan
> <kugan.vivekanandarajah@linaro.org> wrote:
>> Hi Andrew,
>>
>> On 15/07/16 17:28, Andrew Pinski wrote:
>>>
>>> On Fri, Jul 15, 2016 at 12:08 AM, kugan
>>> <kugan.vivekanandarajah@linaro.org> wrote:
>>>>
>>>> Hi Andrew,
>>>>
>>>>> Why separate out early VRP from tree-vrp?  Just a little curious.
>>>>
>>>>
>>>>
>>>> It is based on the discussion in
>>>> https://gcc.gnu.org/ml/gcc/2016-01/msg00069.html.
>>>> In summary, conclusion (based on my understanding) was to implement a
>>>> simplified VRP algorithm that doesn't require ASSERT_EXPR insertion.
>>>
>>>
>>> But I don't see why you are moving it from tree-vrp.c .  That was my
>>> question, you pointing to that discussion does not say to split it
>>> into a new file and expose these interfaces.
>>>
>>
>> Are you saying that I should keep this part of tree-vrp.c. I am happy to do
>> that if this is considered the best approach.
>
> Yes, I think that's the best approach.
>
Thanks. Moved it into tree-vrp.c now.

> Can you, as a refactoring before your patch, please change VRP to use
> an alloc-pool
> for allocating value_range?  The DOM-based VRP will add a lot of
> malloc/free churn
> otherwise.
>
> Generally watch coding-style such as  missed function comments.
>
> As you do a non-iterating VRP and thus do not visit back-edges you don't need
> to initialize loops or SCEV nor do you need loop-closed SSA.
>
> As you do a DOM-based VRP using SSA propagator stuff like ssa_prop_result
> doesn't make any sense.

I have removed it.
>
> +edge evrp_dom_walker::before_dom_children (basic_block bb)
> +{
> +  /* If we are going out of scope, restore the old VR.  */
> +  while (!cond_stack.is_empty ()
> +        && !dominated_by_p (CDI_DOMINATORS, bb, cond_stack.last ().first))
> +    {
> +      tree var = cond_stack.last ().second.first;
> +      value_range *vr = cond_stack.last ().second.second;
> +      value_range *vr_to_del = get_value_range (var);
> +      XDELETE (vr_to_del);
> +      change_value_range (var, vr);
> +      cond_stack.pop ();
> +    }
>
> that should be in after_dom_children I think and use a marker instead
> of a DOM query.
> See other examples like DOM itself or SCCVN.
>

Done.
> +         /* Discover VR when condition is true.  */
> +         if (te == e
> +             && !TREE_OVERFLOW_P (op0)
> +             && !TREE_OVERFLOW_P (op1))

This is mainly to handle gcc.dg/pr38934.c. This would result in ICE from 
set_value_range otherwise:

gcc_assert ((!TREE_OVERFLOW_P (min) || is_overflow_infinity (min))
                   && (!TREE_OVERFLOW_P (max) || is_overflow_infinity 
(max)));

>
> you can use e->flags & EDGE_TRUE_VALUE/EDGE_FALSE_VALUE
>
> why do you need those TREE_OVERFLOW checks?
>
> +             tree cond = build2 (code, boolean_type_node, op0, op1);
> +             tree a = build2 (ASSERT_EXPR, TREE_TYPE (op0), op0, cond);
> +             extract_range_from_assert (&vr, a);
>
> so I was hoping that the "refactoring" patch in the series would expose a more
> useful interface than extract_range_from_assert ... namely one that can
> extract a range from the comparison directly and does not require building
> a scratch ASSERT_EXPR.

I have split extract_range_from_assert into 
extract_range_for_var_from_comparison_expr and using it now. Is that better?
>
> +         /* If we found any usable VR, set the VR to ssa_name and create a
> +            restore point in the cond_stack with the  old VR. */
> +         if (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE)
> +           {
> +             value_range *new_vr = XCNEW (value_range);
> +             *new_vr = vr;
> +             cond_stack.safe_push (std::make_pair (bb,
> +                                                   std::make_pair (op0,
> +                                                                   old_vr)));
> +             change_value_range (op0, new_vr);
>
> I don't like 'change_value_range' as interface, please integrate that into
> a push/pop_value_range style interface instead.

Tried using push/pop interface.
>
> +       vrp_visit_stmt (stmt, &taken_edge_p, &output_p);
> +    }
> +
> +  return NULL;
>
> you should return taken_edge_p (misnamed as it isn't a pointer) and take
> advantage of EDGE_EXECUTABLE.  Again see DOM/SCCVN (might want to
> defer this as a followup improvement).

I have added a TODO to this effect and will comeback to it.
>
> Note that the advantage of a DOM-based VRP is that backtracking is easy
> to implement (you don't do that yet).  That is, after DEF got a (better)
> value-range you can simply re-visit all the defs of its uses (and recursively).
> I think you have to be careful with stmts that might prematurely leave a BB
> though (like via EH).  So sth for a followup as well.

Is this OK now. Bootstrapped and regression tested on x86_64-linux  with 
no new regressions.

Thanks,
Kugan

gcc/ChangeLog:

2016-07-22  Kugan Vivekanandarajah  <kuganv@linaro.org>

	* common.opt: New option -ftree-evrp.
	* doc/invoke.texi: Document -ftree-evrp.
	* passes.def: Define new pass_early_vrp.
	* timevar.def: Define new TV_TREE_EARLY_VRP.
	* tree-pass.h (make_pass_early_vrp): New.
	* tree-vrp.c (extract_range_for_var_from_comparison_expr): New.
	(extract_range_from_assert): Call
	extract_range_for_var_from_comparison_expr.
	(push_value_range): New.
	(pop_value_range): Likewise.
	(evrp_visit_phi_node_local): Likewise.
	(edge evrp_dom_walker::before_dom_children): Likewise.
	(void evrp_dom_walker::after_dom_children): Likewise.
	(void evrp_dom_walker::finalize_dom_walker): Likewise.
	(execute_early_vrp): Likewise.
	(make_pass_early_vrp): Likewise.


gcc/testsuite/ChangeLog:

2016-07-22  Kugan Vivekanandarajah  <kuganv@linaro.org>

	* gcc.dg/tree-ssa/evrp1.c: New test.
	* gcc.dg/tree-ssa/evrp2.c: New test.
	* gcc.dg/tree-ssa/evrp3.c: New test.
	* g++.dg/tree-ssa/pr31146-2.C: Run with -fno-tree-evrp as evrp also
	does the same transformation.
	* gcc.dg/tree-ssa/pr20318.c: Likewise.
	* gcc.dg/tree-ssa/pr25382.c: Likewise.
	* gcc.dg/tree-ssa/pr68431.c: Likewise.
	* gcc.dg/tree-ssa/vrp19.c: Likewise.
	* gcc.dg/tree-ssa/vrp23.c: Likewise.
	* gcc.dg/tree-ssa/vrp24.c: Likewise.
	* gcc.dg/tree-ssa/vrp58.c: Likewise.
	* gcc.dg/tree-ssa/vrp67.c: Likewise.
	* gcc.dg/tree-ssa/vrp98.c: Likewise.
	* gcc.dg/tree-ssa/vrp19.c: Likewise.
	* gcc.dg/tree-ssa/vrp23.c: Likewise.
	* gcc.dg/tree-ssa/vrp24.c: Likewise.
	* gcc.dg/tree-ssa/vrp58.c: Likewise.
	* gcc.dg/tree-ssa/vrp67.c: Likewise.
	* gcc.dg/tree-ssa/vrp98.c: Likewise.
	* gcc.dg/tree-ssa/pr22117.c: Run with -fno-tree-evrp as predicate is
	optimized away before vrp1.

[-- Attachment #2: 0005-Add-early-vrp.patch --]
[-- Type: text/x-patch, Size: 24325 bytes --]

From d2b49fe0fc7d3b2b1f130e448834ffee0deb981a Mon Sep 17 00:00:00 2001
From: Kugan Vivekanandarajah <kugan.vivekanandarajah@linaro.org>
Date: Fri, 24 Jun 2016 14:45:24 +1000
Subject: [PATCH 5/7] Add early vrp

---
 gcc/common.opt                            |   4 +
 gcc/doc/invoke.texi                       |   9 +
 gcc/passes.def                            |   1 +
 gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C |   2 +-
 gcc/testsuite/gcc.dg/tree-ssa/evrp1.c     |  13 ++
 gcc/testsuite/gcc.dg/tree-ssa/evrp2.c     |  18 ++
 gcc/testsuite/gcc.dg/tree-ssa/evrp3.c     |  15 ++
 gcc/testsuite/gcc.dg/tree-ssa/pr20318.c   |   4 +-
 gcc/testsuite/gcc.dg/tree-ssa/pr22117.c   |   2 +-
 gcc/testsuite/gcc.dg/tree-ssa/pr25382.c   |   4 +-
 gcc/testsuite/gcc.dg/tree-ssa/pr68431.c   |   4 +-
 gcc/testsuite/gcc.dg/tree-ssa/vrp19.c     |   6 +-
 gcc/testsuite/gcc.dg/tree-ssa/vrp23.c     |   4 +-
 gcc/testsuite/gcc.dg/tree-ssa/vrp24.c     |   5 +-
 gcc/testsuite/gcc.dg/tree-ssa/vrp58.c     |   4 +-
 gcc/testsuite/gcc.dg/tree-ssa/vrp67.c     |   4 +-
 gcc/testsuite/gcc.dg/tree-ssa/vrp98.c     |   6 +-
 gcc/timevar.def                           |   1 +
 gcc/tree-pass.h                           |   1 +
 gcc/tree-vrp.c                            | 303 +++++++++++++++++++++++++++++-
 20 files changed, 382 insertions(+), 28 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/evrp1.c
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/evrp2.c
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/evrp3.c

diff --git a/gcc/common.opt b/gcc/common.opt
index f0d7196..29d0e4d 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2471,6 +2471,10 @@ ftree-vrp
 Common Report Var(flag_tree_vrp) Init(0) Optimization
 Perform Value Range Propagation on trees.
 
+ftree-evrp
+Common Report Var(flag_tree_early_vrp) Init(1) Optimization
+Perform Early Value Range Propagation on trees.
+
 fsplit-paths
 Common Report Var(flag_split_paths) Init(0) Optimization
 Split paths leading to loop backedges.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index e000218..f4dc88d 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -7665,6 +7665,10 @@ enabled by default at @option{-O2} and higher.  Null pointer check
 elimination is only done if @option{-fdelete-null-pointer-checks} is
 enabled.
 
+@item -ftree-evrp
+@opindex ftree-evrp
+Perform Early Value Range Propagation on trees.
+
 @item -fsplit-paths
 @opindex fsplit-paths
 Split paths leading to loop backedges.  This can improve dead code
@@ -12270,6 +12274,11 @@ is made by appending @file{.slp} to the source file name.
 Dump each function after Value Range Propagation (VRP).  The file name
 is made by appending @file{.vrp} to the source file name.
 
+@item early vrp
+@opindex fdump-tree-evrp
+Dump each function after Early Value Range Propagation (EVRP).  The file name
+is made by appending @file{.evrp} to the source file name.
+
 @item oaccdevlow
 @opindex fdump-tree-oaccdevlow
 Dump each function after applying device-specific OpenACC transformations.
diff --git a/gcc/passes.def b/gcc/passes.def
index 3647e90..1e59d45 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -102,6 +102,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_early_vrp);
       POP_INSERT_PASSES ()
       NEXT_PASS (pass_release_ssa_names);
       NEXT_PASS (pass_rebuild_cgraph_edges);
diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C b/gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C
index 5e09583..dce05d6 100644
--- a/gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C
+++ b/gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O -fdump-tree-forwprop1" } */
+/* { dg-options "-O -fno-tree-evrp -fdump-tree-forwprop1" } */
 
 #include <new>
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/evrp1.c b/gcc/testsuite/gcc.dg/tree-ssa/evrp1.c
new file mode 100644
index 0000000..8c6e4e6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/evrp1.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+int foo (int i);
+int bar (int j)
+{
+  if (j > 2)
+    return foo (j + 2);
+  else
+    return j;
+}
+
+/* { dg-final { scan-tree-dump "\\\[5, \\+INF" "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/evrp2.c b/gcc/testsuite/gcc.dg/tree-ssa/evrp2.c
new file mode 100644
index 0000000..e6d4235
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/evrp2.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+int foo (int i);
+int bar2 (int j)
+{
+  if (j > 2)
+    {
+      if (j < 7)
+	return foo (j + 1);
+      else
+	return foo (j + 2);
+    }
+  return j;
+}
+
+
+/* { dg-final { scan-tree-dump "\\\[4, 7\\\]" "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/evrp3.c b/gcc/testsuite/gcc.dg/tree-ssa/evrp3.c
new file mode 100644
index 0000000..1a3bbd5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/evrp3.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+int foo (int i);
+void bar (int j)
+{
+  unsigned int i;
+  for (i = 0; i < 10; ++i)
+    {
+      bar (i + 1);
+    }
+}
+
+/* { dg-final { scan-tree-dump "\\\[1, 10\\\]" "evrp" } } */
+
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr20318.c b/gcc/testsuite/gcc.dg/tree-ssa/pr20318.c
index 41f569e..8c12863 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr20318.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr20318.c
@@ -1,5 +1,5 @@
 /* { dg-do compile { target { ! keeps_null_pointer_checks } } } */
-/* { dg-options "-O2 -fdump-tree-original -fdump-tree-vrp1 -fdelete-null-pointer-checks" } */
+/* { dg-options "-O2 -fdump-tree-original -fdump-tree-evrp  -fdelete-null-pointer-checks" } */
 
 extern int* f(int) __attribute__((returns_nonnull));
 extern void eliminate ();
@@ -14,4 +14,4 @@ void h () {
 }
 
 /* { dg-final { scan-tree-dump-times "== 0" 1 "original" } } */
-/* { dg-final { scan-tree-dump-times "Folding predicate\[^\\n\]*to 0" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "Folding predicate\[^\\n\]*to 0" 1 "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c b/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c
index 7efdd63..43cea0b 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c
@@ -3,7 +3,7 @@
    known to be zero after entering the first two "if" statements.  */
 
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1" } */
+/* { dg-options "-O2 -fno-tree-evrp -fdump-tree-vrp" } */
 
 void link_error (void);
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c b/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c
index dcf9148..0d19d0d 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c
@@ -3,7 +3,7 @@
    Check that VRP now gets ranges from BIT_AND_EXPRs.  */
 
 /* { dg-do compile } */
-/* { dg-options "-O2 -fno-tree-ccp -fdump-tree-vrp1" } */
+/* { dg-options "-O2 -fno-tree-ccp -fdump-tree-evrp" } */
 
 int
 foo (int a)
@@ -15,4 +15,4 @@ foo (int a)
     return 1;
 }
 
-/* { dg-final { scan-tree-dump-times "Folding predicate b_.* > 300 to 0" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "Folding predicate b_.* > 300 to 0" 1 "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr68431.c b/gcc/testsuite/gcc.dg/tree-ssa/pr68431.c
index 3bd3843..a73aa00 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr68431.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr68431.c
@@ -1,5 +1,5 @@
 /* PR tree-optimization/68431 */
-/* { dg-options "-O2 -fdump-tree-vrp1-details" } */
+/* { dg-options "-O2 -fdump-tree-evrp-details" } */
 
 unsigned int x = 1;
 int
@@ -13,4 +13,4 @@ main (void)
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "Folding predicate .*to 0" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "Folding predicate .*to 0" 1 "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp19.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp19.c
index cecacb6..3d47bfd 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp19.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp19.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-fwrapv -O1 -ftree-vrp -fdump-tree-vrp1" } */
+/* { dg-options "-fwrapv -O1 -ftree-vrp -fdump-tree-evrp" } */
 
 #include <limits.h>
 extern void abort ();
@@ -22,5 +22,5 @@ int g (int b) {
 	}
 	return 1;
 }
-/* { dg-final { scan-tree-dump "Folding predicate a_. < 0 to 0" "vrp1" } } */
-/* { dg-final { scan-tree-dump "Folding predicate b_. >= 0 to 1" "vrp1" } } */
+/* { dg-final { scan-tree-dump "Folding predicate a_. < 0 to 0" "evrp" } } */
+/* { dg-final { scan-tree-dump "Folding predicate b_. >= 0 to 1" "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp23.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp23.c
index b877ccc..a6d2a24 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp23.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp23.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1-details" } */
+/* { dg-options "-O2 -fdump-tree-evrp-details" } */
 
 void aa (void);
 void aos (void);
@@ -45,5 +45,5 @@ L8:
 /* The n_sets > 0 test can be simplified into n_sets == 1 since the
    only way to reach the test is when n_sets <= 1, and the only value
    which satisfies both conditions is n_sets == 1.  */
-/* { dg-final { scan-tree-dump-times "Simplified relational" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "Simplified relational" 1 "evrp" } } */
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp24.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp24.c
index e740575..0e1e69c 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp24.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp24.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1-details" } */
+/* { dg-options "-O2 -fdump-tree-evrp-details -fdump-tree-vrp1-details" } */
 
 
 struct rtx_def;
@@ -91,5 +91,6 @@ L7:
    The second n_sets > 0 test can also be simplified into n_sets == 1
    as the only way to reach the tests is when n_sets <= 1 and the only
    value which satisfies both conditions is n_sets == 1.  */
-/* { dg-final { scan-tree-dump-times "Simplified relational" 2 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "Simplified relational" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "Simplified relational" 1 "evrp" } } */
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp58.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp58.c
index 5b44ae2..6df91ca 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp58.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp58.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1-details" } */
+/* { dg-options "-O2 -fdump-tree-evrp-details" } */
 
 long long
 foo (long long a, signed char b, signed char c)
@@ -9,4 +9,4 @@ foo (long long a, signed char b, signed char c)
 }
 
 /* { dg-final { scan-tree-dump "Folded into" "vrp1" { target int32plus } } } */
-/* { dg-final { scan-tree-dump "Folding statement: _\[0-9\]\* = \\(long long int\\) bc_\[0-9\]\*;" "vrp1" { target int16 } } } */
+/* { dg-final { scan-tree-dump "Folding statement: _\[0-9\]\* = \\(long long int\\) bc_\[0-9\]\*;" "evrp" { target int16 } } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp67.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp67.c
index ef5e8f9..b19b546 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp67.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp67.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1" } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
 
 extern void link_error (void);
 
@@ -36,4 +36,4 @@ unsigned baz (unsigned i)
   return i;
 }
 
-/* { dg-final { scan-tree-dump-times "Folding predicate" 3 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "Folding predicate" 3 "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp98.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp98.c
index 982f091..7ad818c 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp98.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp98.c
@@ -1,6 +1,6 @@
 /* { dg-do compile } */
 /* { dg-require-effective-target int128 } */
-/* { dg-options "-Os -fdump-tree-vrp1-details" } */
+/* { dg-options "-Os -fdump-tree-evrp-details" } */
 
 #include <stdint.h>
 #include <limits.h>
@@ -36,6 +36,6 @@ foo (bigger_than_word a, word b, uint8_t c)
   return ret;
 }
 
-/* { dg-final { scan-tree-dump "Folded into: if \\(_\[0-9\]+ == 1\\)" "vrp1" } } */
+/* { dg-final { scan-tree-dump "Folded into: if \\(_\[0-9\]+ == 1\\)" "evrp" } } */
 /* { dg-final { scan-tree-dump-not "Folded into: if \\(_\[0-9\]+ == 2\\)" "vrp1" } } */
-/* { dg-final { scan-tree-dump "Folded into: if \\(_\[0-9\]+ == 3\\)" "vrp1" } } */
+/* { dg-final { scan-tree-dump "Folded into: if \\(_\[0-9\]+ == 3\\)" "evrp" } } */
diff --git a/gcc/timevar.def b/gcc/timevar.def
index 362aa6e..8d308ac 100644
--- a/gcc/timevar.def
+++ b/gcc/timevar.def
@@ -147,6 +147,7 @@ DEFTIMEVAR (TV_TREE_CFG		     , "tree CFG construction")
 DEFTIMEVAR (TV_TREE_CLEANUP_CFG	     , "tree CFG cleanup")
 DEFTIMEVAR (TV_TREE_TAIL_MERGE       , "tree tail merge")
 DEFTIMEVAR (TV_TREE_VRP              , "tree VRP")
+DEFTIMEVAR (TV_TREE_EARLY_VRP        , "tree Early VRP")
 DEFTIMEVAR (TV_TREE_COPY_PROP        , "tree copy propagation")
 DEFTIMEVAR (TV_FIND_REFERENCED_VARS  , "tree find ref. vars")
 DEFTIMEVAR (TV_TREE_PTA		     , "tree PTA")
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index 36299a6..d836d57 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -440,6 +440,7 @@ extern gimple_opt_pass *make_pass_fre (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_check_data_deps (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_copy_prop (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_isolate_erroneous_paths (gcc::context *ctxt);
+extern gimple_opt_pass *make_pass_early_vrp (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_vrp (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_uncprop (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_return_slot (gcc::context *ctxt);
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index a318d39..20b4a33 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -60,6 +60,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "case-cfn-macros.h"
 #include "alloc-pool.h"
 #include "tree-vrp.h"
+#include "domwalk.h"
 
 #define VR_INITIALIZER { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL }
 
@@ -1437,19 +1438,17 @@ op_with_boolean_value_range_p (tree op)
 	  && integer_onep (vr->max));
 }
 
-/* Extract value range information from an ASSERT_EXPR EXPR and store
+/* Extract value range information for VAR when COND is true and store
    it in *VR_P.  */
 
 static void
-extract_range_from_assert (value_range *vr_p, tree expr)
+extract_range_for_var_from_comparison_expr (value_range *vr_p,
+					    tree var, tree cond)
 {
-  tree var, cond, limit, min, max, type;
+  tree limit, min, max, type;
   value_range *limit_vr;
   enum tree_code cond_code;
 
-  var = ASSERT_EXPR_VAR (expr);
-  cond = ASSERT_EXPR_COND (expr);
-
   gcc_assert (COMPARISON_CLASS_P (cond));
 
   /* Find VAR in the ASSERT_EXPR conditional.  */
@@ -1709,6 +1708,16 @@ extract_range_from_assert (value_range *vr_p, tree expr)
   vrp_intersect_ranges (vr_p, get_value_range (var));
 }
 
+/* Extract value range information from an ASSERT_EXPR EXPR and store
+   it in *VR_P.  */
+
+static void
+extract_range_from_assert (value_range *vr_p, tree expr)
+{
+  tree var = ASSERT_EXPR_VAR (expr);
+  tree cond = ASSERT_EXPR_COND (expr);
+  extract_range_for_var_from_comparison_expr (vr_p, var, cond);
+}
 
 /* Extract range information from SSA name VAR and store it in VR.  If
    VAR has an interesting range, use it.  Otherwise, create the
@@ -10201,6 +10210,250 @@ vrp_finalize (bool jump_thread_p, bool warn_array_bounds_p)
 }
 
 
+/* vrp_stack for maintaining value ranges in the scope and to update.  The
+   order in which variable are pushed and poped must be the same.
+   I.e. if a VR for variable VAR is pushed, it must be poped first.  */
+
+static vec<std::pair <const_tree, value_range*> > vrp_stack (vNULL);
+
+/* Push the Value Range of VAR to the stack and upadate it with new VR.  */
+
+void push_value_range (const_tree var, value_range *vr)
+{
+  unsigned ver = SSA_NAME_VERSION (var);
+  gcc_checking_assert (vr_value);
+  vrp_stack.safe_push (std::make_pair (var, vr_value[ver]));
+
+  if (ver < num_vr_values)
+    vr_value[ver] = vr;
+}
+
+/* Pop the Value Range from the vrp_stack and update VAR with it.  */
+
+value_range *pop_value_range (const_tree var)
+{
+  unsigned ver = SSA_NAME_VERSION (var);
+  value_range *vr = vrp_stack.last ().second;
+  gcc_checking_assert (var == vrp_stack.last ().first);
+  vrp_stack.pop ();
+  gcc_checking_assert (vr_value);
+
+  if (ver < num_vr_values)
+      vr_value[ver] = vr;
+  return vr;
+}
+
+/* Visit the basic blocks in the dominance order and set the Value Ranges (VR)
+   for SSA_NAMEs in the scope.  Use this VR to discover more VRs.  Restore the
+   old VR once the scope is exited.  */
+
+static bool
+evrp_visit_phi_node_local (gphi *phi)
+{
+  size_t i;
+  tree lhs = PHI_RESULT (phi);
+  value_range vr_result = VR_INITIALIZER;
+  bool first = true;
+  int edges;
+
+  edges = 0;
+  for (i = 0; i < gimple_phi_num_args (phi); i++)
+    {
+      edge e = gimple_phi_arg_edge (phi, i);
+      tree arg = PHI_ARG_DEF (phi, i);
+      value_range vr_arg = VR_INITIALIZER;
+      ++edges;
+
+      /* If there is a back-edge, set the result to VARYING.  */
+      if (e->flags & (EDGE_DFS_BACK | EDGE_COMPLEX))
+	{
+	  set_value_range_to_varying (&vr_result);
+	  break;
+	}
+
+      if (TREE_CODE (arg) == SSA_NAME)
+	vr_arg = *(get_value_range (arg));
+      else
+	set_value_range_to_varying (&vr_arg);
+
+      /* If any of the RHS value is VARYING, set the result to VARYING.  */
+      if ((vr_arg.type != VR_RANGE)
+	  && (vr_arg.type != VR_ANTI_RANGE))
+	{
+	  set_value_range_to_varying (&vr_result);
+	  break;
+	}
+
+      /* Set/meet the RHS value range with the result so far.  */
+      if (first)
+	set_value_range (&vr_result, vr_arg.type, vr_arg.min,
+			 vr_arg.max, vr_arg.equiv);
+      else
+	vrp_meet (&vr_result, &vr_arg);
+      first = false;
+      if (vr_result.type == VR_VARYING)
+	break;
+    }
+
+  /* Check if the value range has changed and return accordingly.  */
+  if (update_value_range (lhs, &vr_result))
+    return true;
+  else
+    return false;
+}
+
+/* evrp_dom_walker visits the basic blocks in the dominance order and set the
+   Value Ranges (VR) for SSA_NAMEs in the scope.  Use this VR to discover
+   more VRs.  */
+
+class evrp_dom_walker : public dom_walker
+{
+public:
+  evrp_dom_walker ()
+    : dom_walker (CDI_DOMINATORS), cond_stack (vNULL) {}
+
+  void finalize_dom_walker ();
+  virtual edge before_dom_children (basic_block);
+  virtual void after_dom_children (basic_block);
+
+  /* Cond_stack holds the old VR.  */
+  vec<std::pair <basic_block, tree> > cond_stack;
+};
+
+/* See if there is any new scope is entered with new VR and set that VR to
+   ssa_name before visiting the statements in the scope.  */
+
+edge evrp_dom_walker::before_dom_children (basic_block bb)
+{
+  if (single_pred_p (bb))
+    {
+      edge e = single_pred_edge (bb);
+      value_range vr = VR_INITIALIZER;
+      gimple *stmt = last_stmt (e->src);
+
+      if (stmt
+	  && gimple_code (stmt) == GIMPLE_COND
+	  && INTEGRAL_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt))))
+	{
+	  tree op0 = gimple_cond_lhs (stmt);
+	  tree op1 = gimple_cond_rhs (stmt);
+	  tree_code code = gimple_cond_code (stmt);
+	  value_range *old_vr = get_value_range (op0);
+
+	  /* Discover VR when condition is true.  */
+	  if (e->flags & EDGE_TRUE_VALUE
+	      && !TREE_OVERFLOW_P (op0)
+	      && !TREE_OVERFLOW_P (op1))
+	    {
+	      tree cond = build2 (code, boolean_type_node, op0, op1);
+	      extract_range_for_var_from_comparison_expr (&vr, op0, cond);
+	      if (old_vr->type == VR_RANGE || old_vr->type == VR_ANTI_RANGE)
+		vrp_intersect_ranges (&vr, old_vr);
+	    }
+	  /* Discover VR when condition is false.  */
+	  else if (e->flags & EDGE_FALSE_VALUE
+	      && !TREE_OVERFLOW_P (op0)
+	      && !TREE_OVERFLOW_P (op1))
+	    {
+	      tree_code code
+		= invert_tree_comparison (gimple_cond_code (stmt),
+					  HONOR_NANS (op0));
+	      tree cond = build2 (code, boolean_type_node, op0, op1);
+	      extract_range_for_var_from_comparison_expr (&vr, op0, cond);
+	      if (old_vr->type == VR_RANGE || old_vr->type == VR_ANTI_RANGE)
+		vrp_intersect_ranges (&vr, old_vr);
+	    }
+
+	  /* If we found any usable VR, set the VR to ssa_name and create a
+	     PUSH old value in the cond_stack with the old VR.  */
+	  if (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE)
+	    {
+	      value_range *new_vr = vrp_value_range_pool.allocate ();
+	      memset (new_vr, 0, sizeof (*new_vr));
+	      *new_vr = vr;
+	      cond_stack.safe_push (std::make_pair (bb, op0));
+	      push_value_range (op0, new_vr);
+	    }
+	}
+    }
+
+  /* Visit PHI stmts and discover any new VRs possible.  */
+  gimple_stmt_iterator gsi;
+  for (gphi_iterator gpi = gsi_start_phis (bb);
+       !gsi_end_p (gpi); gsi_next (&gpi))
+    {
+      gphi *phi = gpi.phi ();
+      if (stmt_interesting_for_vrp (phi))
+	evrp_visit_phi_node_local (phi);
+    }
+
+  /* Visit all other stmts and discover any new VRs possible.  */
+  for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+    {
+      gimple *stmt = gsi_stmt (gsi);
+      edge taken_edge;
+      tree output;
+      /* TODO, if found taken_edge, we should visit (return it) and travel
+	 again to improve VR as done in DOM/SCCVN optimizations.  It should
+	 be done carefully as stmts might prematurely leave a BB like
+	 in EH.  */
+      if (stmt_interesting_for_vrp (stmt))
+	vrp_visit_stmt (stmt, &taken_edge, &output);
+    }
+  return NULL;
+}
+
+/* Restore/Pop VRs valid only for BB when we leave BB.  */
+
+void evrp_dom_walker::after_dom_children (basic_block bb)
+{
+  if (!cond_stack.is_empty ()
+      && bb == cond_stack.last ().first)
+    {
+      tree var = cond_stack.last ().second;
+      pop_value_range (var);
+      cond_stack.pop ();
+    }
+}
+
+/* Restore/Pop all the old VRs maintained in the cond_stack.  */
+
+void evrp_dom_walker::finalize_dom_walker ()
+{
+  while (!cond_stack.is_empty ())
+    {
+      tree var = cond_stack.last ().second;
+      pop_value_range (var);
+      cond_stack.pop ();
+    }
+}
+
+/* Main entry point for the early vrp pass which is a simplified non-iterative
+   version of VRP.  Value ranges discovered in early vrp will be used by ipa-vrp.  */
+
+static unsigned int
+execute_early_vrp ()
+{
+  basic_block bb;
+  edge e;
+  edge_iterator ei;
+
+  calculate_dominance_info (CDI_DOMINATORS);
+  vrp_initialize ();
+  FOR_EACH_BB_FN (bb, cfun)
+    {
+      FOR_EACH_EDGE (e, ei, bb->preds)
+	e->flags |= EDGE_EXECUTABLE;
+    }
+
+  evrp_dom_walker walker;
+  walker.walk (ENTRY_BLOCK_PTR_FOR_FN (cfun));
+  walker.finalize_dom_walker ();
+
+  vrp_finalize (false, false);
+  return 0;
+}
+
 /* Main entry point to VRP (Value Range Propagation).  This pass is
    loosely based on J. R. C. Patterson, ``Accurate Static Branch
    Prediction by Value Range Propagation,'' in SIGPLAN Conference on
@@ -10368,3 +10621,41 @@ make_pass_vrp (gcc::context *ctxt)
 {
   return new pass_vrp (ctxt);
 }
+
+namespace {
+
+const pass_data pass_data_early_vrp =
+{
+  GIMPLE_PASS, /* type */
+  "evrp", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_TREE_EARLY_VRP, /* tv_id */
+  PROP_ssa, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  ( TODO_cleanup_cfg | TODO_update_ssa | TODO_verify_all ),
+};
+
+class pass_early_vrp : public gimple_opt_pass
+{
+public:
+  pass_early_vrp (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_early_vrp, ctxt)
+    {}
+
+  /* opt_pass methods: */
+  opt_pass * clone () { return new pass_early_vrp (m_ctxt); }
+  virtual bool gate (function *) { return flag_tree_early_vrp != 0; }
+  virtual unsigned int execute (function *)
+    { return execute_early_vrp (); }
+
+}; // class pass_vrp
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_early_vrp (gcc::context *ctxt)
+{
+  return new pass_early_vrp (ctxt);
+}
+
-- 
1.9.1


^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Re-factor tree-vrp to factor out common code
  2016-07-15  4:44 ` [RFC][IPA-VRP] Re-factor tree-vrp to factor out common code kugan
  2016-07-15  4:47   ` [RFC][IPA-VRP] Add support for IPA VRP in ipa-cp/ipa-prop kugan
@ 2016-07-22 12:27   ` kugan
  2016-07-22 12:49     ` Richard Biener
  1 sibling, 1 reply; 67+ messages in thread
From: kugan @ 2016-07-22 12:27 UTC (permalink / raw)
  To: gcc-patches; +Cc: Richard Biener, Jan Hubicka, Martin Jambor

[-- Attachment #1: Type: text/plain, Size: 907 bytes --]

Hi,

Now that early vrp is moved as part of tree-vrp, there is only minimal 
interface tree-vrp should expose for ipa-vrp. However, I have not found 
the right place to place struct value_range (with GTY marker) and enum 
value_range_type.

enum value_range_type is needed in tree-ssanames.[h|c] and in all the 
places where get|set_range_info is used.

struct value_range is needed in ipa-prop.h, therefore all the places 
ipa-prop.h is included.

One option is to place it in tree-vrp.h and expose this to GTY 
infrastructure. Then include it in all the places we need any of these 
types. It is in lots of c files.

I have now placed both in tree.h. Even though that compiles, I am not 
convinced that is the right place.

I would appreciate comment/preferences in this regard. I am also 
attaching the current version of this patch for review. I will update it 
based on the comments.

Thanks,
Kugan




[-- Attachment #2: 0004-Refactor-vrp.patch --]
[-- Type: text/x-patch, Size: 7760 bytes --]

From 2e7d10923fefddafdeffc571e870508ac0ee193c Mon Sep 17 00:00:00 2001
From: Kugan Vivekanandarajah <kugan.vivekanandarajah@linaro.org>
Date: Tue, 21 Jun 2016 12:42:44 +1000
Subject: [PATCH 4/7] Refactor vrp

---
 gcc/tree-ssanames.h |  5 -----
 gcc/tree-vrp.c      | 50 ++++++++++++--------------------------------------
 gcc/tree-vrp.h      | 23 +++++++++++++++++++++++
 gcc/tree.h          | 31 +++++++++++++++++++++++++++++++
 4 files changed, 66 insertions(+), 43 deletions(-)
 create mode 100644 gcc/tree-vrp.h

diff --git a/gcc/tree-ssanames.h b/gcc/tree-ssanames.h
index c81b1a1..8e66ce6 100644
--- a/gcc/tree-ssanames.h
+++ b/gcc/tree-ssanames.h
@@ -62,11 +62,6 @@ struct GTY ((variable_size)) range_info_def {
 #define num_ssa_names (vec_safe_length (cfun->gimple_df->ssa_names))
 #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 };
-
 /* Sets the value range to SSA.  */
 extern void set_range_info (tree, enum value_range_type, const wide_int_ref &,
 			    const wide_int_ref &);
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index edaacf2..a318d39 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -59,32 +59,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "target.h"
 #include "case-cfn-macros.h"
 #include "alloc-pool.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;
-};
+#include "tree-vrp.h"
 
 #define VR_INITIALIZER { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL }
 
@@ -108,8 +83,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 *,
 						     bool *);
@@ -4605,7 +4578,7 @@ compare_range_with_value (enum tree_code comp, value_range *vr, tree val,
 
 /* Debugging dumps.  */
 
-void dump_value_range (FILE *, value_range *);
+void dump_value_range (FILE *, const value_range *);
 void debug_value_range (value_range *);
 void dump_all_value_ranges (FILE *);
 void debug_all_value_ranges (void);
@@ -4616,7 +4589,7 @@ void debug_vr_equiv (bitmap);
 /* Dump value range VR to FILE.  */
 
 void
-dump_value_range (FILE *file, value_range *vr)
+dump_value_range (FILE *file, const value_range *vr)
 {
   if (vr == NULL)
     fprintf (file, "[]");
@@ -8447,7 +8420,7 @@ intersect_ranges (enum value_range_type *vr0type,
 /* Intersect the two value-ranges *VR0 and *VR1 and store the result
    in *VR0.  This may not be the smallest possible such range.  */
 
-static void
+void
 vrp_intersect_ranges_1 (value_range *vr0, value_range *vr1)
 {
   value_range saved;
@@ -8499,7 +8472,7 @@ vrp_intersect_ranges_1 (value_range *vr0, value_range *vr1)
     bitmap_copy (vr0->equiv, vr1->equiv);
 }
 
-static void
+void
 vrp_intersect_ranges (value_range *vr0, value_range *vr1)
 {
   if (dump_file && (dump_flags & TDF_DETAILS))
@@ -8524,7 +8497,7 @@ vrp_intersect_ranges (value_range *vr0, value_range *vr1)
    may not be the smallest possible such range.  */
 
 static void
-vrp_meet_1 (value_range *vr0, value_range *vr1)
+vrp_meet_1 (value_range *vr0, const value_range *vr1)
 {
   value_range saved;
 
@@ -8596,8 +8569,8 @@ vrp_meet_1 (value_range *vr0, value_range *vr1)
     bitmap_clear (vr0->equiv);
 }
 
-static void
-vrp_meet (value_range *vr0, value_range *vr1)
+void
+vrp_meet (value_range *vr0, const value_range *vr1)
 {
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
@@ -10171,7 +10144,7 @@ finalize_jump_threads (void)
 /* Traverse all the blocks folding conditionals with known ranges.  */
 
 static void
-vrp_finalize (bool warn_array_bounds_p)
+vrp_finalize (bool jump_thread_p, bool warn_array_bounds_p)
 {
   size_t i;
 
@@ -10212,7 +10185,8 @@ vrp_finalize (bool warn_array_bounds_p)
 
   /* We must identify jump threading opportunities before we release
      the datastructures built by VRP.  */
-  identify_jump_threads ();
+  if (jump_thread_p)
+    identify_jump_threads ();
 
   /* Free allocated memory.  */
   free (vr_value);
@@ -10296,7 +10270,7 @@ execute_vrp (bool warn_array_bounds_p)
 
   vrp_initialize ();
   ssa_propagate (vrp_visit_stmt, vrp_visit_phi_node);
-  vrp_finalize (warn_array_bounds_p);
+  vrp_finalize (true, warn_array_bounds_p);
 
   free_numbers_of_iterations_estimates (cfun);
 
diff --git a/gcc/tree-vrp.h b/gcc/tree-vrp.h
new file mode 100644
index 0000000..38aacf5
--- /dev/null
+++ b/gcc/tree-vrp.h
@@ -0,0 +1,23 @@
+/* Support routines for Value Range Propagation (VRP).
+   Copyright (C) Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+extern void vrp_intersect_ranges (value_range *vr0, value_range *vr1);
+extern void vrp_meet (value_range *vr0, const value_range *vr1);
+extern void dump_value_range (FILE *, const value_range *);
+
diff --git a/gcc/tree.h b/gcc/tree.h
index 90413fc..8fc4f4f 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -230,6 +230,37 @@ as_internal_fn (combined_fn code)
 
 #define TREE_CODE_LENGTH(CODE)	tree_code_length[(int) (CODE)]
 
+/* 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;
+};
+
 
 /* Helper macros for math builtins.  */
 
-- 
1.9.1


^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Re-factor tree-vrp to factor out common code
  2016-07-22 12:27   ` [RFC][IPA-VRP] Re-factor tree-vrp to factor out common code kugan
@ 2016-07-22 12:49     ` Richard Biener
  2016-07-22 14:34       ` kugan
  0 siblings, 1 reply; 67+ messages in thread
From: Richard Biener @ 2016-07-22 12:49 UTC (permalink / raw)
  To: kugan; +Cc: gcc-patches, Jan Hubicka, Martin Jambor

On Fri, Jul 22, 2016 at 2:27 PM, kugan
<kugan.vivekanandarajah@linaro.org> wrote:
> Hi,
>
> Now that early vrp is moved as part of tree-vrp, there is only minimal
> interface tree-vrp should expose for ipa-vrp. However, I have not found the
> right place to place struct value_range (with GTY marker) and enum
> value_range_type.
>
> enum value_range_type is needed in tree-ssanames.[h|c] and in all the places
> where get|set_range_info is used.
>
> struct value_range is needed in ipa-prop.h, therefore all the places
> ipa-prop.h is included.
>
> One option is to place it in tree-vrp.h and expose this to GTY
> infrastructure. Then include it in all the places we need any of these
> types. It is in lots of c files.
>
> I have now placed both in tree.h. Even though that compiles, I am not
> convinced that is the right place.

I'm convinced it is not ;)

As we had value_range_type in tree-ssanames.h why not put value_range there?

Or simply put value_range into tree-vrp.h and leave value_range_type
where it is.

You no longer export vrp_finalize so no need to change it.

> I would appreciate comment/preferences in this regard. I am also attaching
> the current version of this patch for review. I will update it based on the
> comments.

Richard.

> Thanks,
> Kugan
>
>
>

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Re-factor tree-vrp to factor out common code
  2016-07-22 12:49     ` Richard Biener
@ 2016-07-22 14:34       ` kugan
  2016-07-23 10:12         ` kugan
  0 siblings, 1 reply; 67+ messages in thread
From: kugan @ 2016-07-22 14:34 UTC (permalink / raw)
  To: Richard Biener; +Cc: gcc-patches, Jan Hubicka, Martin Jambor

[-- Attachment #1: Type: text/plain, Size: 1651 bytes --]

Hi Richard,

Thanks for the review.

On 22/07/16 22:49, Richard Biener wrote:
> On Fri, Jul 22, 2016 at 2:27 PM, kugan
> <kugan.vivekanandarajah@linaro.org> wrote:
>> Hi,
>>
>> Now that early vrp is moved as part of tree-vrp, there is only minimal
>> interface tree-vrp should expose for ipa-vrp. However, I have not found the
>> right place to place struct value_range (with GTY marker) and enum
>> value_range_type.
>>
>> enum value_range_type is needed in tree-ssanames.[h|c] and in all the places
>> where get|set_range_info is used.
>>
>> struct value_range is needed in ipa-prop.h, therefore all the places
>> ipa-prop.h is included.
>>
>> One option is to place it in tree-vrp.h and expose this to GTY
>> infrastructure. Then include it in all the places we need any of these
>> types. It is in lots of c files.
>>
>> I have now placed both in tree.h. Even though that compiles, I am not
>> convinced that is the right place.
>
> I'm convinced it is not ;)

I totally agree. I just kept it their for the time being.

>
> As we had value_range_type in tree-ssanames.h why not put value_range there?
>
For IPA_VRP, we now need value_range used in ipa-prop.h (in ipa-vrp 
patch). Based on this, attached patch now adds struct value_range to 
tree-ssanames.h and fixes the header files. Please note that I also had 
to add other headers in few places due to the dependency. Are you OK 
with this ?

> Or simply put value_range into tree-vrp.h and leave value_range_type
> where it is.

In this case, we will have to add tree-vrp.h and tree-ssanames.h in 
those places.
>
> You no longer export vrp_finalize so no need to change it.

Thanks,
Kugan


[-- Attachment #2: 0004-Refactor-vrp.patch --]
[-- Type: text/x-patch, Size: 12625 bytes --]

From f75f2f836238e2e65615bec7ea2ce3a31257e204 Mon Sep 17 00:00:00 2001
From: Kugan Vivekanandarajah <kugan.vivekanandarajah@linaro.org>
Date: Tue, 21 Jun 2016 12:42:44 +1000
Subject: [PATCH 4/7] Refactor vrp

---
 gcc/cgraph.c               |  2 ++
 gcc/cgraphunit.c           |  1 +
 gcc/ipa-cp.c               |  3 +++
 gcc/ipa-devirt.c           |  2 ++
 gcc/ipa-inline-transform.c |  3 +++
 gcc/ipa-inline.c           |  2 ++
 gcc/ipa-profile.c          |  2 ++
 gcc/ipa-utils.c            |  2 ++
 gcc/ipa.c                  |  1 +
 gcc/lto/lto-partition.c    |  1 +
 gcc/lto/lto.c              |  2 ++
 gcc/toplev.c               |  2 ++
 gcc/trans-mem.c            |  1 +
 gcc/tree-ssanames.h        | 29 ++++++++++++++++++++++++++-
 gcc/tree-vrp.c             | 50 +++++++++++-----------------------------------
 gcc/tree-vrp.h             | 23 +++++++++++++++++++++
 16 files changed, 87 insertions(+), 39 deletions(-)
 create mode 100644 gcc/tree-vrp.h

diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index e256dd0..01fbf5e 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -49,6 +49,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "value-prof.h"
 #include "ipa-utils.h"
 #include "symbol-summary.h"
+#include "stringpool.h"
+#include "tree-ssanames.h"
 #include "ipa-prop.h"
 #include "ipa-inline.h"
 #include "cfgloop.h"
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index 4bfcad7..bf85356 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -190,6 +190,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "toplev.h"
 #include "debug.h"
 #include "symbol-summary.h"
+#include "tree-ssanames.h"
 #include "ipa-prop.h"
 #include "gimple-pretty-print.h"
 #include "plugin.h"
diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
index 4b7f6bb..7e08a31 100644
--- a/gcc/ipa-cp.c
+++ b/gcc/ipa-cp.c
@@ -114,6 +114,9 @@ along with GCC; see the file COPYING3.  If not see
 #include "fold-const.h"
 #include "gimple-fold.h"
 #include "symbol-summary.h"
+#include "tree-ssa-alias.h"
+#include "stringpool.h"
+#include "tree-ssanames.h"
 #include "ipa-prop.h"
 #include "tree-pretty-print.h"
 #include "tree-inline.h"
diff --git a/gcc/ipa-devirt.c b/gcc/ipa-devirt.c
index 2cf018b..cdc539c 100644
--- a/gcc/ipa-devirt.c
+++ b/gcc/ipa-devirt.c
@@ -122,6 +122,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-utils.h"
 #include "gimple-fold.h"
 #include "symbol-summary.h"
+#include "stringpool.h"
+#include "tree-ssanames.h"
 #include "ipa-prop.h"
 #include "ipa-inline.h"
 #include "demangle.h"
diff --git a/gcc/ipa-inline-transform.c b/gcc/ipa-inline-transform.c
index f6b7d41..ea7c9c7 100644
--- a/gcc/ipa-inline-transform.c
+++ b/gcc/ipa-inline-transform.c
@@ -39,6 +39,9 @@ along with GCC; see the file COPYING3.  If not see
 #include "cgraph.h"
 #include "tree-cfg.h"
 #include "symbol-summary.h"
+#include "tree-ssa-alias.h"
+#include "stringpool.h"
+#include "tree-ssanames.h"
 #include "ipa-prop.h"
 #include "ipa-inline.h"
 #include "tree-inline.h"
diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
index 5c9366a..3eac298 100644
--- a/gcc/ipa-inline.c
+++ b/gcc/ipa-inline.c
@@ -108,6 +108,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "params.h"
 #include "profile.h"
 #include "symbol-summary.h"
+#include "stringpool.h"
+#include "tree-ssanames.h"
 #include "ipa-prop.h"
 #include "ipa-inline.h"
 #include "ipa-utils.h"
diff --git a/gcc/ipa-profile.c b/gcc/ipa-profile.c
index da17bcd..e43c3c9 100644
--- a/gcc/ipa-profile.c
+++ b/gcc/ipa-profile.c
@@ -62,6 +62,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "value-prof.h"
 #include "tree-inline.h"
 #include "symbol-summary.h"
+#include "stringpool.h"
+#include "tree-ssanames.h"
 #include "ipa-prop.h"
 #include "ipa-inline.h"
 
diff --git a/gcc/ipa-utils.c b/gcc/ipa-utils.c
index 5eb7d5f..df9f178 100644
--- a/gcc/ipa-utils.c
+++ b/gcc/ipa-utils.c
@@ -32,6 +32,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "splay-tree.h"
 #include "ipa-utils.h"
 #include "symbol-summary.h"
+#include "stringpool.h"
+#include "tree-ssanames.h"
 #include "ipa-prop.h"
 #include "ipa-inline.h"
 
diff --git a/gcc/ipa.c b/gcc/ipa.c
index 6722d3b..b8c55c0 100644
--- a/gcc/ipa.c
+++ b/gcc/ipa.c
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-iterator.h"
 #include "ipa-utils.h"
 #include "symbol-summary.h"
+#include "tree-ssanames.h"
 #include "ipa-prop.h"
 #include "ipa-inline.h"
 #include "dbgcnt.h"
diff --git a/gcc/lto/lto-partition.c b/gcc/lto/lto-partition.c
index 453343a..ca0fa24 100644
--- a/gcc/lto/lto-partition.c
+++ b/gcc/lto/lto-partition.c
@@ -31,6 +31,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "lto-streamer.h"
 #include "params.h"
 #include "symbol-summary.h"
+#include "tree-ssanames.h"
 #include "ipa-prop.h"
 #include "ipa-inline.h"
 #include "lto-partition.h"
diff --git a/gcc/lto/lto.c b/gcc/lto/lto.c
index af735cb..ea81931 100644
--- a/gcc/lto/lto.c
+++ b/gcc/lto/lto.c
@@ -36,6 +36,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "toplev.h"
 #include "stor-layout.h"
 #include "symbol-summary.h"
+#include "stringpool.h"
+#include "tree-ssanames.h"
 #include "ipa-prop.h"
 #include "common.h"
 #include "debug.h"
diff --git a/gcc/toplev.c b/gcc/toplev.c
index f51d2cb..4c973f0 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -71,6 +71,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "dwarf2out.h"
 #include "ipa-reference.h"
 #include "symbol-summary.h"
+#include "stringpool.h"
+#include "tree-ssanames.h"
 #include "ipa-prop.h"
 #include "gcse.h"
 #include "tree-chkp.h"
diff --git a/gcc/trans-mem.c b/gcc/trans-mem.c
index 2a6e101..3137f80 100644
--- a/gcc/trans-mem.c
+++ b/gcc/trans-mem.c
@@ -49,6 +49,7 @@
 #include "params.h"
 #include "langhooks.h"
 #include "cfgloop.h"
+#include "tree-ssanames.h"
 #include "tree-ssa-address.h"
 
 
diff --git a/gcc/tree-ssanames.h b/gcc/tree-ssanames.h
index c81b1a1..d4a8cc3 100644
--- a/gcc/tree-ssanames.h
+++ b/gcc/tree-ssanames.h
@@ -65,7 +65,34 @@ struct GTY ((variable_size)) range_info_def {
 
 /* 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 };
+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;
+};
 
 /* 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 edaacf2..a318d39 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -59,32 +59,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "target.h"
 #include "case-cfn-macros.h"
 #include "alloc-pool.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;
-};
+#include "tree-vrp.h"
 
 #define VR_INITIALIZER { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL }
 
@@ -108,8 +83,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 *,
 						     bool *);
@@ -4605,7 +4578,7 @@ compare_range_with_value (enum tree_code comp, value_range *vr, tree val,
 
 /* Debugging dumps.  */
 
-void dump_value_range (FILE *, value_range *);
+void dump_value_range (FILE *, const value_range *);
 void debug_value_range (value_range *);
 void dump_all_value_ranges (FILE *);
 void debug_all_value_ranges (void);
@@ -4616,7 +4589,7 @@ void debug_vr_equiv (bitmap);
 /* Dump value range VR to FILE.  */
 
 void
-dump_value_range (FILE *file, value_range *vr)
+dump_value_range (FILE *file, const value_range *vr)
 {
   if (vr == NULL)
     fprintf (file, "[]");
@@ -8447,7 +8420,7 @@ intersect_ranges (enum value_range_type *vr0type,
 /* Intersect the two value-ranges *VR0 and *VR1 and store the result
    in *VR0.  This may not be the smallest possible such range.  */
 
-static void
+void
 vrp_intersect_ranges_1 (value_range *vr0, value_range *vr1)
 {
   value_range saved;
@@ -8499,7 +8472,7 @@ vrp_intersect_ranges_1 (value_range *vr0, value_range *vr1)
     bitmap_copy (vr0->equiv, vr1->equiv);
 }
 
-static void
+void
 vrp_intersect_ranges (value_range *vr0, value_range *vr1)
 {
   if (dump_file && (dump_flags & TDF_DETAILS))
@@ -8524,7 +8497,7 @@ vrp_intersect_ranges (value_range *vr0, value_range *vr1)
    may not be the smallest possible such range.  */
 
 static void
-vrp_meet_1 (value_range *vr0, value_range *vr1)
+vrp_meet_1 (value_range *vr0, const value_range *vr1)
 {
   value_range saved;
 
@@ -8596,8 +8569,8 @@ vrp_meet_1 (value_range *vr0, value_range *vr1)
     bitmap_clear (vr0->equiv);
 }
 
-static void
-vrp_meet (value_range *vr0, value_range *vr1)
+void
+vrp_meet (value_range *vr0, const value_range *vr1)
 {
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
@@ -10171,7 +10144,7 @@ finalize_jump_threads (void)
 /* Traverse all the blocks folding conditionals with known ranges.  */
 
 static void
-vrp_finalize (bool warn_array_bounds_p)
+vrp_finalize (bool jump_thread_p, bool warn_array_bounds_p)
 {
   size_t i;
 
@@ -10212,7 +10185,8 @@ vrp_finalize (bool warn_array_bounds_p)
 
   /* We must identify jump threading opportunities before we release
      the datastructures built by VRP.  */
-  identify_jump_threads ();
+  if (jump_thread_p)
+    identify_jump_threads ();
 
   /* Free allocated memory.  */
   free (vr_value);
@@ -10296,7 +10270,7 @@ execute_vrp (bool warn_array_bounds_p)
 
   vrp_initialize ();
   ssa_propagate (vrp_visit_stmt, vrp_visit_phi_node);
-  vrp_finalize (warn_array_bounds_p);
+  vrp_finalize (true, warn_array_bounds_p);
 
   free_numbers_of_iterations_estimates (cfun);
 
diff --git a/gcc/tree-vrp.h b/gcc/tree-vrp.h
new file mode 100644
index 0000000..38aacf5
--- /dev/null
+++ b/gcc/tree-vrp.h
@@ -0,0 +1,23 @@
+/* Support routines for Value Range Propagation (VRP).
+   Copyright (C) Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+extern void vrp_intersect_ranges (value_range *vr0, value_range *vr1);
+extern void vrp_meet (value_range *vr0, const value_range *vr1);
+extern void dump_value_range (FILE *, const value_range *);
+
-- 
1.9.1



^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Re-factor tree-vrp to factor out common code
  2016-07-22 14:34       ` kugan
@ 2016-07-23 10:12         ` kugan
  2016-08-16  8:09           ` kugan
  0 siblings, 1 reply; 67+ messages in thread
From: kugan @ 2016-07-23 10:12 UTC (permalink / raw)
  To: Richard Biener; +Cc: gcc-patches, Jan Hubicka, Martin Jambor

[-- Attachment #1: Type: text/plain, Size: 587 bytes --]

Hi Richard,

>> As we had value_range_type in tree-ssanames.h why not put value_range there?
>>
> For IPA_VRP, we now need value_range used in ipa-prop.h (in ipa-vrp
> patch). Based on this, attached patch now adds struct value_range to
> tree-ssanames.h and fixes the header files. Please note that I also had
> to add other headers in few places due to the dependency. Are you OK
> with this ?
Here is alternate patch where we keep struct value_range and enum 
value_range_type to tree-vrp.h. May be it is a better approach? Please 
let me know what is your preference.

Thanks,
Kugan

[-- Attachment #2: 0004-Refactor-vrp.patch --]
[-- Type: text/x-patch, Size: 17318 bytes --]

From 37129f66a59c435afc301ecce1ba9340fdfc9eb2 Mon Sep 17 00:00:00 2001
From: Kugan Vivekanandarajah <kugan.vivekanandarajah@linaro.org>
Date: Tue, 21 Jun 2016 12:42:44 +1000
Subject: [PATCH 4/7] Refactor vrp

---
 gcc/Makefile.in            |  1 +
 gcc/asan.c                 |  1 +
 gcc/builtins.c             |  1 +
 gcc/cgraph.c               |  1 +
 gcc/cgraphunit.c           |  1 +
 gcc/fold-const.c           |  1 +
 gcc/gengtype.c             |  2 +-
 gcc/gimple-builder.c       |  1 +
 gcc/gimple-laddress.c      |  1 +
 gcc/hsa-gen.c              |  1 +
 gcc/internal-fn.c          |  1 +
 gcc/ipa-cp.c               |  1 +
 gcc/ipa-devirt.c           |  1 +
 gcc/ipa-inline-transform.c |  1 +
 gcc/ipa-inline.c           |  1 +
 gcc/ipa-profile.c          |  1 +
 gcc/ipa-utils.c            |  1 +
 gcc/ipa.c                  |  1 +
 gcc/lto/lto-partition.c    |  1 +
 gcc/lto/lto.c              |  1 +
 gcc/ssa.h                  |  1 +
 gcc/targhooks.c            |  1 +
 gcc/toplev.c               |  1 +
 gcc/tree-ssa-address.c     |  1 +
 gcc/tree-ssanames.h        |  5 -----
 gcc/tree-vrp.c             | 50 +++++++++++-------------------------------
 gcc/tree-vrp.h             | 54 ++++++++++++++++++++++++++++++++++++++++++++++
 27 files changed, 90 insertions(+), 44 deletions(-)
 create mode 100644 gcc/tree-vrp.h

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 776f6d7..36ceb76 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -2424,6 +2424,7 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
   $(srcdir)/tree-phinodes.c \
   $(srcdir)/tree-ssa-alias.h \
   $(srcdir)/tree-ssanames.h \
+  $(srcdir)/tree-vrp.h \
   $(srcdir)/ipa-prop.h \
   $(srcdir)/trans-mem.c \
   $(srcdir)/lto-streamer.h \
diff --git a/gcc/asan.c b/gcc/asan.c
index 71095fb..6451c85 100644
--- a/gcc/asan.c
+++ b/gcc/asan.c
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-pass.h"
 #include "tm_p.h"
 #include "stringpool.h"
+#include "tree-vrp.h"
 #include "tree-ssanames.h"
 #include "optabs.h"
 #include "emit-rtl.h"
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 5d234a5..a5c36f4 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "predict.h"
 #include "tm_p.h"
 #include "stringpool.h"
+#include "tree-vrp.h"
 #include "tree-ssanames.h"
 #include "expmed.h"
 #include "optabs.h"
diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index e256dd0..3a5473a 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -49,6 +49,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "value-prof.h"
 #include "ipa-utils.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "ipa-inline.h"
 #include "cfgloop.h"
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index 4bfcad7..4fcc368 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -190,6 +190,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "toplev.h"
 #include "debug.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "gimple-pretty-print.h"
 #include "plugin.h"
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 3b9500d..2068f8a 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -75,6 +75,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "md5.h"
 #include "case-cfn-macros.h"
 #include "stringpool.h"
+#include "tree-vrp.h"
 #include "tree-ssanames.h"
 #include "selftest.h"
 
diff --git a/gcc/gengtype.c b/gcc/gengtype.c
index 5479b8f..97fe7ee 100644
--- a/gcc/gengtype.c
+++ b/gcc/gengtype.c
@@ -1712,7 +1712,7 @@ open_base_files (void)
       "explow.h", "calls.h", "cilk.h", "emit-rtl.h", "varasm.h", "stmt.h",
       "expr.h", "alloc-pool.h", "cselib.h", "insn-addr.h", "optabs.h",
       "libfuncs.h", "debug.h", "internal-fn.h", "gimple-fold.h", "tree-eh.h",
-      "gimple-iterator.h", "gimple-ssa.h", "tree-cfg.h",
+      "gimple-iterator.h", "gimple-ssa.h", "tree-cfg.h", "tree-vrp.h",
       "tree-phinodes.h", "ssa-iterators.h", "stringpool.h", "tree-ssanames.h",
       "tree-ssa-loop.h", "tree-ssa-loop-ivopts.h", "tree-ssa-loop-manip.h",
       "tree-ssa-loop-niter.h", "tree-into-ssa.h", "tree-dfa.h", 
diff --git a/gcc/gimple-builder.c b/gcc/gimple-builder.c
index f124554..4fb21e4 100644
--- a/gcc/gimple-builder.c
+++ b/gcc/gimple-builder.c
@@ -24,6 +24,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree.h"
 #include "gimple.h"
 #include "stringpool.h"
+#include "tree-vrp.h"
 #include "tree-ssanames.h"
 
 
diff --git a/gcc/gimple-laddress.c b/gcc/gimple-laddress.c
index 4560b862..04844b9 100644
--- a/gcc/gimple-laddress.c
+++ b/gcc/gimple-laddress.c
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "symtab.h"
 #include "tree.h"
 #include "stringpool.h"
+#include "tree-vrp.h"
 #include "tree-ssanames.h"
 #include "fold-const.h"
 #include "gimple-expr.h"
diff --git a/gcc/hsa-gen.c b/gcc/hsa-gen.c
index cf7d434..237de23 100644
--- a/gcc/hsa-gen.c
+++ b/gcc/hsa-gen.c
@@ -42,6 +42,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-ssa.h"
 #include "tree-phinodes.h"
 #include "stringpool.h"
+#include "tree-vrp.h"
 #include "tree-ssanames.h"
 #include "tree-dfa.h"
 #include "ssa-iterators.h"
diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c
index c867ddc..950c9dc 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -27,6 +27,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple.h"
 #include "predict.h"
 #include "stringpool.h"
+#include "tree-vrp.h"
 #include "tree-ssanames.h"
 #include "expmed.h"
 #include "optabs.h"
diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
index 4b7f6bb..17f847a 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"
diff --git a/gcc/ipa-devirt.c b/gcc/ipa-devirt.c
index 2cf018b..62a08f8 100644
--- a/gcc/ipa-devirt.c
+++ b/gcc/ipa-devirt.c
@@ -122,6 +122,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-utils.h"
 #include "gimple-fold.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "ipa-inline.h"
 #include "demangle.h"
diff --git a/gcc/ipa-inline-transform.c b/gcc/ipa-inline-transform.c
index f6b7d41..213748a 100644
--- a/gcc/ipa-inline-transform.c
+++ b/gcc/ipa-inline-transform.c
@@ -39,6 +39,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "cgraph.h"
 #include "tree-cfg.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "ipa-inline.h"
 #include "tree-inline.h"
diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
index 5c9366a..82bb94f 100644
--- a/gcc/ipa-inline.c
+++ b/gcc/ipa-inline.c
@@ -108,6 +108,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "params.h"
 #include "profile.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "ipa-inline.h"
 #include "ipa-utils.h"
diff --git a/gcc/ipa-profile.c b/gcc/ipa-profile.c
index da17bcd..e87615a 100644
--- a/gcc/ipa-profile.c
+++ b/gcc/ipa-profile.c
@@ -62,6 +62,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "value-prof.h"
 #include "tree-inline.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "ipa-inline.h"
 
diff --git a/gcc/ipa-utils.c b/gcc/ipa-utils.c
index 5eb7d5f..61d8dd1 100644
--- a/gcc/ipa-utils.c
+++ b/gcc/ipa-utils.c
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "splay-tree.h"
 #include "ipa-utils.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "ipa-inline.h"
 
diff --git a/gcc/ipa.c b/gcc/ipa.c
index 6722d3b..fe0c84b 100644
--- a/gcc/ipa.c
+++ b/gcc/ipa.c
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-iterator.h"
 #include "ipa-utils.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "ipa-inline.h"
 #include "dbgcnt.h"
diff --git a/gcc/lto/lto-partition.c b/gcc/lto/lto-partition.c
index 453343a..b52d175 100644
--- a/gcc/lto/lto-partition.c
+++ b/gcc/lto/lto-partition.c
@@ -31,6 +31,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "lto-streamer.h"
 #include "params.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "ipa-inline.h"
 #include "lto-partition.h"
diff --git a/gcc/lto/lto.c b/gcc/lto/lto.c
index af735cb..fedf668 100644
--- a/gcc/lto/lto.c
+++ b/gcc/lto/lto.c
@@ -36,6 +36,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "toplev.h"
 #include "stor-layout.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "common.h"
 #include "debug.h"
diff --git a/gcc/ssa.h b/gcc/ssa.h
index 40bc1c7..0ec1bf0 100644
--- a/gcc/ssa.h
+++ b/gcc/ssa.h
@@ -25,6 +25,7 @@ along with GCC; see the file COPYING3.  If not see
 
 #include "stringpool.h"
 #include "gimple-ssa.h"
+#include "tree-vrp.h"
 #include "tree-ssanames.h"
 #include "tree-phinodes.h"
 #include "ssa-iterators.h" 
diff --git a/gcc/targhooks.c b/gcc/targhooks.c
index 3e089e7..1d9c00a 100644
--- a/gcc/targhooks.c
+++ b/gcc/targhooks.c
@@ -57,6 +57,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-expr.h"
 #include "tm_p.h"
 #include "stringpool.h"
+#include "tree-vrp.h"
 #include "tree-ssanames.h"
 #include "optabs.h"
 #include "regs.h"
diff --git a/gcc/toplev.c b/gcc/toplev.c
index f51d2cb..c9d6ae1 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -71,6 +71,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "dwarf2out.h"
 #include "ipa-reference.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "gcse.h"
 #include "tree-chkp.h"
diff --git a/gcc/tree-ssa-address.c b/gcc/tree-ssa-address.c
index b04545c..30f0c32 100644
--- a/gcc/tree-ssa-address.c
+++ b/gcc/tree-ssa-address.c
@@ -29,6 +29,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree.h"
 #include "gimple.h"
 #include "stringpool.h"
+#include "tree-vrp.h"
 #include "tree-ssanames.h"
 #include "expmed.h"
 #include "insn-config.h"
diff --git a/gcc/tree-ssanames.h b/gcc/tree-ssanames.h
index c81b1a1..8e66ce6 100644
--- a/gcc/tree-ssanames.h
+++ b/gcc/tree-ssanames.h
@@ -62,11 +62,6 @@ struct GTY ((variable_size)) range_info_def {
 #define num_ssa_names (vec_safe_length (cfun->gimple_df->ssa_names))
 #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 };
-
 /* Sets the value range to SSA.  */
 extern void set_range_info (tree, enum value_range_type, const wide_int_ref &,
 			    const wide_int_ref &);
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index edaacf2..83579e3 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -59,32 +59,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "target.h"
 #include "case-cfn-macros.h"
 #include "alloc-pool.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;
-};
+#include "domwalk.h"
 
 #define VR_INITIALIZER { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL }
 
@@ -108,8 +83,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 *,
 						     bool *);
@@ -4605,7 +4578,7 @@ compare_range_with_value (enum tree_code comp, value_range *vr, tree val,
 
 /* Debugging dumps.  */
 
-void dump_value_range (FILE *, value_range *);
+void dump_value_range (FILE *, const value_range *);
 void debug_value_range (value_range *);
 void dump_all_value_ranges (FILE *);
 void debug_all_value_ranges (void);
@@ -4616,7 +4589,7 @@ void debug_vr_equiv (bitmap);
 /* Dump value range VR to FILE.  */
 
 void
-dump_value_range (FILE *file, value_range *vr)
+dump_value_range (FILE *file, const value_range *vr)
 {
   if (vr == NULL)
     fprintf (file, "[]");
@@ -8447,7 +8420,7 @@ intersect_ranges (enum value_range_type *vr0type,
 /* Intersect the two value-ranges *VR0 and *VR1 and store the result
    in *VR0.  This may not be the smallest possible such range.  */
 
-static void
+void
 vrp_intersect_ranges_1 (value_range *vr0, value_range *vr1)
 {
   value_range saved;
@@ -8499,7 +8472,7 @@ vrp_intersect_ranges_1 (value_range *vr0, value_range *vr1)
     bitmap_copy (vr0->equiv, vr1->equiv);
 }
 
-static void
+void
 vrp_intersect_ranges (value_range *vr0, value_range *vr1)
 {
   if (dump_file && (dump_flags & TDF_DETAILS))
@@ -8524,7 +8497,7 @@ vrp_intersect_ranges (value_range *vr0, value_range *vr1)
    may not be the smallest possible such range.  */
 
 static void
-vrp_meet_1 (value_range *vr0, value_range *vr1)
+vrp_meet_1 (value_range *vr0, const value_range *vr1)
 {
   value_range saved;
 
@@ -8596,8 +8569,8 @@ vrp_meet_1 (value_range *vr0, value_range *vr1)
     bitmap_clear (vr0->equiv);
 }
 
-static void
-vrp_meet (value_range *vr0, value_range *vr1)
+void
+vrp_meet (value_range *vr0, const value_range *vr1)
 {
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
@@ -10171,7 +10144,7 @@ finalize_jump_threads (void)
 /* Traverse all the blocks folding conditionals with known ranges.  */
 
 static void
-vrp_finalize (bool warn_array_bounds_p)
+vrp_finalize (bool jump_thread_p, bool warn_array_bounds_p)
 {
   size_t i;
 
@@ -10212,7 +10185,8 @@ vrp_finalize (bool warn_array_bounds_p)
 
   /* We must identify jump threading opportunities before we release
      the datastructures built by VRP.  */
-  identify_jump_threads ();
+  if (jump_thread_p)
+    identify_jump_threads ();
 
   /* Free allocated memory.  */
   free (vr_value);
@@ -10296,7 +10270,7 @@ execute_vrp (bool warn_array_bounds_p)
 
   vrp_initialize ();
   ssa_propagate (vrp_visit_stmt, vrp_visit_phi_node);
-  vrp_finalize (warn_array_bounds_p);
+  vrp_finalize (true, warn_array_bounds_p);
 
   free_numbers_of_iterations_estimates (cfun);
 
diff --git a/gcc/tree-vrp.h b/gcc/tree-vrp.h
new file mode 100644
index 0000000..e514c1e
--- /dev/null
+++ b/gcc/tree-vrp.h
@@ -0,0 +1,54 @@
+/* Support routines for Value Range Propagation (VRP).
+   Copyright (C) Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+/* 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;
+};
+
+extern void vrp_intersect_ranges (value_range *vr0, value_range *vr1);
+extern void vrp_meet (value_range *vr0, const value_range *vr1);
+extern void dump_value_range (FILE *, const value_range *);
+
-- 
1.9.1


^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Disable setting param of __builtin_constant_p to null
  2016-07-15  8:43   ` Jan Hubicka
@ 2016-07-25  6:59     ` kugan
  2016-07-25 10:02       ` Richard Biener
  0 siblings, 1 reply; 67+ messages in thread
From: kugan @ 2016-07-25  6:59 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: gcc-patches, Richard Biener, Martin Jambor

[-- Attachment #1: Type: text/plain, Size: 854 bytes --]

Hi,

>> diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
>> index ecfab1f..23c12b5 100644
>> --- a/gcc/tree-vrp.c
>> +++ b/gcc/tree-vrp.c
>> @@ -3759,8 +3759,10 @@ extract_range_basic (value_range *vr, gimple *stmt)
>>  	      && SSA_NAME_IS_DEFAULT_DEF (arg)
>>  	      && TREE_CODE (SSA_NAME_VAR (arg)) == PARM_DECL)
>>  	    {
>> +#if 0
>>  	      set_value_range_to_null (vr, type);
>>  	      return;
>> +#endif
>
> It is not cleanest either, but better to test cfun->after_inlining

Thanks. Here is the patch which does this. Bootstrapped and regression 
tested with the rest of the patches in the series. Is this OK for trunk?

Thanks,
Kugan

gcc/ChangeLog:

2016-07-25  Kugan Vivekanandarajah  <kuganv@linaro.org>

	* tree-vrp.c (extract_range_basic): Check cfun->after_inlining before
	folding call to __builtin_constant_p with parameters to false.

[-- Attachment #2: 0002-Prevent-setting-__builtin_constant_p-of-param-to-nul.patch --]
[-- Type: text/x-patch, Size: 885 bytes --]

From 4805ea975de0fd3b183b27324df1caa7ff29f887 Mon Sep 17 00:00:00 2001
From: Kugan Vivekanandarajah <kugan.vivekanandarajah@linaro.org>
Date: Sat, 25 Jun 2016 11:52:57 +1000
Subject: [PATCH 2/7] Prevent setting __builtin_constant_p of param to null
 before inlining in Early VRP

---
 gcc/tree-vrp.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index bdfc1b6..edaacf2 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -3763,7 +3763,8 @@ extract_range_basic (value_range *vr, gimple *stmt)
 	  arg = gimple_call_arg (stmt, 0);
 	  if (TREE_CODE (arg) == SSA_NAME
 	      && SSA_NAME_IS_DEFAULT_DEF (arg)
-	      && TREE_CODE (SSA_NAME_VAR (arg)) == PARM_DECL)
+	      && TREE_CODE (SSA_NAME_VAR (arg)) == PARM_DECL
+	      && cfun->after_inlining)
 	    {
 	      set_value_range_to_null (vr, type);
 	      return;
-- 
1.9.1


^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Disable setting param of __builtin_constant_p to null
  2016-07-25  6:59     ` kugan
@ 2016-07-25 10:02       ` Richard Biener
  0 siblings, 0 replies; 67+ messages in thread
From: Richard Biener @ 2016-07-25 10:02 UTC (permalink / raw)
  To: kugan; +Cc: Jan Hubicka, gcc-patches, Martin Jambor

On Mon, Jul 25, 2016 at 8:59 AM, kugan
<kugan.vivekanandarajah@linaro.org> wrote:
> Hi,
>
>>> diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
>>> index ecfab1f..23c12b5 100644
>>> --- a/gcc/tree-vrp.c
>>> +++ b/gcc/tree-vrp.c
>>> @@ -3759,8 +3759,10 @@ extract_range_basic (value_range *vr, gimple
>>> *stmt)
>>>               && SSA_NAME_IS_DEFAULT_DEF (arg)
>>>               && TREE_CODE (SSA_NAME_VAR (arg)) == PARM_DECL)
>>>             {
>>> +#if 0
>>>               set_value_range_to_null (vr, type);
>>>               return;
>>> +#endif
>>
>>
>> It is not cleanest either, but better to test cfun->after_inlining
>
>
> Thanks. Here is the patch which does this. Bootstrapped and regression
> tested with the rest of the patches in the series. Is this OK for trunk?

Ok.

Richard.

> Thanks,
> Kugan
>
> gcc/ChangeLog:
>
> 2016-07-25  Kugan Vivekanandarajah  <kuganv@linaro.org>
>
>         * tree-vrp.c (extract_range_basic): Check cfun->after_inlining
> before
>         folding call to __builtin_constant_p with parameters to false.

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Early VRP Implementation
  2016-07-22 12:10             ` kugan
@ 2016-07-25 11:18               ` Richard Biener
  2016-07-26 12:27                 ` kugan
  0 siblings, 1 reply; 67+ messages in thread
From: Richard Biener @ 2016-07-25 11:18 UTC (permalink / raw)
  To: kugan; +Cc: Andrew Pinski, gcc-patches, Jan Hubicka, Martin Jambor

On Fri, Jul 22, 2016 at 2:10 PM, kugan
<kugan.vivekanandarajah@linaro.org> wrote:
> Hi Richard,
>
> Thanks for the review.
>
> On 18/07/16 21:51, Richard Biener wrote:
>>
>> On Fri, Jul 15, 2016 at 9:33 AM, kugan
>> <kugan.vivekanandarajah@linaro.org> wrote:
>>>
>>> Hi Andrew,
>>>
>>> On 15/07/16 17:28, Andrew Pinski wrote:
>>>>
>>>>
>>>> On Fri, Jul 15, 2016 at 12:08 AM, kugan
>>>> <kugan.vivekanandarajah@linaro.org> wrote:
>>>>>
>>>>>
>>>>> Hi Andrew,
>>>>>
>>>>>> Why separate out early VRP from tree-vrp?  Just a little curious.
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> It is based on the discussion in
>>>>> https://gcc.gnu.org/ml/gcc/2016-01/msg00069.html.
>>>>> In summary, conclusion (based on my understanding) was to implement a
>>>>> simplified VRP algorithm that doesn't require ASSERT_EXPR insertion.
>>>>
>>>>
>>>>
>>>> But I don't see why you are moving it from tree-vrp.c .  That was my
>>>> question, you pointing to that discussion does not say to split it
>>>> into a new file and expose these interfaces.
>>>>
>>>
>>> Are you saying that I should keep this part of tree-vrp.c. I am happy to
>>> do
>>> that if this is considered the best approach.
>>
>>
>> Yes, I think that's the best approach.
>>
> Thanks. Moved it into tree-vrp.c now.
>
>> Can you, as a refactoring before your patch, please change VRP to use
>> an alloc-pool
>> for allocating value_range?  The DOM-based VRP will add a lot of
>> malloc/free churn
>> otherwise.
>>
>> Generally watch coding-style such as  missed function comments.
>>
>> As you do a non-iterating VRP and thus do not visit back-edges you don't
>> need
>> to initialize loops or SCEV nor do you need loop-closed SSA.
>>
>> As you do a DOM-based VRP using SSA propagator stuff like ssa_prop_result
>> doesn't make any sense.
>
>
> I have removed it.
>>
>>
>> +edge evrp_dom_walker::before_dom_children (basic_block bb)
>> +{
>> +  /* If we are going out of scope, restore the old VR.  */
>> +  while (!cond_stack.is_empty ()
>> +        && !dominated_by_p (CDI_DOMINATORS, bb, cond_stack.last
>> ().first))
>> +    {
>> +      tree var = cond_stack.last ().second.first;
>> +      value_range *vr = cond_stack.last ().second.second;
>> +      value_range *vr_to_del = get_value_range (var);
>> +      XDELETE (vr_to_del);
>> +      change_value_range (var, vr);
>> +      cond_stack.pop ();
>> +    }
>>
>> that should be in after_dom_children I think and use a marker instead
>> of a DOM query.
>> See other examples like DOM itself or SCCVN.
>>
>
> Done.

+/* Restore/Pop all the old VRs maintained in the cond_stack.  */
+
+void evrp_dom_walker::finalize_dom_walker ()
+{
+  while (!cond_stack.is_empty ())
+    {
+      tree var = cond_stack.last ().second;
+      pop_value_range (var);
+      cond_stack.pop ();
+    }

why is this necessary at all?  Looks like a waste of time (and the
stack should be empty here
anyway).  I think you leak cond_stack as well, I suppose using
auto_vec might work here,
you have to check.

>>
>> +         /* Discover VR when condition is true.  */
>> +         if (te == e
>> +             && !TREE_OVERFLOW_P (op0)
>> +             && !TREE_OVERFLOW_P (op1))
>
>
> This is mainly to handle gcc.dg/pr38934.c. This would result in ICE from
> set_value_range otherwise:
>
> gcc_assert ((!TREE_OVERFLOW_P (min) || is_overflow_infinity (min))
>                   && (!TREE_OVERFLOW_P (max) || is_overflow_infinity
> (max)));

Ok, instead make sure to remove the overflow flag via

  if (TREE_OVERFLOW_P (op0))
    op0 = drop_tree_overflow (op0);
...

it looks like you want to merge the if ( & EDGE_TRUE_VALUE) and FALSE_VALUE
cases and only invert the tree comparison for the false edge.

+             tree cond = build2 (code, boolean_type_node, op0, op1);
+             extract_range_for_var_from_comparison_expr (&vr, op0, cond);

no wasteful tree building here please.  Instead of cond pass in code,
op0 and op1
as separate arguments.

+         /* If we found any usable VR, set the VR to ssa_name and create a
+            PUSH old value in the cond_stack with the old VR.  */
+         if (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE)
+           {
+             value_range *new_vr = vrp_value_range_pool.allocate ();
+             memset (new_vr, 0, sizeof (*new_vr));
+             *new_vr = vr;
+             cond_stack.safe_push (std::make_pair (bb, op0));

the memset looks redundant given you copy-assing from vr anyway.

You seem to miss the chance to register ranges for x_2 in i_1 < x_2 where
both i_1 and x_2 might have ranges that are useful.

push and pop_value_range should be methods in the dom walker class
and vrp_stack and cond_stack should be a single stack.  You can omit
basic_block if you use a "magic" NULL_TREE var as marker (simply
push a NULL_TREE, NULL pair at the end of before_dom_children).

>>
>> you can use e->flags & EDGE_TRUE_VALUE/EDGE_FALSE_VALUE
>>
>> why do you need those TREE_OVERFLOW checks?
>>
>> +             tree cond = build2 (code, boolean_type_node, op0, op1);
>> +             tree a = build2 (ASSERT_EXPR, TREE_TYPE (op0), op0, cond);
>> +             extract_range_from_assert (&vr, a);
>>
>> so I was hoping that the "refactoring" patch in the series would expose a
>> more
>> useful interface than extract_range_from_assert ... namely one that can
>> extract a range from the comparison directly and does not require building
>> a scratch ASSERT_EXPR.
>
>
> I have split extract_range_from_assert into
> extract_range_for_var_from_comparison_expr and using it now. Is that better?

See above.

>>
>>
>> +         /* If we found any usable VR, set the VR to ssa_name and create
>> a
>> +            restore point in the cond_stack with the  old VR. */
>> +         if (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE)
>> +           {
>> +             value_range *new_vr = XCNEW (value_range);
>> +             *new_vr = vr;
>> +             cond_stack.safe_push (std::make_pair (bb,
>> +                                                   std::make_pair (op0,
>> +
>> old_vr)));
>> +             change_value_range (op0, new_vr);
>>
>> I don't like 'change_value_range' as interface, please integrate that into
>> a push/pop_value_range style interface instead.
>
>
> Tried using push/pop interface.
>>
>>
>> +       vrp_visit_stmt (stmt, &taken_edge_p, &output_p);
>> +    }
>> +
>> +  return NULL;
>>
>> you should return taken_edge_p (misnamed as it isn't a pointer) and take
>> advantage of EDGE_EXECUTABLE.  Again see DOM/SCCVN (might want to
>> defer this as a followup improvement).
>
>
> I have added a TODO to this effect and will comeback to it.
>>
>>
>> Note that the advantage of a DOM-based VRP is that backtracking is easy
>> to implement (you don't do that yet).  That is, after DEF got a (better)
>> value-range you can simply re-visit all the defs of its uses (and
>> recursively).
>> I think you have to be careful with stmts that might prematurely leave a
>> BB
>> though (like via EH).  So sth for a followup as well.
>
>
> Is this OK now. Bootstrapped and regression tested on x86_64-linux  with no
> new regressions.

Better, still not perfect.

I'm also arguing on the pass placement now - you put it where it may make sense
for IPA VRP (but then IPA VRP could simply do this in its analysis phase) but
not so much where it makes sense during the early pipeline.  I think it makes
sense after FRE.

Looking at how you finalize I see several issues with simply re-using
vrp_finalize.

First of all the loop doing the set_range_info will turn up with
nothing as you've
popped off all value-ranges from the lattice.  Same for substitute-and-fold (or
jump-threading).

What you instead need to do with the DOM scheme is at the point you
call vrp_visit_stmt do sth like

     vrp_visit_stmt (....);
     if (fold_stmt (&gsi, follow_single_use_edges))
       update_stmt ();
     tree def = SINGLE_SSA_DEF_OPERAND (stmt, SSA_OP_DEF);
     if (def
         && INTEGRAL_TYPE_P (TREE_TYPE (def))
         && (TREE_CODE (vr_value[i]->min) == INTEGER_CST)
          && (TREE_CODE (vr_value[i]->max) == INTEGER_CST)
          && (vr_value[i]->type == VR_RANGE
              || vr_value[i]->type == VR_ANTI_RANGE))
        set_range_info (name, vr_value[i]->type, vr_value[i]->min,
                        vr_value[i]->max);

thus please split vrp_finalize into two parts, one of it with the memory
freeing which is the one you'd call.

Note that EVRP is not enabled by default at any optimization level
it seems so bootstrap / test of it would be useless (did you only
test with the full series?  I never looked at the IPA VRP part)

Thanks,
Richard.


> Thanks,
> Kugan
>
> gcc/ChangeLog:
>
> 2016-07-22  Kugan Vivekanandarajah  <kuganv@linaro.org>
>
>         * common.opt: New option -ftree-evrp.
>         * doc/invoke.texi: Document -ftree-evrp.
>         * passes.def: Define new pass_early_vrp.
>         * timevar.def: Define new TV_TREE_EARLY_VRP.
>         * tree-pass.h (make_pass_early_vrp): New.
>         * tree-vrp.c (extract_range_for_var_from_comparison_expr): New.
>         (extract_range_from_assert): Call
>         extract_range_for_var_from_comparison_expr.
>         (push_value_range): New.
>         (pop_value_range): Likewise.
>         (evrp_visit_phi_node_local): Likewise.
>         (edge evrp_dom_walker::before_dom_children): Likewise.
>         (void evrp_dom_walker::after_dom_children): Likewise.
>         (void evrp_dom_walker::finalize_dom_walker): Likewise.
>         (execute_early_vrp): Likewise.
>         (make_pass_early_vrp): Likewise.
>
>
> gcc/testsuite/ChangeLog:
>
> 2016-07-22  Kugan Vivekanandarajah  <kuganv@linaro.org>
>
>         * gcc.dg/tree-ssa/evrp1.c: New test.
>         * gcc.dg/tree-ssa/evrp2.c: New test.
>         * gcc.dg/tree-ssa/evrp3.c: New test.
>         * g++.dg/tree-ssa/pr31146-2.C: Run with -fno-tree-evrp as evrp also
>         does the same transformation.
>         * gcc.dg/tree-ssa/pr20318.c: Likewise.
>         * gcc.dg/tree-ssa/pr25382.c: Likewise.
>         * gcc.dg/tree-ssa/pr68431.c: Likewise.
>         * gcc.dg/tree-ssa/vrp19.c: Likewise.
>         * gcc.dg/tree-ssa/vrp23.c: Likewise.
>         * gcc.dg/tree-ssa/vrp24.c: Likewise.
>         * gcc.dg/tree-ssa/vrp58.c: Likewise.
>         * gcc.dg/tree-ssa/vrp67.c: Likewise.
>         * gcc.dg/tree-ssa/vrp98.c: Likewise.
>         * gcc.dg/tree-ssa/vrp19.c: Likewise.
>         * gcc.dg/tree-ssa/vrp23.c: Likewise.
>         * gcc.dg/tree-ssa/vrp24.c: Likewise.
>         * gcc.dg/tree-ssa/vrp58.c: Likewise.
>         * gcc.dg/tree-ssa/vrp67.c: Likewise.
>         * gcc.dg/tree-ssa/vrp98.c: Likewise.
>         * gcc.dg/tree-ssa/pr22117.c: Run with -fno-tree-evrp as predicate is
>         optimized away before vrp1.

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Early VRP Implementation
  2016-07-25 11:18               ` Richard Biener
@ 2016-07-26 12:27                 ` kugan
  2016-07-26 13:37                   ` Richard Biener
  0 siblings, 1 reply; 67+ messages in thread
From: kugan @ 2016-07-26 12:27 UTC (permalink / raw)
  To: Richard Biener; +Cc: Andrew Pinski, gcc-patches, Jan Hubicka, Martin Jambor

[-- Attachment #1: Type: text/plain, Size: 7362 bytes --]



Hi Riachard,

Thanks for the review. Here is an updated patch with comments below.

> +/* Restore/Pop all the old VRs maintained in the cond_stack.  */
> +
> +void evrp_dom_walker::finalize_dom_walker ()
> +{
> +  while (!cond_stack.is_empty ())
> +    {
> +      tree var = cond_stack.last ().second;
> +      pop_value_range (var);
> +      cond_stack.pop ();
> +    }
>
> why is this necessary at all?  Looks like a waste of time (and the
> stack should be empty here
> anyway).  I think you leak cond_stack as well, I suppose using
> auto_vec might work here,
> you have to check.
Done.

>
>>>
>>> +         /* Discover VR when condition is true.  */
>>> +         if (te == e
>>> +             && !TREE_OVERFLOW_P (op0)
>>> +             && !TREE_OVERFLOW_P (op1))
>>
>>
>> This is mainly to handle gcc.dg/pr38934.c. This would result in ICE from
>> set_value_range otherwise:
>>
>> gcc_assert ((!TREE_OVERFLOW_P (min) || is_overflow_infinity (min))
>>                   && (!TREE_OVERFLOW_P (max) || is_overflow_infinity
>> (max)));
>
> Ok, instead make sure to remove the overflow flag via
>
>   if (TREE_OVERFLOW_P (op0))
>     op0 = drop_tree_overflow (op0);
  ...
Done.

>
> it looks like you want to merge the if ( & EDGE_TRUE_VALUE) and FALSE_VALUE
> cases and only invert the tree comparison for the false edge.
Done.

>
> +             tree cond = build2 (code, boolean_type_node, op0, op1);
> +             extract_range_for_var_from_comparison_expr (&vr, op0, cond);
>
> no wasteful tree building here please.  Instead of cond pass in code,
> op0 and op1
> as separate arguments.
Done.

>
> +         /* If we found any usable VR, set the VR to ssa_name and create a
> +            PUSH old value in the cond_stack with the old VR.  */
> +         if (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE)
> +           {
> +             value_range *new_vr = vrp_value_range_pool.allocate ();
> +             memset (new_vr, 0, sizeof (*new_vr));
> +             *new_vr = vr;
> +             cond_stack.safe_push (std::make_pair (bb, op0));
>
> the memset looks redundant given you copy-assing from vr anyway.
Done.

>
> You seem to miss the chance to register ranges for x_2 in i_1 < x_2 where
> both i_1 and x_2 might have ranges that are useful.
I will address this once the basic structure is in place if that is OK 
with you.

>
> push and pop_value_range should be methods in the dom walker class
> and vrp_stack and cond_stack should be a single stack.  You can omit
> basic_block if you use a "magic" NULL_TREE var as marker (simply
> push a NULL_TREE, NULL pair at the end of before_dom_children).
>
Done.

>>>
>>> you can use e->flags & EDGE_TRUE_VALUE/EDGE_FALSE_VALUE
>>>
>>> why do you need those TREE_OVERFLOW checks?
>>>
>>> +             tree cond = build2 (code, boolean_type_node, op0, op1);
>>> +             tree a = build2 (ASSERT_EXPR, TREE_TYPE (op0), op0, cond);
>>> +             extract_range_from_assert (&vr, a);
>>>
>>> so I was hoping that the "refactoring" patch in the series would expose a
>>> more
>>> useful interface than extract_range_from_assert ... namely one that can
>>> extract a range from the comparison directly and does not require building
>>> a scratch ASSERT_EXPR.
>>
>>
>> I have split extract_range_from_assert into
>> extract_range_for_var_from_comparison_expr and using it now. Is that better?
>
> See above.
>
>>>
>>>
>>> +         /* If we found any usable VR, set the VR to ssa_name and create
>>> a
>>> +            restore point in the cond_stack with the  old VR. */
>>> +         if (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE)
>>> +           {
>>> +             value_range *new_vr = XCNEW (value_range);
>>> +             *new_vr = vr;
>>> +             cond_stack.safe_push (std::make_pair (bb,
>>> +                                                   std::make_pair (op0,
>>> +
>>> old_vr)));
>>> +             change_value_range (op0, new_vr);
>>>
>>> I don't like 'change_value_range' as interface, please integrate that into
>>> a push/pop_value_range style interface instead.
>>
>>
>> Tried using push/pop interface.
>>>
>>>
>>> +       vrp_visit_stmt (stmt, &taken_edge_p, &output_p);
>>> +    }
>>> +
>>> +  return NULL;
>>>
>>> you should return taken_edge_p (misnamed as it isn't a pointer) and take
>>> advantage of EDGE_EXECUTABLE.  Again see DOM/SCCVN (might want to
>>> defer this as a followup improvement).
>>
>>
>> I have added a TODO to this effect and will comeback to it.
>>>
>>>
>>> Note that the advantage of a DOM-based VRP is that backtracking is easy
>>> to implement (you don't do that yet).  That is, after DEF got a (better)
>>> value-range you can simply re-visit all the defs of its uses (and
>>> recursively).
>>> I think you have to be careful with stmts that might prematurely leave a
>>> BB
>>> though (like via EH).  So sth for a followup as well.
>>
>>
>> Is this OK now. Bootstrapped and regression tested on x86_64-linux  with no
>> new regressions.
>
> Better, still not perfect.
>
> I'm also arguing on the pass placement now - you put it where it may make sense
> for IPA VRP (but then IPA VRP could simply do this in its analysis phase) but
> not so much where it makes sense during the early pipeline.  I think it makes
> sense after FRE.
>
> Looking at how you finalize I see several issues with simply re-using
> vrp_finalize.
>
> First of all the loop doing the set_range_info will turn up with
> nothing as you've
> popped off all value-ranges from the lattice.  Same for substitute-and-fold (or
> jump-threading).
I am not sure understanding you. I am poping the value ranges for scope 
when we leave them. Other value ranges which lives in all the regions 
will remain.

>
> What you instead need to do with the DOM scheme is at the point you
> call vrp_visit_stmt do sth like
>
>      vrp_visit_stmt (....);
>      if (fold_stmt (&gsi, follow_single_use_edges))
>        update_stmt ();
I have added this. I think this will be good as we would be able to 
optimize with value ranges that is valid within the scope.

>      tree def = SINGLE_SSA_DEF_OPERAND (stmt, SSA_OP_DEF);
>      if (def
>          && INTEGRAL_TYPE_P (TREE_TYPE (def))
>          && (TREE_CODE (vr_value[i]->min) == INTEGER_CST)
>           && (TREE_CODE (vr_value[i]->max) == INTEGER_CST)
>           && (vr_value[i]->type == VR_RANGE
>               || vr_value[i]->type == VR_ANTI_RANGE))
>         set_range_info (name, vr_value[i]->type, vr_value[i]->min,
>                         vr_value[i]->max);
>
I am not sure if this is needed. I dont know if my push/pop value range 
implementation is not what you wanted. If you still prefer, I am happy 
to add this.

> thus please split vrp_finalize into two parts, one of it with the memory
> freeing which is the one you'd call.
>
> Note that EVRP is not enabled by default at any optimization level
> it seems so bootstrap / test of it would be useless (did you only
> test with the full series?  I never looked at the IPA VRP part)
>
I have:

+ftree-evrp
+Common Report Var(flag_tree_early_vrp) Init(1) Optimization
+Perform Early Value Range Propagation on trees.

I would like to run this only for -O2 and above but for now I am using 
this to test.

I  have tested the last set of patch separately.

I will do more testing on this patch based on your feedback. Does this 
look better?

Thanks,
Kugan



[-- Attachment #2: 0005-Add-early-vrp.patch --]
[-- Type: text/x-patch, Size: 27023 bytes --]

From eefcd1c5444cf5dd9f121e8bd04148d324d06ffc Mon Sep 17 00:00:00 2001
From: Kugan Vivekanandarajah <kugan.vivekanandarajah@linaro.org>
Date: Fri, 24 Jun 2016 14:45:24 +1000
Subject: [PATCH 5/7] Add early vrp

---
 gcc/common.opt                            |   4 +
 gcc/doc/invoke.texi                       |   9 +
 gcc/passes.def                            |   1 +
 gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C |   2 +-
 gcc/testsuite/gcc.dg/tree-ssa/evrp1.c     |  13 ++
 gcc/testsuite/gcc.dg/tree-ssa/evrp2.c     |  18 ++
 gcc/testsuite/gcc.dg/tree-ssa/evrp3.c     |  15 ++
 gcc/testsuite/gcc.dg/tree-ssa/pr20318.c   |   4 +-
 gcc/testsuite/gcc.dg/tree-ssa/pr22117.c   |   2 +-
 gcc/testsuite/gcc.dg/tree-ssa/pr25382.c   |   4 +-
 gcc/testsuite/gcc.dg/tree-ssa/pr68431.c   |   4 +-
 gcc/testsuite/gcc.dg/tree-ssa/vrp19.c     |   6 +-
 gcc/testsuite/gcc.dg/tree-ssa/vrp23.c     |   4 +-
 gcc/testsuite/gcc.dg/tree-ssa/vrp24.c     |   5 +-
 gcc/testsuite/gcc.dg/tree-ssa/vrp58.c     |   4 +-
 gcc/testsuite/gcc.dg/tree-ssa/vrp67.c     |   4 +-
 gcc/testsuite/gcc.dg/tree-ssa/vrp98.c     |   6 +-
 gcc/timevar.def                           |   1 +
 gcc/tree-pass.h                           |   1 +
 gcc/tree-vrp.c                            | 354 ++++++++++++++++++++++++++----
 20 files changed, 397 insertions(+), 64 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/evrp1.c
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/evrp2.c
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/evrp3.c

diff --git a/gcc/common.opt b/gcc/common.opt
index f0d7196..29d0e4d 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2471,6 +2471,10 @@ ftree-vrp
 Common Report Var(flag_tree_vrp) Init(0) Optimization
 Perform Value Range Propagation on trees.
 
+ftree-evrp
+Common Report Var(flag_tree_early_vrp) Init(1) Optimization
+Perform Early Value Range Propagation on trees.
+
 fsplit-paths
 Common Report Var(flag_split_paths) Init(0) Optimization
 Split paths leading to loop backedges.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index e000218..f4dc88d 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -7665,6 +7665,10 @@ enabled by default at @option{-O2} and higher.  Null pointer check
 elimination is only done if @option{-fdelete-null-pointer-checks} is
 enabled.
 
+@item -ftree-evrp
+@opindex ftree-evrp
+Perform Early Value Range Propagation on trees.
+
 @item -fsplit-paths
 @opindex fsplit-paths
 Split paths leading to loop backedges.  This can improve dead code
@@ -12270,6 +12274,11 @@ is made by appending @file{.slp} to the source file name.
 Dump each function after Value Range Propagation (VRP).  The file name
 is made by appending @file{.vrp} to the source file name.
 
+@item early vrp
+@opindex fdump-tree-evrp
+Dump each function after Early Value Range Propagation (EVRP).  The file name
+is made by appending @file{.evrp} to the source file name.
+
 @item oaccdevlow
 @opindex fdump-tree-oaccdevlow
 Dump each function after applying device-specific OpenACC transformations.
diff --git a/gcc/passes.def b/gcc/passes.def
index 3647e90..ebd360b 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -89,6 +89,7 @@ along with GCC; see the file COPYING3.  If not see
 	     execute TODO_rebuild_alias at this point.  */
 	  NEXT_PASS (pass_build_ealias);
 	  NEXT_PASS (pass_fre);
+	  NEXT_PASS (pass_early_vrp);
 	  NEXT_PASS (pass_merge_phi);
           NEXT_PASS (pass_dse);
 	  NEXT_PASS (pass_cd_dce);
diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C b/gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C
index 5e09583..dce05d6 100644
--- a/gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C
+++ b/gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O -fdump-tree-forwprop1" } */
+/* { dg-options "-O -fno-tree-evrp -fdump-tree-forwprop1" } */
 
 #include <new>
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/evrp1.c b/gcc/testsuite/gcc.dg/tree-ssa/evrp1.c
new file mode 100644
index 0000000..8c6e4e6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/evrp1.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+int foo (int i);
+int bar (int j)
+{
+  if (j > 2)
+    return foo (j + 2);
+  else
+    return j;
+}
+
+/* { dg-final { scan-tree-dump "\\\[5, \\+INF" "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/evrp2.c b/gcc/testsuite/gcc.dg/tree-ssa/evrp2.c
new file mode 100644
index 0000000..e6d4235
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/evrp2.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+int foo (int i);
+int bar2 (int j)
+{
+  if (j > 2)
+    {
+      if (j < 7)
+	return foo (j + 1);
+      else
+	return foo (j + 2);
+    }
+  return j;
+}
+
+
+/* { dg-final { scan-tree-dump "\\\[4, 7\\\]" "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/evrp3.c b/gcc/testsuite/gcc.dg/tree-ssa/evrp3.c
new file mode 100644
index 0000000..1a3bbd5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/evrp3.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+int foo (int i);
+void bar (int j)
+{
+  unsigned int i;
+  for (i = 0; i < 10; ++i)
+    {
+      bar (i + 1);
+    }
+}
+
+/* { dg-final { scan-tree-dump "\\\[1, 10\\\]" "evrp" } } */
+
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr20318.c b/gcc/testsuite/gcc.dg/tree-ssa/pr20318.c
index 41f569e..8c12863 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr20318.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr20318.c
@@ -1,5 +1,5 @@
 /* { dg-do compile { target { ! keeps_null_pointer_checks } } } */
-/* { dg-options "-O2 -fdump-tree-original -fdump-tree-vrp1 -fdelete-null-pointer-checks" } */
+/* { dg-options "-O2 -fdump-tree-original -fdump-tree-evrp  -fdelete-null-pointer-checks" } */
 
 extern int* f(int) __attribute__((returns_nonnull));
 extern void eliminate ();
@@ -14,4 +14,4 @@ void h () {
 }
 
 /* { dg-final { scan-tree-dump-times "== 0" 1 "original" } } */
-/* { dg-final { scan-tree-dump-times "Folding predicate\[^\\n\]*to 0" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "Folding predicate\[^\\n\]*to 0" 1 "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c b/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c
index 7efdd63..43cea0b 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c
@@ -3,7 +3,7 @@
    known to be zero after entering the first two "if" statements.  */
 
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1" } */
+/* { dg-options "-O2 -fno-tree-evrp -fdump-tree-vrp" } */
 
 void link_error (void);
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c b/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c
index dcf9148..0d19d0d 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c
@@ -3,7 +3,7 @@
    Check that VRP now gets ranges from BIT_AND_EXPRs.  */
 
 /* { dg-do compile } */
-/* { dg-options "-O2 -fno-tree-ccp -fdump-tree-vrp1" } */
+/* { dg-options "-O2 -fno-tree-ccp -fdump-tree-evrp" } */
 
 int
 foo (int a)
@@ -15,4 +15,4 @@ foo (int a)
     return 1;
 }
 
-/* { dg-final { scan-tree-dump-times "Folding predicate b_.* > 300 to 0" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "Folding predicate b_.* > 300 to 0" 1 "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr68431.c b/gcc/testsuite/gcc.dg/tree-ssa/pr68431.c
index 3bd3843..a73aa00 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr68431.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr68431.c
@@ -1,5 +1,5 @@
 /* PR tree-optimization/68431 */
-/* { dg-options "-O2 -fdump-tree-vrp1-details" } */
+/* { dg-options "-O2 -fdump-tree-evrp-details" } */
 
 unsigned int x = 1;
 int
@@ -13,4 +13,4 @@ main (void)
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "Folding predicate .*to 0" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "Folding predicate .*to 0" 1 "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp19.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp19.c
index cecacb6..3d47bfd 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp19.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp19.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-fwrapv -O1 -ftree-vrp -fdump-tree-vrp1" } */
+/* { dg-options "-fwrapv -O1 -ftree-vrp -fdump-tree-evrp" } */
 
 #include <limits.h>
 extern void abort ();
@@ -22,5 +22,5 @@ int g (int b) {
 	}
 	return 1;
 }
-/* { dg-final { scan-tree-dump "Folding predicate a_. < 0 to 0" "vrp1" } } */
-/* { dg-final { scan-tree-dump "Folding predicate b_. >= 0 to 1" "vrp1" } } */
+/* { dg-final { scan-tree-dump "Folding predicate a_. < 0 to 0" "evrp" } } */
+/* { dg-final { scan-tree-dump "Folding predicate b_. >= 0 to 1" "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp23.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp23.c
index b877ccc..a6d2a24 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp23.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp23.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1-details" } */
+/* { dg-options "-O2 -fdump-tree-evrp-details" } */
 
 void aa (void);
 void aos (void);
@@ -45,5 +45,5 @@ L8:
 /* The n_sets > 0 test can be simplified into n_sets == 1 since the
    only way to reach the test is when n_sets <= 1, and the only value
    which satisfies both conditions is n_sets == 1.  */
-/* { dg-final { scan-tree-dump-times "Simplified relational" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "Simplified relational" 1 "evrp" } } */
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp24.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp24.c
index e740575..0e1e69c 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp24.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp24.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1-details" } */
+/* { dg-options "-O2 -fdump-tree-evrp-details -fdump-tree-vrp1-details" } */
 
 
 struct rtx_def;
@@ -91,5 +91,6 @@ L7:
    The second n_sets > 0 test can also be simplified into n_sets == 1
    as the only way to reach the tests is when n_sets <= 1 and the only
    value which satisfies both conditions is n_sets == 1.  */
-/* { dg-final { scan-tree-dump-times "Simplified relational" 2 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "Simplified relational" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "Simplified relational" 1 "evrp" } } */
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp58.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp58.c
index 5b44ae2..6df91ca 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp58.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp58.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1-details" } */
+/* { dg-options "-O2 -fdump-tree-evrp-details" } */
 
 long long
 foo (long long a, signed char b, signed char c)
@@ -9,4 +9,4 @@ foo (long long a, signed char b, signed char c)
 }
 
 /* { dg-final { scan-tree-dump "Folded into" "vrp1" { target int32plus } } } */
-/* { dg-final { scan-tree-dump "Folding statement: _\[0-9\]\* = \\(long long int\\) bc_\[0-9\]\*;" "vrp1" { target int16 } } } */
+/* { dg-final { scan-tree-dump "Folding statement: _\[0-9\]\* = \\(long long int\\) bc_\[0-9\]\*;" "evrp" { target int16 } } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp67.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp67.c
index ef5e8f9..b19b546 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp67.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp67.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1" } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
 
 extern void link_error (void);
 
@@ -36,4 +36,4 @@ unsigned baz (unsigned i)
   return i;
 }
 
-/* { dg-final { scan-tree-dump-times "Folding predicate" 3 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "Folding predicate" 3 "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp98.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp98.c
index 982f091..7ad818c 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp98.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp98.c
@@ -1,6 +1,6 @@
 /* { dg-do compile } */
 /* { dg-require-effective-target int128 } */
-/* { dg-options "-Os -fdump-tree-vrp1-details" } */
+/* { dg-options "-Os -fdump-tree-evrp-details" } */
 
 #include <stdint.h>
 #include <limits.h>
@@ -36,6 +36,6 @@ foo (bigger_than_word a, word b, uint8_t c)
   return ret;
 }
 
-/* { dg-final { scan-tree-dump "Folded into: if \\(_\[0-9\]+ == 1\\)" "vrp1" } } */
+/* { dg-final { scan-tree-dump "Folded into: if \\(_\[0-9\]+ == 1\\)" "evrp" } } */
 /* { dg-final { scan-tree-dump-not "Folded into: if \\(_\[0-9\]+ == 2\\)" "vrp1" } } */
-/* { dg-final { scan-tree-dump "Folded into: if \\(_\[0-9\]+ == 3\\)" "vrp1" } } */
+/* { dg-final { scan-tree-dump "Folded into: if \\(_\[0-9\]+ == 3\\)" "evrp" } } */
diff --git a/gcc/timevar.def b/gcc/timevar.def
index 362aa6e..8d308ac 100644
--- a/gcc/timevar.def
+++ b/gcc/timevar.def
@@ -147,6 +147,7 @@ DEFTIMEVAR (TV_TREE_CFG		     , "tree CFG construction")
 DEFTIMEVAR (TV_TREE_CLEANUP_CFG	     , "tree CFG cleanup")
 DEFTIMEVAR (TV_TREE_TAIL_MERGE       , "tree tail merge")
 DEFTIMEVAR (TV_TREE_VRP              , "tree VRP")
+DEFTIMEVAR (TV_TREE_EARLY_VRP        , "tree Early VRP")
 DEFTIMEVAR (TV_TREE_COPY_PROP        , "tree copy propagation")
 DEFTIMEVAR (TV_FIND_REFERENCED_VARS  , "tree find ref. vars")
 DEFTIMEVAR (TV_TREE_PTA		     , "tree PTA")
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index 36299a6..d836d57 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -440,6 +440,7 @@ extern gimple_opt_pass *make_pass_fre (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_check_data_deps (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_copy_prop (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_isolate_erroneous_paths (gcc::context *ctxt);
+extern gimple_opt_pass *make_pass_early_vrp (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_vrp (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_uncprop (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_return_slot (gcc::context *ctxt);
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index 83579e3..de755bc 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -59,6 +59,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "target.h"
 #include "case-cfn-macros.h"
 #include "alloc-pool.h"
+#include "tree-vrp.h"
 #include "domwalk.h"
 
 #define VR_INITIALIZER { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL }
@@ -1437,44 +1438,17 @@ op_with_boolean_value_range_p (tree op)
 	  && integer_onep (vr->max));
 }
 
-/* Extract value range information from an ASSERT_EXPR EXPR and store
-   it in *VR_P.  */
+/* Extract value range information for VAR when (OP COND_CODE LIMIT) is
+   true and store it in *VR_P.  */
 
 static void
-extract_range_from_assert (value_range *vr_p, tree expr)
+extract_range_for_var_from_comparison_expr (tree var, enum tree_code cond_code,
+					    tree op, tree limit,
+					    value_range *vr_p)
 {
-  tree var, cond, limit, min, max, type;
+  tree  min, max, type;
   value_range *limit_vr;
-  enum tree_code cond_code;
-
-  var = ASSERT_EXPR_VAR (expr);
-  cond = ASSERT_EXPR_COND (expr);
-
-  gcc_assert (COMPARISON_CLASS_P (cond));
-
-  /* Find VAR in the ASSERT_EXPR conditional.  */
-  if (var == TREE_OPERAND (cond, 0)
-      || TREE_CODE (TREE_OPERAND (cond, 0)) == PLUS_EXPR
-      || TREE_CODE (TREE_OPERAND (cond, 0)) == NOP_EXPR)
-    {
-      /* If the predicate is of the form VAR COMP LIMIT, then we just
-	 take LIMIT from the RHS and use the same comparison code.  */
-      cond_code = TREE_CODE (cond);
-      limit = TREE_OPERAND (cond, 1);
-      cond = TREE_OPERAND (cond, 0);
-    }
-  else
-    {
-      /* If the predicate is of the form LIMIT COMP VAR, then we need
-	 to flip around the comparison code to create the proper range
-	 for VAR.  */
-      cond_code = swap_tree_comparison (TREE_CODE (cond));
-      limit = TREE_OPERAND (cond, 0);
-      cond = TREE_OPERAND (cond, 1);
-    }
-
   limit = avoid_overflow_infinity (limit);
-
   type = TREE_TYPE (var);
   gcc_assert (limit != var);
 
@@ -1517,15 +1491,15 @@ extract_range_from_assert (value_range *vr_p, tree expr)
      as well build the range [b_4, +INF] for it.
      One special case we handle is extracting a range from a
      range test encoded as (unsigned)var + CST <= limit.  */
-  if (TREE_CODE (cond) == NOP_EXPR
-      || TREE_CODE (cond) == PLUS_EXPR)
+  if (TREE_CODE (op) == NOP_EXPR
+      || TREE_CODE (op) == PLUS_EXPR)
     {
-      if (TREE_CODE (cond) == PLUS_EXPR)
+      if (TREE_CODE (op) == PLUS_EXPR)
         {
-          min = fold_build1 (NEGATE_EXPR, TREE_TYPE (TREE_OPERAND (cond, 1)),
-			     TREE_OPERAND (cond, 1));
+          min = fold_build1 (NEGATE_EXPR, TREE_TYPE (TREE_OPERAND (op, 1)),
+			     TREE_OPERAND (op, 1));
           max = int_const_binop (PLUS_EXPR, limit, min);
-	  cond = TREE_OPERAND (cond, 0);
+	  op = TREE_OPERAND (op, 0);
 	}
       else
 	{
@@ -1709,6 +1683,41 @@ extract_range_from_assert (value_range *vr_p, tree expr)
   vrp_intersect_ranges (vr_p, get_value_range (var));
 }
 
+/* Extract value range information from an ASSERT_EXPR EXPR and store
+   it in *VR_P.  */
+
+static void
+extract_range_from_assert (value_range *vr_p, tree expr)
+{
+  tree var = ASSERT_EXPR_VAR (expr);
+  tree cond = ASSERT_EXPR_COND (expr);
+  tree limit, op;
+  enum tree_code cond_code;
+  gcc_assert (COMPARISON_CLASS_P (cond));
+
+  /* Find VAR in the ASSERT_EXPR conditional.  */
+  if (var == TREE_OPERAND (cond, 0)
+      || TREE_CODE (TREE_OPERAND (cond, 0)) == PLUS_EXPR
+      || TREE_CODE (TREE_OPERAND (cond, 0)) == NOP_EXPR)
+    {
+      /* If the predicate is of the form VAR COMP LIMIT, then we just
+	 take LIMIT from the RHS and use the same comparison code.  */
+      cond_code = TREE_CODE (cond);
+      limit = TREE_OPERAND (cond, 1);
+      op = TREE_OPERAND (cond, 0);
+    }
+  else
+    {
+      /* If the predicate is of the form LIMIT COMP VAR, then we need
+	 to flip around the comparison code to create the proper range
+	 for VAR.  */
+      cond_code = swap_tree_comparison (TREE_CODE (cond));
+      limit = TREE_OPERAND (cond, 0);
+      op = TREE_OPERAND (cond, 1);
+    }
+  extract_range_for_var_from_comparison_expr (var, cond_code, op,
+					      limit, vr_p);
+}
 
 /* Extract range information from SSA name VAR and store it in VR.  If
    VAR has an interesting range, use it.  Otherwise, create the
@@ -10144,7 +10153,7 @@ finalize_jump_threads (void)
 /* Traverse all the blocks folding conditionals with known ranges.  */
 
 static void
-vrp_finalize (bool jump_thread_p, bool warn_array_bounds_p)
+vrp_finalize (bool early_vrp_p, bool warn_array_bounds_p)
 {
   size_t i;
 
@@ -10185,7 +10194,7 @@ vrp_finalize (bool jump_thread_p, bool warn_array_bounds_p)
 
   /* We must identify jump threading opportunities before we release
      the datastructures built by VRP.  */
-  if (jump_thread_p)
+  if (!early_vrp_p)
     identify_jump_threads ();
 
   /* Free allocated memory.  */
@@ -10201,6 +10210,229 @@ vrp_finalize (bool jump_thread_p, bool warn_array_bounds_p)
 }
 
 
+/* Visit the basic blocks in the dominance order and set the Value Ranges (VR)
+   for SSA_NAMEs in the scope.  Use this VR to discover more VRs.  Restore the
+   old VR once the scope is exited.  */
+
+static bool
+evrp_visit_phi_node_local (gphi *phi)
+{
+  size_t i;
+  tree lhs = PHI_RESULT (phi);
+  value_range vr_result = VR_INITIALIZER;
+  bool first = true;
+  int edges;
+
+  edges = 0;
+  for (i = 0; i < gimple_phi_num_args (phi); i++)
+    {
+      edge e = gimple_phi_arg_edge (phi, i);
+      tree arg = PHI_ARG_DEF (phi, i);
+      value_range vr_arg = VR_INITIALIZER;
+      ++edges;
+
+      /* If there is a back-edge, set the result to VARYING.  */
+      if (e->flags & (EDGE_DFS_BACK | EDGE_COMPLEX))
+	{
+	  set_value_range_to_varying (&vr_result);
+	  break;
+	}
+
+      if (TREE_CODE (arg) == SSA_NAME)
+	vr_arg = *(get_value_range (arg));
+      else
+	set_value_range_to_varying (&vr_arg);
+
+      /* If any of the RHS value is VARYING, set the result to VARYING.  */
+      if ((vr_arg.type != VR_RANGE)
+	  && (vr_arg.type != VR_ANTI_RANGE))
+	{
+	  set_value_range_to_varying (&vr_result);
+	  break;
+	}
+
+      /* Set/meet the RHS value range with the result so far.  */
+      if (first)
+	set_value_range (&vr_result, vr_arg.type, vr_arg.min,
+			 vr_arg.max, vr_arg.equiv);
+      else
+	vrp_meet (&vr_result, &vr_arg);
+      first = false;
+      if (vr_result.type == VR_VARYING)
+	break;
+    }
+
+  /* Check if the value range has changed and return accordingly.  */
+  if (update_value_range (lhs, &vr_result))
+    return true;
+  else
+    return false;
+}
+
+/* evrp_dom_walker visits the basic blocks in the dominance order and set the
+   Value Ranges (VR) for SSA_NAMEs in the scope.  Use this VR to discover
+   more VRs.  */
+
+class evrp_dom_walker : public dom_walker
+{
+public:
+  evrp_dom_walker ()
+    : dom_walker (CDI_DOMINATORS), stack (10) {}
+
+  virtual edge before_dom_children (basic_block);
+  virtual void after_dom_children (basic_block);
+  void push_value_range (const_tree var, value_range *vr);
+  value_range *pop_value_range (const_tree var);
+
+  /* Cond_stack holds the old VR.  */
+  auto_vec<std::pair <const_tree, value_range*>, 0 > stack;
+};
+
+/* See if there is any new scope is entered with new VR and set that VR to
+   ssa_name before visiting the statements in the scope.  */
+
+edge evrp_dom_walker::before_dom_children (basic_block bb)
+{
+  value_range *new_vr = NULL;
+  tree op0 = NULL_TREE;
+  if (single_pred_p (bb))
+    {
+      edge e = single_pred_edge (bb);
+      value_range vr = VR_INITIALIZER;
+      gimple *stmt = last_stmt (e->src);
+
+      if (stmt
+	  && gimple_code (stmt) == GIMPLE_COND
+	  && INTEGRAL_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt))))
+	{
+	  op0 = gimple_cond_lhs (stmt);
+	  tree op1 = gimple_cond_rhs (stmt);
+	  tree_code code = gimple_cond_code (stmt);
+	  value_range *old_vr = get_value_range (op0);
+
+	  if (TREE_OVERFLOW_P (op1))
+	    op1 = drop_tree_overflow (op1);
+
+	  /* If condition is false, invert the cond.  */
+	  if (e->flags & EDGE_FALSE_VALUE)
+	    code = invert_tree_comparison (gimple_cond_code (stmt),
+					   HONOR_NANS (op0));
+	  /* Discover VR when condition is true.  */
+	  extract_range_for_var_from_comparison_expr (op0, code, op0, op1, &vr);
+	  if (old_vr->type == VR_RANGE || old_vr->type == VR_ANTI_RANGE)
+	    vrp_intersect_ranges (&vr, old_vr);
+
+	  /* If we found any usable VR, set the VR to ssa_name and create a
+	     PUSH old value in the stack with the old VR.  */
+	  if (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE)
+	    {
+	      new_vr = vrp_value_range_pool.allocate ();
+	      *new_vr = vr;
+	    }
+	}
+    }
+  push_value_range (op0, new_vr);
+
+  /* Visit PHI stmts and discover any new VRs possible.  */
+  gimple_stmt_iterator gsi;
+  for (gphi_iterator gpi = gsi_start_phis (bb);
+       !gsi_end_p (gpi); gsi_next (&gpi))
+    {
+      gphi *phi = gpi.phi ();
+      if (stmt_interesting_for_vrp (phi))
+	evrp_visit_phi_node_local (phi);
+    }
+
+  /* Visit all other stmts and discover any new VRs possible.  */
+  for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+    {
+      gimple *stmt = gsi_stmt (gsi);
+      edge taken_edge;
+      tree output;
+      /* TODO, if found taken_edge, we should visit (return it) and travel
+	 again to improve VR as done in DOM/SCCVN optimizations.  It should
+	 be done carefully as stmts might prematurely leave a BB like
+	 in EH.  */
+      if (stmt_interesting_for_vrp (stmt))
+	{
+	  vrp_visit_stmt (stmt, &taken_edge, &output);
+	  if (fold_stmt (&gsi, follow_single_use_edges))
+	    update_stmt (gsi_stmt (gsi));
+	}
+    }
+  return NULL;
+}
+
+/* Restore/Pop VRs valid only for BB when we leave BB.  */
+
+void evrp_dom_walker::after_dom_children (basic_block bb ATTRIBUTE_UNUSED)
+{
+  gcc_checking_assert (!stack.is_empty ());
+  const_tree var = stack.last ().first;
+  pop_value_range (var);
+}
+
+/* Push the Value Range of VAR to the stack and upadate it with new VR.  */
+
+void evrp_dom_walker::push_value_range (const_tree var, value_range *vr)
+{
+  if  (vr != NULL)
+    {
+      unsigned ver = SSA_NAME_VERSION (var);
+      gcc_checking_assert (vr_value);
+      stack.safe_push (std::make_pair (var, vr_value[ver]));
+
+      if (ver < num_vr_values)
+	vr_value[ver] = vr;
+    }
+  else
+    stack.safe_push (std::make_pair (var, vr));
+}
+
+/* Pop the Value Range from the vrp_stack and update VAR with it.  */
+
+value_range *evrp_dom_walker::pop_value_range (const_tree var)
+{
+  value_range *vr = stack.last ().second;
+  if (vr != NULL)
+    {
+      unsigned ver = SSA_NAME_VERSION (var);
+      gcc_checking_assert (var == stack.last ().first);
+      gcc_checking_assert (vr_value);
+
+      if (ver < num_vr_values)
+	vr_value[ver] = vr;
+    }
+  stack.pop ();
+  return vr;
+}
+
+
+/* Main entry point for the early vrp pass which is a simplified non-iterative
+   version of VRP.  Value ranges discovered in early vrp will be used by ipa-vrp.  */
+
+static unsigned int
+execute_early_vrp ()
+{
+  basic_block bb;
+  edge e;
+  edge_iterator ei;
+
+  calculate_dominance_info (CDI_DOMINATORS);
+  vrp_initialize ();
+  FOR_EACH_BB_FN (bb, cfun)
+    {
+      FOR_EACH_EDGE (e, ei, bb->preds)
+	e->flags |= EDGE_EXECUTABLE;
+    }
+
+  evrp_dom_walker walker;
+  walker.walk (ENTRY_BLOCK_PTR_FOR_FN (cfun));
+
+  vrp_finalize (true, false);
+  return 0;
+}
+
 /* Main entry point to VRP (Value Range Propagation).  This pass is
    loosely based on J. R. C. Patterson, ``Accurate Static Branch
    Prediction by Value Range Propagation,'' in SIGPLAN Conference on
@@ -10270,7 +10502,7 @@ execute_vrp (bool warn_array_bounds_p)
 
   vrp_initialize ();
   ssa_propagate (vrp_visit_stmt, vrp_visit_phi_node);
-  vrp_finalize (true, warn_array_bounds_p);
+  vrp_finalize (false, warn_array_bounds_p);
 
   free_numbers_of_iterations_estimates (cfun);
 
@@ -10368,3 +10600,41 @@ make_pass_vrp (gcc::context *ctxt)
 {
   return new pass_vrp (ctxt);
 }
+
+namespace {
+
+const pass_data pass_data_early_vrp =
+{
+  GIMPLE_PASS, /* type */
+  "evrp", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_TREE_EARLY_VRP, /* tv_id */
+  PROP_ssa, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  ( TODO_cleanup_cfg | TODO_update_ssa | TODO_verify_all ),
+};
+
+class pass_early_vrp : public gimple_opt_pass
+{
+public:
+  pass_early_vrp (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_early_vrp, ctxt)
+    {}
+
+  /* opt_pass methods: */
+  opt_pass * clone () { return new pass_early_vrp (m_ctxt); }
+  virtual bool gate (function *) { return flag_tree_early_vrp != 0; }
+  virtual unsigned int execute (function *)
+    { return execute_early_vrp (); }
+
+}; // class pass_vrp
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_early_vrp (gcc::context *ctxt)
+{
+  return new pass_early_vrp (ctxt);
+}
+
-- 
1.9.1


^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Early VRP Implementation
  2016-07-26 12:27                 ` kugan
@ 2016-07-26 13:37                   ` Richard Biener
  2016-07-28  7:36                     ` kugan
  0 siblings, 1 reply; 67+ messages in thread
From: Richard Biener @ 2016-07-26 13:37 UTC (permalink / raw)
  To: kugan; +Cc: Andrew Pinski, gcc-patches, Jan Hubicka, Martin Jambor

On Tue, Jul 26, 2016 at 2:27 PM, kugan
<kugan.vivekanandarajah@linaro.org> wrote:
>
>
> Hi Riachard,
>
> Thanks for the review. Here is an updated patch with comments below.
>
>> +/* Restore/Pop all the old VRs maintained in the cond_stack.  */
>> +
>> +void evrp_dom_walker::finalize_dom_walker ()
>> +{
>> +  while (!cond_stack.is_empty ())
>> +    {
>> +      tree var = cond_stack.last ().second;
>> +      pop_value_range (var);
>> +      cond_stack.pop ();
>> +    }
>>
>> why is this necessary at all?  Looks like a waste of time (and the
>> stack should be empty here
>> anyway).  I think you leak cond_stack as well, I suppose using
>> auto_vec might work here,
>> you have to check.
>
> Done.
>
>>
>>>>
>>>> +         /* Discover VR when condition is true.  */
>>>> +         if (te == e
>>>> +             && !TREE_OVERFLOW_P (op0)
>>>> +             && !TREE_OVERFLOW_P (op1))
>>>
>>>
>>>
>>> This is mainly to handle gcc.dg/pr38934.c. This would result in ICE from
>>> set_value_range otherwise:
>>>
>>> gcc_assert ((!TREE_OVERFLOW_P (min) || is_overflow_infinity (min))
>>>                   && (!TREE_OVERFLOW_P (max) || is_overflow_infinity
>>> (max)));
>>
>>
>> Ok, instead make sure to remove the overflow flag via
>>
>>   if (TREE_OVERFLOW_P (op0))
>>     op0 = drop_tree_overflow (op0);
>
>  ...
> Done.
>
>>
>> it looks like you want to merge the if ( & EDGE_TRUE_VALUE) and
>> FALSE_VALUE
>> cases and only invert the tree comparison for the false edge.
>
> Done.
>
>>
>> +             tree cond = build2 (code, boolean_type_node, op0, op1);
>> +             extract_range_for_var_from_comparison_expr (&vr, op0, cond);
>>
>> no wasteful tree building here please.  Instead of cond pass in code,
>> op0 and op1
>> as separate arguments.
>
> Done.
>
>>
>> +         /* If we found any usable VR, set the VR to ssa_name and create
>> a
>> +            PUSH old value in the cond_stack with the old VR.  */
>> +         if (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE)
>> +           {
>> +             value_range *new_vr = vrp_value_range_pool.allocate ();
>> +             memset (new_vr, 0, sizeof (*new_vr));
>> +             *new_vr = vr;
>> +             cond_stack.safe_push (std::make_pair (bb, op0));
>>
>> the memset looks redundant given you copy-assing from vr anyway.
>
> Done.
>
>>
>> You seem to miss the chance to register ranges for x_2 in i_1 < x_2 where
>> both i_1 and x_2 might have ranges that are useful.
>
> I will address this once the basic structure is in place if that is OK with
> you.

Sure.  Just note it down somewhere.

>>
>> push and pop_value_range should be methods in the dom walker class
>> and vrp_stack and cond_stack should be a single stack.  You can omit
>> basic_block if you use a "magic" NULL_TREE var as marker (simply
>> push a NULL_TREE, NULL pair at the end of before_dom_children).
>>
> Done.
>
>
>>>>
>>>> you can use e->flags & EDGE_TRUE_VALUE/EDGE_FALSE_VALUE
>>>>
>>>> why do you need those TREE_OVERFLOW checks?
>>>>
>>>> +             tree cond = build2 (code, boolean_type_node, op0, op1);
>>>> +             tree a = build2 (ASSERT_EXPR, TREE_TYPE (op0), op0, cond);
>>>> +             extract_range_from_assert (&vr, a);
>>>>
>>>> so I was hoping that the "refactoring" patch in the series would expose
>>>> a
>>>> more
>>>> useful interface than extract_range_from_assert ... namely one that can
>>>> extract a range from the comparison directly and does not require
>>>> building
>>>> a scratch ASSERT_EXPR.
>>>
>>>
>>>
>>> I have split extract_range_from_assert into
>>> extract_range_for_var_from_comparison_expr and using it now. Is that
>>> better?
>>
>>
>> See above.
>>
>>>>
>>>>
>>>> +         /* If we found any usable VR, set the VR to ssa_name and
>>>> create
>>>> a
>>>> +            restore point in the cond_stack with the  old VR. */
>>>> +         if (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE)
>>>> +           {
>>>> +             value_range *new_vr = XCNEW (value_range);
>>>> +             *new_vr = vr;
>>>> +             cond_stack.safe_push (std::make_pair (bb,
>>>> +                                                   std::make_pair (op0,
>>>> +
>>>> old_vr)));
>>>> +             change_value_range (op0, new_vr);
>>>>
>>>> I don't like 'change_value_range' as interface, please integrate that
>>>> into
>>>> a push/pop_value_range style interface instead.
>>>
>>>
>>>
>>> Tried using push/pop interface.
>>>>
>>>>
>>>>
>>>> +       vrp_visit_stmt (stmt, &taken_edge_p, &output_p);
>>>> +    }
>>>> +
>>>> +  return NULL;
>>>>
>>>> you should return taken_edge_p (misnamed as it isn't a pointer) and take
>>>> advantage of EDGE_EXECUTABLE.  Again see DOM/SCCVN (might want to
>>>> defer this as a followup improvement).
>>>
>>>
>>>
>>> I have added a TODO to this effect and will comeback to it.
>>>>
>>>>
>>>>
>>>> Note that the advantage of a DOM-based VRP is that backtracking is easy
>>>> to implement (you don't do that yet).  That is, after DEF got a (better)
>>>> value-range you can simply re-visit all the defs of its uses (and
>>>> recursively).
>>>> I think you have to be careful with stmts that might prematurely leave a
>>>> BB
>>>> though (like via EH).  So sth for a followup as well.
>>>
>>>
>>>
>>> Is this OK now. Bootstrapped and regression tested on x86_64-linux  with
>>> no
>>> new regressions.
>>
>>
>> Better, still not perfect.
>>
>> I'm also arguing on the pass placement now - you put it where it may make
>> sense
>> for IPA VRP (but then IPA VRP could simply do this in its analysis phase)
>> but
>> not so much where it makes sense during the early pipeline.  I think it
>> makes
>> sense after FRE.
>>
>> Looking at how you finalize I see several issues with simply re-using
>> vrp_finalize.
>>
>> First of all the loop doing the set_range_info will turn up with
>> nothing as you've
>> popped off all value-ranges from the lattice.  Same for
>> substitute-and-fold (or
>> jump-threading).
>
> I am not sure understanding you. I am poping the value ranges for scope when
> we leave them. Other value ranges which lives in all the regions will
> remain.

Ah, yeah.  Sorry for the confusion.

>>
>> What you instead need to do with the DOM scheme is at the point you
>> call vrp_visit_stmt do sth like
>>
>>      vrp_visit_stmt (....);
>>      if (fold_stmt (&gsi, follow_single_use_edges))
>>        update_stmt ();
>
> I have added this. I think this will be good as we would be able to optimize
> with value ranges that is valid within the scope.

Yes, it also improves memory access locality and thus compile-time I think.

>>      tree def = SINGLE_SSA_DEF_OPERAND (stmt, SSA_OP_DEF);
>>      if (def
>>          && INTEGRAL_TYPE_P (TREE_TYPE (def))
>>          && (TREE_CODE (vr_value[i]->min) == INTEGER_CST)
>>           && (TREE_CODE (vr_value[i]->max) == INTEGER_CST)
>>           && (vr_value[i]->type == VR_RANGE
>>               || vr_value[i]->type == VR_ANTI_RANGE))
>>         set_range_info (name, vr_value[i]->type, vr_value[i]->min,
>>                         vr_value[i]->max);
>>
> I am not sure if this is needed. I dont know if my push/pop value range
> implementation is not what you wanted. If you still prefer, I am happy to
> add this.

See above, also if you fold at this point names used should have their
ranges updated so match.pd patterns can utilize them.

I see you are still calling substitute_and_fold though so if you want to
continue doing that (for now) then you don't need any of the above.
If you stop doing that then you need to supply vrp_valueize instead of
follow_single_use_edges to fold_stmt, otherwise you won't get any
constants propagated.

I'd prefer to not call substitute_and_fold as that is a function of the
SSA propagator.

>
>> thus please split vrp_finalize into two parts, one of it with the memory
>> freeing which is the one you'd call.
>>
>> Note that EVRP is not enabled by default at any optimization level
>> it seems so bootstrap / test of it would be useless (did you only
>> test with the full series?  I never looked at the IPA VRP part)
>>
> I have:
>
> +ftree-evrp
> +Common Report Var(flag_tree_early_vrp) Init(1) Optimization
> +Perform Early Value Range Propagation on trees.
>
> I would like to run this only for -O2 and above but for now I am using this
> to test.

There is an array in opts.c, default_options_table, where you can set
defaults based on the optimization level.  If you want to turn it on
at -O2 that would match the setting for -ftree-vrp in which case I would
rather not add another option.  For debugging one can use
-fdisable-tree-evrp1 for example.

+value_range *evrp_dom_walker::pop_value_range (const_tree var)
+{

coding style nit: newline missing after return type.

It seems that in your pop_value_range you assume you only pop one
range per BB - while that's likely true at the moment it will be a limitation
in the future.  You want to pop ranges until you hit the NULL marker
in after_dom_children and unconditionally push a NULL marker.

For example to match current VRPs behavior on say

   i_2 = (int) j_3;
   if (i_2 < 0)
     ...

which can register an assert for j_3 when i_2 < 0 is true we'd do that
by re-simulating DEFs of uses we figured out new ranges of (and all
their uses).  All those ranges would be temporary as well, thus they'd
need to be pushed/popped.  In my quick prototype this was done
using a worklist seeded by the names we can derive a range from from
conditionals and "SSA propagating" from it.  Note that for this
the generic vrp_visit_stmt cannot be re-used as it doesn't push/pop,
factoring out the lattice update is what is needed here.

+/* Visit the basic blocks in the dominance order and set the Value Ranges (VR)
+   for SSA_NAMEs in the scope.  Use this VR to discover more VRs.  Restore the
+   old VR once the scope is exited.  */
+
+static bool
+evrp_visit_phi_node_local (gphi *phi)
+{
+  size_t i;
+  tree lhs = PHI_RESULT (phi);
+  value_range vr_result = VR_INITIALIZER;
+  bool first = true;
+  int edges;
+
+  edges = 0;
+  for (i = 0; i < gimple_phi_num_args (phi); i++)
+    {
+      edge e = gimple_phi_arg_edge (phi, i);
+      tree arg = PHI_ARG_DEF (phi, i);
+      value_range vr_arg = VR_INITIALIZER;
+      ++edges;
+
+      /* If there is a back-edge, set the result to VARYING.  */
+      if (e->flags & (EDGE_DFS_BACK | EDGE_COMPLEX))
+       {
+         set_value_range_to_varying (&vr_result);
+         break;
+       }
...
+      /* If any of the RHS value is VARYING, set the result to VARYING.  */
+      if ((vr_arg.type != VR_RANGE)
+         && (vr_arg.type != VR_ANTI_RANGE))
+       {
+         set_value_range_to_varying (&vr_result);
+         break;
+       }

this shows that you need to start conservative for a DOM based VRP,
thus with all lattice values initialized to VARYING (but undefined SSA
names of course still can be UNDEFINED) rather than UNDEFINED.

+      if (TREE_CODE (arg) == SSA_NAME)
+       vr_arg = *(get_value_range (arg));
+      else
+       set_value_range_to_varying (&vr_arg);

err - what about constants?  When you initialize the lattice properly
you should be able to re-use vrp_visit_phi_node (maybe split out
its head to avoid using SCEV or the iteration limitation).

Btw, you don't want to call vrp_initialize in evrp either, this is setting
SSA propagator state which you do not want to do.  Please factor
out lattice allocation/deallocation instead.  I see that might require
really factoring vrp_visit_stmt into a function that omits updating
the lattice and just returns a range for the single DEF.

That said, a good refactoring is to split the SSA propagator callback
implementations (vrp_visit_stmt and vrp_visit_phi_node) into workers
returning a value range and the callback that does the update_value_range
call plus returing a SSA propgator state.  You can then re-use the worker.

Thanks,
Richard.

> I  have tested the last set of patch separately.
>
> I will do more testing on this patch based on your feedback. Does this look
> better?
>
> Thanks,
> Kugan
>
>

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Early VRP Implementation
  2016-07-26 13:37                   ` Richard Biener
@ 2016-07-28  7:36                     ` kugan
  2016-07-28 11:34                       ` Richard Biener
  0 siblings, 1 reply; 67+ messages in thread
From: kugan @ 2016-07-28  7:36 UTC (permalink / raw)
  To: Richard Biener; +Cc: Andrew Pinski, gcc-patches, Jan Hubicka, Martin Jambor

Hi Richard,

Thanks for the review.
>
> It seems that in your pop_value_range you assume you only pop one
> range per BB - while that's likely true at the moment it will be a limitation
> in the future.  You want to pop ranges until you hit the NULL marker
> in after_dom_children and unconditionally push a NULL marker.
>
I understand. Right now, I am adding only one assert based on the 
condition. But in future, we will be adding more so this is needed. I 
will do that.

> For example to match current VRPs behavior on say
>
>    i_2 = (int) j_3;
>    if (i_2 < 0)
>      ...
>
> which can register an assert for j_3 when i_2 < 0 is true we'd do that
> by re-simulating DEFs of uses we figured out new ranges of (and all
> their uses).  All those ranges would be temporary as well, thus they'd
> need to be pushed/popped.  In my quick prototype this was done
> using a worklist seeded by the names we can derive a range from from
> conditionals and "SSA propagating" from it.  Note that for this
> the generic vrp_visit_stmt cannot be re-used as it doesn't push/pop,
> factoring out the lattice update is what is needed here.
>

I dont think I understand this part. vrp_visit_stmt is going to add 
value ranges for the variables defined in the if-block (in the example 
below it is for t). If we push the value range for i_2 and j_3 when we 
enter if-block, vrp_visit_stmt should compute "t" correctly. When we 
leave the if-block, we will pop i_2 and j_3.

     i_2 = (int) j_3;
     if (i_2 < 0)
     {
       t = j_2 * 2;	
     }
Am I missing something here?

> +/* Visit the basic blocks in the dominance order and set the Value Ranges (VR)
> +   for SSA_NAMEs in the scope.  Use this VR to discover more VRs.  Restore the
> +   old VR once the scope is exited.  */
> +
> +static bool
> +evrp_visit_phi_node_local (gphi *phi)
> +{
> +  size_t i;
> +  tree lhs = PHI_RESULT (phi);
> +  value_range vr_result = VR_INITIALIZER;
> +  bool first = true;
> +  int edges;
> +
> +  edges = 0;
> +  for (i = 0; i < gimple_phi_num_args (phi); i++)
> +    {
> +      edge e = gimple_phi_arg_edge (phi, i);
> +      tree arg = PHI_ARG_DEF (phi, i);
> +      value_range vr_arg = VR_INITIALIZER;
> +      ++edges;
> +
> +      /* If there is a back-edge, set the result to VARYING.  */
> +      if (e->flags & (EDGE_DFS_BACK | EDGE_COMPLEX))
> +       {
> +         set_value_range_to_varying (&vr_result);
> +         break;
> +       }
> ...
> +      /* If any of the RHS value is VARYING, set the result to VARYING.  */
> +      if ((vr_arg.type != VR_RANGE)
> +         && (vr_arg.type != VR_ANTI_RANGE))
> +       {
> +         set_value_range_to_varying (&vr_result);
> +         break;
> +       }
>
> this shows that you need to start conservative for a DOM based VRP,
> thus with all lattice values initialized to VARYING (but undefined SSA
> names of course still can be UNDEFINED) rather than UNDEFINED.
>
> +      if (TREE_CODE (arg) == SSA_NAME)
> +       vr_arg = *(get_value_range (arg));
> +      else
> +       set_value_range_to_varying (&vr_arg);
>
> err - what about constants?  When you initialize the lattice properly
> you should be able to re-use vrp_visit_phi_node (maybe split out
> its head to avoid using SCEV or the iteration limitation).

I also like re-using vrp_visit_phi_node but the issue is, we will have 
to keep a work-list of nodes to be re-evaluated till the lattice reach a 
fixpoint. Is that OK with you?

If we are to do this, we should be able to reuse the callbacks 
vrp_visit_phi_node and vrp_visit_stmt as it is.

Do you have a reference to your DOM based prototype?

Thanks,
Kugan

> Btw, you don't want to call vrp_initialize in evrp either, this is setting
> SSA propagator state which you do not want to do.  Please factor
> out lattice allocation/deallocation instead.  I see that might require
> really factoring vrp_visit_stmt into a function that omits updating
> the lattice and just returns a range for the single DEF.
>
> That said, a good refactoring is to split the SSA propagator callback
> implementations (vrp_visit_stmt and vrp_visit_phi_node) into workers
> returning a value range and the callback that does the update_value_range
> call plus returing a SSA propgator state.  You can then re-use the worker.
>
> Thanks,
> Richard.
>
>> I  have tested the last set of patch separately.
>>
>> I will do more testing on this patch based on your feedback. Does this look
>> better?
>>
>> Thanks,
>> Kugan
>>
>>

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Early VRP Implementation
  2016-07-28  7:36                     ` kugan
@ 2016-07-28 11:34                       ` Richard Biener
  2016-08-03  1:17                         ` kugan
  0 siblings, 1 reply; 67+ messages in thread
From: Richard Biener @ 2016-07-28 11:34 UTC (permalink / raw)
  To: kugan; +Cc: Andrew Pinski, gcc-patches, Jan Hubicka, Martin Jambor

On Thu, Jul 28, 2016 at 9:35 AM, kugan
<kugan.vivekanandarajah@linaro.org> wrote:
> Hi Richard,
>
> Thanks for the review.
>>
>>
>> It seems that in your pop_value_range you assume you only pop one
>> range per BB - while that's likely true at the moment it will be a
>> limitation
>> in the future.  You want to pop ranges until you hit the NULL marker
>> in after_dom_children and unconditionally push a NULL marker.
>>
> I understand. Right now, I am adding only one assert based on the condition.
> But in future, we will be adding more so this is needed. I will do that.
>
>> For example to match current VRPs behavior on say
>>
>>    i_2 = (int) j_3;
>>    if (i_2 < 0)
>>      ...
>>
>> which can register an assert for j_3 when i_2 < 0 is true we'd do that
>> by re-simulating DEFs of uses we figured out new ranges of (and all
>> their uses).  All those ranges would be temporary as well, thus they'd
>> need to be pushed/popped.  In my quick prototype this was done
>> using a worklist seeded by the names we can derive a range from from
>> conditionals and "SSA propagating" from it.  Note that for this
>> the generic vrp_visit_stmt cannot be re-used as it doesn't push/pop,
>> factoring out the lattice update is what is needed here.
>>
>
> I dont think I understand this part. vrp_visit_stmt is going to add value
> ranges for the variables defined in the if-block (in the example below it is
> for t). If we push the value range for i_2 and j_3 when we enter if-block,
> vrp_visit_stmt should compute "t" correctly. When we leave the if-block, we
> will pop i_2 and j_3.
>
>     i_2 = (int) j_3;
>     if (i_2 < 0)
>     {
>       t = j_2 * 2;
>     }
> Am I missing something here?

It works if you push the old value before calling vrp_visit_stmt, yes.
But I think
you want to do that only if the value-range changed to avoid too many changes
on the stack.  I guess we can defer further refactoring and
optimization of this case
to the point where we consider looking back very aggressively.

>> +/* Visit the basic blocks in the dominance order and set the Value Ranges
>> (VR)
>> +   for SSA_NAMEs in the scope.  Use this VR to discover more VRs.
>> Restore the
>> +   old VR once the scope is exited.  */
>> +
>> +static bool
>> +evrp_visit_phi_node_local (gphi *phi)
>> +{
>> +  size_t i;
>> +  tree lhs = PHI_RESULT (phi);
>> +  value_range vr_result = VR_INITIALIZER;
>> +  bool first = true;
>> +  int edges;
>> +
>> +  edges = 0;
>> +  for (i = 0; i < gimple_phi_num_args (phi); i++)
>> +    {
>> +      edge e = gimple_phi_arg_edge (phi, i);
>> +      tree arg = PHI_ARG_DEF (phi, i);
>> +      value_range vr_arg = VR_INITIALIZER;
>> +      ++edges;
>> +
>> +      /* If there is a back-edge, set the result to VARYING.  */
>> +      if (e->flags & (EDGE_DFS_BACK | EDGE_COMPLEX))
>> +       {
>> +         set_value_range_to_varying (&vr_result);
>> +         break;
>> +       }
>> ...
>> +      /* If any of the RHS value is VARYING, set the result to VARYING.
>> */
>> +      if ((vr_arg.type != VR_RANGE)
>> +         && (vr_arg.type != VR_ANTI_RANGE))
>> +       {
>> +         set_value_range_to_varying (&vr_result);
>> +         break;
>> +       }
>>
>> this shows that you need to start conservative for a DOM based VRP,
>> thus with all lattice values initialized to VARYING (but undefined SSA
>> names of course still can be UNDEFINED) rather than UNDEFINED.
>>
>> +      if (TREE_CODE (arg) == SSA_NAME)
>> +       vr_arg = *(get_value_range (arg));
>> +      else
>> +       set_value_range_to_varying (&vr_arg);
>>
>> err - what about constants?  When you initialize the lattice properly
>> you should be able to re-use vrp_visit_phi_node (maybe split out
>> its head to avoid using SCEV or the iteration limitation).
>
>
> I also like re-using vrp_visit_phi_node but the issue is, we will have to
> keep a work-list of nodes to be re-evaluated till the lattice reach a
> fixpoint. Is that OK with you?

No, why would you need to iterate here?  As said, the key point is to
initialize value-ranges as VARYING rather than UNDEFINED.

> If we are to do this, we should be able to reuse the callbacks
> vrp_visit_phi_node and vrp_visit_stmt as it is.
>
> Do you have a reference to your DOM based prototype?

I never posted it I think, it's structure is similar to yours with lots
of ??? comments ;)

Richard.

> Thanks,
> Kugan
>
>
>> Btw, you don't want to call vrp_initialize in evrp either, this is setting
>> SSA propagator state which you do not want to do.  Please factor
>> out lattice allocation/deallocation instead.  I see that might require
>> really factoring vrp_visit_stmt into a function that omits updating
>> the lattice and just returns a range for the single DEF.
>>
>> That said, a good refactoring is to split the SSA propagator callback
>> implementations (vrp_visit_stmt and vrp_visit_phi_node) into workers
>> returning a value range and the callback that does the update_value_range
>> call plus returing a SSA propgator state.  You can then re-use the worker.
>>
>> Thanks,
>> Richard.
>>
>>> I  have tested the last set of patch separately.
>>>
>>> I will do more testing on this patch based on your feedback. Does this
>>> look
>>> better?
>>>
>>> Thanks,
>>> Kugan
>>>
>>>
>

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Early VRP Implementation
  2016-07-28 11:34                       ` Richard Biener
@ 2016-08-03  1:17                         ` kugan
  2016-08-12 10:43                           ` Richard Biener
  0 siblings, 1 reply; 67+ messages in thread
From: kugan @ 2016-08-03  1:17 UTC (permalink / raw)
  To: Richard Biener; +Cc: Andrew Pinski, gcc-patches, Jan Hubicka, Martin Jambor

[-- Attachment #1: Type: text/plain, Size: 5286 bytes --]

Hi Richard,

Thanks for the review.

On 28/07/16 21:34, Richard Biener wrote:
> On Thu, Jul 28, 2016 at 9:35 AM, kugan
> <kugan.vivekanandarajah@linaro.org> wrote:
>> Hi Richard,
>>
>> Thanks for the review.
>>>
>>>
>>> It seems that in your pop_value_range you assume you only pop one
>>> range per BB - while that's likely true at the moment it will be a
>>> limitation
>>> in the future.  You want to pop ranges until you hit the NULL marker
>>> in after_dom_children and unconditionally push a NULL marker.
>>>
>> I understand. Right now, I am adding only one assert based on the condition.
>> But in future, we will be adding more so this is needed. I will do that.
>>
>>> For example to match current VRPs behavior on say
>>>
>>>    i_2 = (int) j_3;
>>>    if (i_2 < 0)
>>>      ...
>>>
>>> which can register an assert for j_3 when i_2 < 0 is true we'd do that
>>> by re-simulating DEFs of uses we figured out new ranges of (and all
>>> their uses).  All those ranges would be temporary as well, thus they'd
>>> need to be pushed/popped.  In my quick prototype this was done
>>> using a worklist seeded by the names we can derive a range from from
>>> conditionals and "SSA propagating" from it.  Note that for this
>>> the generic vrp_visit_stmt cannot be re-used as it doesn't push/pop,
>>> factoring out the lattice update is what is needed here.
>>>
>>
>> I dont think I understand this part. vrp_visit_stmt is going to add value
>> ranges for the variables defined in the if-block (in the example below it is
>> for t). If we push the value range for i_2 and j_3 when we enter if-block,
>> vrp_visit_stmt should compute "t" correctly. When we leave the if-block, we
>> will pop i_2 and j_3.
>>
>>     i_2 = (int) j_3;
>>     if (i_2 < 0)
>>     {
>>       t = j_2 * 2;
>>     }
>> Am I missing something here?
>
> It works if you push the old value before calling vrp_visit_stmt, yes.
> But I think
> you want to do that only if the value-range changed to avoid too many changes
> on the stack.  I guess we can defer further refactoring and
> optimization of this case
> to the point where we consider looking back very aggressively.
>
>>> +/* Visit the basic blocks in the dominance order and set the Value Ranges
>>> (VR)
>>> +   for SSA_NAMEs in the scope.  Use this VR to discover more VRs.
>>> Restore the
>>> +   old VR once the scope is exited.  */
>>> +
>>> +static bool
>>> +evrp_visit_phi_node_local (gphi *phi)
>>> +{
>>> +  size_t i;
>>> +  tree lhs = PHI_RESULT (phi);
>>> +  value_range vr_result = VR_INITIALIZER;
>>> +  bool first = true;
>>> +  int edges;
>>> +
>>> +  edges = 0;
>>> +  for (i = 0; i < gimple_phi_num_args (phi); i++)
>>> +    {
>>> +      edge e = gimple_phi_arg_edge (phi, i);
>>> +      tree arg = PHI_ARG_DEF (phi, i);
>>> +      value_range vr_arg = VR_INITIALIZER;
>>> +      ++edges;
>>> +
>>> +      /* If there is a back-edge, set the result to VARYING.  */
>>> +      if (e->flags & (EDGE_DFS_BACK | EDGE_COMPLEX))
>>> +       {
>>> +         set_value_range_to_varying (&vr_result);
>>> +         break;
>>> +       }
>>> ...
>>> +      /* If any of the RHS value is VARYING, set the result to VARYING.
>>> */
>>> +      if ((vr_arg.type != VR_RANGE)
>>> +         && (vr_arg.type != VR_ANTI_RANGE))
>>> +       {
>>> +         set_value_range_to_varying (&vr_result);
>>> +         break;
>>> +       }
>>>
>>> this shows that you need to start conservative for a DOM based VRP,
>>> thus with all lattice values initialized to VARYING (but undefined SSA
>>> names of course still can be UNDEFINED) rather than UNDEFINED.
>>>
>>> +      if (TREE_CODE (arg) == SSA_NAME)
>>> +       vr_arg = *(get_value_range (arg));
>>> +      else
>>> +       set_value_range_to_varying (&vr_arg);
>>>
>>> err - what about constants?  When you initialize the lattice properly
>>> you should be able to re-use vrp_visit_phi_node (maybe split out
>>> its head to avoid using SCEV or the iteration limitation).
>>
>>
>> I also like re-using vrp_visit_phi_node but the issue is, we will have to
>> keep a work-list of nodes to be re-evaluated till the lattice reach a
>> fixpoint. Is that OK with you?
>
> No, why would you need to iterate here?  As said, the key point is to
> initialize value-ranges as VARYING rather than UNDEFINED.
>
>> If we are to do this, we should be able to reuse the callbacks
>> vrp_visit_phi_node and vrp_visit_stmt as it is.
>>
>> Do you have a reference to your DOM based prototype?
>
> I never posted it I think, it's structure is similar to yours with lots
> of ??? comments ;)
>


Here is an updated patch which addresses the earlier review comments.

Just to see the effectiveness of this, I did a simple test.

That is, I built gcc with --enable-languages=c,c++ --disable-bootstrap 
--disable-multilib and added -fdump-ipa-cp to the compiler flag and 
grepped for number of times ipa-vrp (with the ipa-vrp patch) is setting 
the value range for argument. I also did the same with tree-vrp used in 
place of tree-evrp as an early vrp. tree-evrp is setting 186 times 
compared to tree-vrp which is setting 207 times. I didn't see the actual 
value ranges which can also make lots of difference.

In future we might want to iterate on dom based vrp till fixed point is 
reached if there is a need.

Thanks,
Kugan



[-- Attachment #2: 0005-Add-Early-VRP.patch --]
[-- Type: text/x-patch, Size: 44177 bytes --]

From 17ea87a0e47a0d2325376d6a66a3ff1d5d70c0b4 Mon Sep 17 00:00:00 2001
From: Kugan Vivekanandarajah <kugan.vivekanandarajah@linaro.org>
Date: Fri, 29 Jul 2016 21:37:20 +1000
Subject: [PATCH 5/7] Add Early VRP

---
 gcc/common.opt                            |   4 +
 gcc/doc/invoke.texi                       |   9 +
 gcc/passes.def                            |   1 +
 gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C |   2 +-
 gcc/testsuite/gcc.dg/tree-ssa/evrp1.c     |  13 +
 gcc/testsuite/gcc.dg/tree-ssa/evrp2.c     |  18 +
 gcc/testsuite/gcc.dg/tree-ssa/evrp3.c     |  15 +
 gcc/testsuite/gcc.dg/tree-ssa/pr20318.c   |   4 +-
 gcc/testsuite/gcc.dg/tree-ssa/pr22117.c   |   2 +-
 gcc/testsuite/gcc.dg/tree-ssa/pr25382.c   |   2 +-
 gcc/testsuite/gcc.dg/tree-ssa/vrp24.c     |   5 +-
 gcc/testsuite/gcc.dg/tree-ssa/vrp58.c     |   4 +-
 gcc/timevar.def                           |   1 +
 gcc/tree-pass.h                           |   1 +
 gcc/tree-vrp.c                            | 578 ++++++++++++++++++++++++------
 15 files changed, 540 insertions(+), 119 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/evrp1.c
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/evrp2.c
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/evrp3.c

diff --git a/gcc/common.opt b/gcc/common.opt
index 8a292ed..7028cd4 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2482,6 +2482,10 @@ ftree-vrp
 Common Report Var(flag_tree_vrp) Init(0) Optimization
 Perform Value Range Propagation on trees.
 
+fdisable-tree-evrp
+Common Report Var(flag_disable_early_vrp) Init(0) Optimization
+Disable Early Value Range Propagation on trees.
+
 fsplit-paths
 Common Report Var(flag_split_paths) Init(0) Optimization
 Split paths leading to loop backedges.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 22001f9..1d4910b 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -7715,6 +7715,10 @@ enabled by default at @option{-O2} and higher.  Null pointer check
 elimination is only done if @option{-fdelete-null-pointer-checks} is
 enabled.
 
+@item -fdisable-tree-evrp
+@opindex fdisable-tree-evrp
+Disables Early Value Range Propagation on trees.
+
 @item -fsplit-paths
 @opindex fsplit-paths
 Split paths leading to loop backedges.  This can improve dead code
@@ -12338,6 +12342,11 @@ is made by appending @file{.slp} to the source file name.
 Dump each function after Value Range Propagation (VRP).  The file name
 is made by appending @file{.vrp} to the source file name.
 
+@item early vrp
+@opindex fdump-tree-evrp
+Dump each function after Early Value Range Propagation (EVRP).  The file name
+is made by appending @file{.evrp} to the source file name.
+
 @item oaccdevlow
 @opindex fdump-tree-oaccdevlow
 Dump each function after applying device-specific OpenACC transformations.
diff --git a/gcc/passes.def b/gcc/passes.def
index 3647e90..ebd360b 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -89,6 +89,7 @@ along with GCC; see the file COPYING3.  If not see
 	     execute TODO_rebuild_alias at this point.  */
 	  NEXT_PASS (pass_build_ealias);
 	  NEXT_PASS (pass_fre);
+	  NEXT_PASS (pass_early_vrp);
 	  NEXT_PASS (pass_merge_phi);
           NEXT_PASS (pass_dse);
 	  NEXT_PASS (pass_cd_dce);
diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C b/gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C
index 5e09583..dce05d6 100644
--- a/gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C
+++ b/gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O -fdump-tree-forwprop1" } */
+/* { dg-options "-O -fno-tree-evrp -fdump-tree-forwprop1" } */
 
 #include <new>
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/evrp1.c b/gcc/testsuite/gcc.dg/tree-ssa/evrp1.c
new file mode 100644
index 0000000..8c6e4e6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/evrp1.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+int foo (int i);
+int bar (int j)
+{
+  if (j > 2)
+    return foo (j + 2);
+  else
+    return j;
+}
+
+/* { dg-final { scan-tree-dump "\\\[5, \\+INF" "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/evrp2.c b/gcc/testsuite/gcc.dg/tree-ssa/evrp2.c
new file mode 100644
index 0000000..e6d4235
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/evrp2.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+int foo (int i);
+int bar2 (int j)
+{
+  if (j > 2)
+    {
+      if (j < 7)
+	return foo (j + 1);
+      else
+	return foo (j + 2);
+    }
+  return j;
+}
+
+
+/* { dg-final { scan-tree-dump "\\\[4, 7\\\]" "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/evrp3.c b/gcc/testsuite/gcc.dg/tree-ssa/evrp3.c
new file mode 100644
index 0000000..1a3bbd5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/evrp3.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+int foo (int i);
+void bar (int j)
+{
+  unsigned int i;
+  for (i = 0; i < 10; ++i)
+    {
+      bar (i + 1);
+    }
+}
+
+/* { dg-final { scan-tree-dump "\\\[1, 10\\\]" "evrp" } } */
+
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr20318.c b/gcc/testsuite/gcc.dg/tree-ssa/pr20318.c
index 41f569e..6f95920 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr20318.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr20318.c
@@ -1,5 +1,5 @@
 /* { dg-do compile { target { ! keeps_null_pointer_checks } } } */
-/* { dg-options "-O2 -fdump-tree-original -fdump-tree-vrp1 -fdelete-null-pointer-checks" } */
+/* { dg-options "-O2 -fdump-tree-original -fdump-tree-vrp  -fdelete-null-pointer-checks" } */
 
 extern int* f(int) __attribute__((returns_nonnull));
 extern void eliminate ();
@@ -14,4 +14,4 @@ void h () {
 }
 
 /* { dg-final { scan-tree-dump-times "== 0" 1 "original" } } */
-/* { dg-final { scan-tree-dump-times "Folding predicate\[^\\n\]*to 0" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "Folding predicate\[^\\n\]*to 0" 1 "vrp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c b/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c
index 7efdd63..43cea0b 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c
@@ -3,7 +3,7 @@
    known to be zero after entering the first two "if" statements.  */
 
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1" } */
+/* { dg-options "-O2 -fno-tree-evrp -fdump-tree-vrp" } */
 
 void link_error (void);
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c b/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c
index dcf9148..c4fda8b 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c
@@ -3,7 +3,7 @@
    Check that VRP now gets ranges from BIT_AND_EXPRs.  */
 
 /* { dg-do compile } */
-/* { dg-options "-O2 -fno-tree-ccp -fdump-tree-vrp1" } */
+/* { dg-options "-O2 -fno-tree-ccp -fdump-tree-vrp" } */
 
 int
 foo (int a)
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp24.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp24.c
index e740575..7da577b 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp24.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp24.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1-details" } */
+/* { dg-options "-O2 -fdump-tree-evrp-details -fdump-tree-vrp1-details" } */
 
 
 struct rtx_def;
@@ -91,5 +91,6 @@ L7:
    The second n_sets > 0 test can also be simplified into n_sets == 1
    as the only way to reach the tests is when n_sets <= 1 and the only
    value which satisfies both conditions is n_sets == 1.  */
-/* { dg-final { scan-tree-dump-times "Simplified relational" 2 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "Simplified relational" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "Simplified relational" 1 "vrp1" } } */
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp58.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp58.c
index 5b44ae2..6df91ca 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp58.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp58.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1-details" } */
+/* { dg-options "-O2 -fdump-tree-evrp-details" } */
 
 long long
 foo (long long a, signed char b, signed char c)
@@ -9,4 +9,4 @@ foo (long long a, signed char b, signed char c)
 }
 
 /* { dg-final { scan-tree-dump "Folded into" "vrp1" { target int32plus } } } */
-/* { dg-final { scan-tree-dump "Folding statement: _\[0-9\]\* = \\(long long int\\) bc_\[0-9\]\*;" "vrp1" { target int16 } } } */
+/* { dg-final { scan-tree-dump "Folding statement: _\[0-9\]\* = \\(long long int\\) bc_\[0-9\]\*;" "evrp" { target int16 } } } */
diff --git a/gcc/timevar.def b/gcc/timevar.def
index 5f12118..8837832 100644
--- a/gcc/timevar.def
+++ b/gcc/timevar.def
@@ -149,6 +149,7 @@ DEFTIMEVAR (TV_TREE_CFG		     , "tree CFG construction")
 DEFTIMEVAR (TV_TREE_CLEANUP_CFG	     , "tree CFG cleanup")
 DEFTIMEVAR (TV_TREE_TAIL_MERGE       , "tree tail merge")
 DEFTIMEVAR (TV_TREE_VRP              , "tree VRP")
+DEFTIMEVAR (TV_TREE_EARLY_VRP        , "tree Early VRP")
 DEFTIMEVAR (TV_TREE_COPY_PROP        , "tree copy propagation")
 DEFTIMEVAR (TV_FIND_REFERENCED_VARS  , "tree find ref. vars")
 DEFTIMEVAR (TV_TREE_PTA		     , "tree PTA")
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index 36299a6..d836d57 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -440,6 +440,7 @@ extern gimple_opt_pass *make_pass_fre (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_check_data_deps (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_copy_prop (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_isolate_erroneous_paths (gcc::context *ctxt);
+extern gimple_opt_pass *make_pass_early_vrp (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_vrp (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_uncprop (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_return_slot (gcc::context *ctxt);
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index 4127e2e..b90d9571 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -1438,44 +1438,17 @@ op_with_boolean_value_range_p (tree op)
 	  && integer_onep (vr->max));
 }
 
-/* Extract value range information from an ASSERT_EXPR EXPR and store
-   it in *VR_P.  */
+/* Extract value range information for VAR when (OP COND_CODE LIMIT) is
+   true and store it in *VR_P.  */
 
 static void
-extract_range_from_assert (value_range *vr_p, tree expr)
+extract_range_for_var_from_comparison_expr (tree var, enum tree_code cond_code,
+					    tree op, tree limit,
+					    value_range *vr_p)
 {
-  tree var, cond, limit, min, max, type;
+  tree  min, max, type;
   value_range *limit_vr;
-  enum tree_code cond_code;
-
-  var = ASSERT_EXPR_VAR (expr);
-  cond = ASSERT_EXPR_COND (expr);
-
-  gcc_assert (COMPARISON_CLASS_P (cond));
-
-  /* Find VAR in the ASSERT_EXPR conditional.  */
-  if (var == TREE_OPERAND (cond, 0)
-      || TREE_CODE (TREE_OPERAND (cond, 0)) == PLUS_EXPR
-      || TREE_CODE (TREE_OPERAND (cond, 0)) == NOP_EXPR)
-    {
-      /* If the predicate is of the form VAR COMP LIMIT, then we just
-	 take LIMIT from the RHS and use the same comparison code.  */
-      cond_code = TREE_CODE (cond);
-      limit = TREE_OPERAND (cond, 1);
-      cond = TREE_OPERAND (cond, 0);
-    }
-  else
-    {
-      /* If the predicate is of the form LIMIT COMP VAR, then we need
-	 to flip around the comparison code to create the proper range
-	 for VAR.  */
-      cond_code = swap_tree_comparison (TREE_CODE (cond));
-      limit = TREE_OPERAND (cond, 0);
-      cond = TREE_OPERAND (cond, 1);
-    }
-
   limit = avoid_overflow_infinity (limit);
-
   type = TREE_TYPE (var);
   gcc_assert (limit != var);
 
@@ -1521,15 +1494,15 @@ extract_range_from_assert (value_range *vr_p, tree expr)
      as well build the range [b_4, +INF] for it.
      One special case we handle is extracting a range from a
      range test encoded as (unsigned)var + CST <= limit.  */
-  if (TREE_CODE (cond) == NOP_EXPR
-      || TREE_CODE (cond) == PLUS_EXPR)
+  if (TREE_CODE (op) == NOP_EXPR
+      || TREE_CODE (op) == PLUS_EXPR)
     {
-      if (TREE_CODE (cond) == PLUS_EXPR)
+      if (TREE_CODE (op) == PLUS_EXPR)
         {
-          min = fold_build1 (NEGATE_EXPR, TREE_TYPE (TREE_OPERAND (cond, 1)),
-			     TREE_OPERAND (cond, 1));
+	  min = fold_build1 (NEGATE_EXPR, TREE_TYPE (TREE_OPERAND (op, 1)),
+			     TREE_OPERAND (op, 1));
           max = int_const_binop (PLUS_EXPR, limit, min);
-	  cond = TREE_OPERAND (cond, 0);
+	  op = TREE_OPERAND (op, 0);
 	}
       else
 	{
@@ -1713,6 +1686,41 @@ extract_range_from_assert (value_range *vr_p, tree expr)
   vrp_intersect_ranges (vr_p, get_value_range (var));
 }
 
+/* Extract value range information from an ASSERT_EXPR EXPR and store
+   it in *VR_P.  */
+
+static void
+extract_range_from_assert (value_range *vr_p, tree expr)
+{
+  tree var = ASSERT_EXPR_VAR (expr);
+  tree cond = ASSERT_EXPR_COND (expr);
+  tree limit, op;
+  enum tree_code cond_code;
+  gcc_assert (COMPARISON_CLASS_P (cond));
+
+  /* Find VAR in the ASSERT_EXPR conditional.  */
+  if (var == TREE_OPERAND (cond, 0)
+      || TREE_CODE (TREE_OPERAND (cond, 0)) == PLUS_EXPR
+      || TREE_CODE (TREE_OPERAND (cond, 0)) == NOP_EXPR)
+    {
+      /* If the predicate is of the form VAR COMP LIMIT, then we just
+	 take LIMIT from the RHS and use the same comparison code.  */
+      cond_code = TREE_CODE (cond);
+      limit = TREE_OPERAND (cond, 1);
+      op = TREE_OPERAND (cond, 0);
+    }
+  else
+    {
+      /* If the predicate is of the form LIMIT COMP VAR, then we need
+	 to flip around the comparison code to create the proper range
+	 for VAR.  */
+      cond_code = swap_tree_comparison (TREE_CODE (cond));
+      limit = TREE_OPERAND (cond, 0);
+      op = TREE_OPERAND (cond, 1);
+    }
+  extract_range_for_var_from_comparison_expr (var, cond_code, op,
+					      limit, vr_p);
+}
 
 /* Extract range information from SSA name VAR and store it in VR.  If
    VAR has an interesting range, use it.  Otherwise, create the
@@ -1728,11 +1736,12 @@ extract_range_from_assert (value_range *vr_p, tree expr)
     always false.  */
 
 static void
-extract_range_from_ssa_name (value_range *vr, tree var)
+extract_range_from_ssa_name (value_range *vr, bool dom_p, tree var)
 {
   value_range *var_vr = get_value_range (var);
 
-  if (var_vr->type != VR_VARYING)
+  if (var_vr->type != VR_VARYING
+      && (!dom_p || var_vr->type != VR_UNDEFINED))
     copy_value_range (vr, var_vr);
   else
     set_value_range (vr, VR_RANGE, var, var, NULL);
@@ -2136,6 +2145,7 @@ extract_range_from_multiplicative_op_1 (value_range *vr,
 
 static void
 extract_range_from_binary_expr_1 (value_range *vr,
+				  bool dom_p,
 				  enum tree_code code, tree expr_type,
 				  value_range *vr0_, value_range *vr1_)
 {
@@ -2152,6 +2162,15 @@ extract_range_from_binary_expr_1 (value_range *vr,
       return;
     }
 
+  /* If we are in dom based non iterative VRP and any of the input is
+     VR_UNDEGFINED, set the resylt to VR_VARYING.  */
+  if (dom_p
+      && (vr0.type == VR_UNDEFINED || vr1.type == VR_UNDEFINED))
+    {
+      set_value_range_to_varying (vr);
+      return;
+    }
+
   /* Not all binary expressions can be applied to ranges in a
      meaningful way.  Handle only arithmetic operations.  */
   if (code != PLUS_EXPR
@@ -2196,11 +2215,12 @@ extract_range_from_binary_expr_1 (value_range *vr,
   if (vr0.type == VR_ANTI_RANGE
       && ranges_from_anti_range (&vr0, &vrtem0, &vrtem1))
     {
-      extract_range_from_binary_expr_1 (vr, code, expr_type, &vrtem0, vr1_);
+      extract_range_from_binary_expr_1 (vr, dom_p, code, expr_type,
+					&vrtem0, vr1_);
       if (vrtem1.type != VR_UNDEFINED)
 	{
 	  value_range vrres = VR_INITIALIZER;
-	  extract_range_from_binary_expr_1 (&vrres, code, expr_type,
+	  extract_range_from_binary_expr_1 (&vrres, dom_p, code, expr_type,
 					    &vrtem1, vr1_);
 	  vrp_meet (vr, &vrres);
 	}
@@ -2210,11 +2230,12 @@ extract_range_from_binary_expr_1 (value_range *vr,
   if (vr1.type == VR_ANTI_RANGE
       && ranges_from_anti_range (&vr1, &vrtem0, &vrtem1))
     {
-      extract_range_from_binary_expr_1 (vr, code, expr_type, vr0_, &vrtem0);
+      extract_range_from_binary_expr_1 (vr, dom_p, code, expr_type,
+					vr0_, &vrtem0);
       if (vrtem1.type != VR_UNDEFINED)
 	{
 	  value_range vrres = VR_INITIALIZER;
-	  extract_range_from_binary_expr_1 (&vrres, code, expr_type,
+	  extract_range_from_binary_expr_1 (&vrres, dom_p, code, expr_type,
 					    vr0_, &vrtem1);
 	  vrp_meet (vr, &vrres);
 	}
@@ -2769,7 +2790,7 @@ extract_range_from_binary_expr_1 (value_range *vr,
 		 on lshifts is implementation defined in C89.  */
 	      saved_flag_wrapv = flag_wrapv;
 	      flag_wrapv = 1;
-	      extract_range_from_binary_expr_1 (vr, MULT_EXPR, expr_type,
+	      extract_range_from_binary_expr_1 (vr, dom_p, MULT_EXPR, expr_type,
 						&vr0, &vr1p);
 	      flag_wrapv = saved_flag_wrapv;
 	      return;
@@ -3154,6 +3175,7 @@ extract_range_from_binary_expr_1 (value_range *vr,
 
 static void
 extract_range_from_binary_expr (value_range *vr,
+				bool dom_p,
 				enum tree_code code,
 				tree expr_type, tree op0, tree op1)
 {
@@ -3176,7 +3198,7 @@ extract_range_from_binary_expr (value_range *vr,
   else
     set_value_range_to_varying (&vr1);
 
-  extract_range_from_binary_expr_1 (vr, code, expr_type, &vr0, &vr1);
+  extract_range_from_binary_expr_1 (vr, dom_p, code, expr_type, &vr0, &vr1);
 
   /* Try harder for PLUS and MINUS if the range of one operand is symbolic
      and based on the other operand, for example if it was deduced from a
@@ -3204,7 +3226,8 @@ extract_range_from_binary_expr (value_range *vr,
       else
 	set_value_range (&n_vr1, VR_RANGE, op1, op1, NULL);
 
-      extract_range_from_binary_expr_1 (vr, code, expr_type, &vr0, &n_vr1);
+      extract_range_from_binary_expr_1 (vr, dom_p, code, expr_type,
+					&vr0, &n_vr1);
     }
 
   if (vr->type == VR_VARYING
@@ -3228,7 +3251,8 @@ extract_range_from_binary_expr (value_range *vr,
       else
 	set_value_range (&n_vr0, VR_RANGE, op0, op0, NULL);
 
-      extract_range_from_binary_expr_1 (vr, code, expr_type, &n_vr0, &vr1);
+      extract_range_from_binary_expr_1 (vr, dom_p, code, expr_type,
+					&n_vr0, &vr1);
     }
 }
 
@@ -3238,6 +3262,7 @@ extract_range_from_binary_expr (value_range *vr,
 
 static void
 extract_range_from_unary_expr_1 (value_range *vr,
+				 bool dom_p,
 				 enum tree_code code, tree type,
 				 value_range *vr0_, tree op0_type)
 {
@@ -3253,6 +3278,14 @@ extract_range_from_unary_expr_1 (value_range *vr,
       return;
     }
 
+  /* If we are in dom based non iterative VRP and the input is
+     VR_UNDEGFINED, set the resylt to VR_VARYING.  */
+  if (dom_p && vr0.type == VR_UNDEFINED)
+    {
+      set_value_range_to_varying (vr);
+      return;
+    }
+
   /* If VR0 is UNDEFINED, so is the result.  */
   if (vr0.type == VR_UNDEFINED)
     {
@@ -3273,7 +3306,8 @@ extract_range_from_unary_expr_1 (value_range *vr,
          anti-ranges fine.  */
       value_range zero = VR_INITIALIZER;
       set_value_range_to_value (&zero, build_int_cst (type, 0), NULL);
-      extract_range_from_binary_expr_1 (vr, MINUS_EXPR, type, &zero, &vr0);
+      extract_range_from_binary_expr_1 (vr, dom_p, MINUS_EXPR,
+					type, &zero, &vr0);
       return;
     }
   else if (code == BIT_NOT_EXPR)
@@ -3282,7 +3316,7 @@ extract_range_from_unary_expr_1 (value_range *vr,
          anti-ranges fine.  */
       value_range minusone = VR_INITIALIZER;
       set_value_range_to_value (&minusone, build_int_cst (type, -1), NULL);
-      extract_range_from_binary_expr_1 (vr, MINUS_EXPR,
+      extract_range_from_binary_expr_1 (vr, dom_p, MINUS_EXPR,
 					type, &minusone, &vr0);
       return;
     }
@@ -3292,12 +3326,13 @@ extract_range_from_unary_expr_1 (value_range *vr,
   if (vr0.type == VR_ANTI_RANGE
       && ranges_from_anti_range (&vr0, &vrtem0, &vrtem1))
     {
-      extract_range_from_unary_expr_1 (vr, code, type, &vrtem0, op0_type);
+      extract_range_from_unary_expr_1 (vr, dom_p, code, type,
+				       &vrtem0, op0_type);
       if (vrtem1.type != VR_UNDEFINED)
 	{
 	  value_range vrres = VR_INITIALIZER;
-	  extract_range_from_unary_expr_1 (&vrres, code, type,
-					   &vrtem1, op0_type);
+	  extract_range_from_unary_expr_1 (&vrres, dom_p, code,
+					   type, &vrtem1, op0_type);
 	  vrp_meet (vr, &vrres);
 	}
       return;
@@ -3538,7 +3573,9 @@ extract_range_from_unary_expr_1 (value_range *vr,
    The resulting range is stored in *VR.  */
 
 static void
-extract_range_from_unary_expr (value_range *vr, enum tree_code code,
+extract_range_from_unary_expr (value_range *vr,
+			       bool dom_p,
+			       enum tree_code code,
 			       tree type, tree op0)
 {
   value_range vr0 = VR_INITIALIZER;
@@ -3552,7 +3589,8 @@ extract_range_from_unary_expr (value_range *vr, enum tree_code code,
   else
     set_value_range_to_varying (&vr0);
 
-  extract_range_from_unary_expr_1 (vr, code, type, &vr0, TREE_TYPE (op0));
+  extract_range_from_unary_expr_1 (vr, dom_p, code, type,
+				   &vr0, TREE_TYPE (op0));
 }
 
 
@@ -3560,7 +3598,9 @@ extract_range_from_unary_expr (value_range *vr, enum tree_code code,
    the ranges of each of its operands and the expression code.  */
 
 static void
-extract_range_from_cond_expr (value_range *vr, gassign *stmt)
+extract_range_from_cond_expr (value_range *vr,
+			      bool dom_p,
+			      gassign *stmt)
 {
   tree op0, op1;
   value_range vr0 = VR_INITIALIZER;
@@ -3584,6 +3624,15 @@ extract_range_from_cond_expr (value_range *vr, gassign *stmt)
   else
     set_value_range_to_varying (&vr1);
 
+  /* If we are in dom based non iterative VRP and any of the input is
+     VR_UNDEGFINED, set the resylt to VR_VARYING.  */
+  if (dom_p
+      && (vr0.type == VR_UNDEFINED || vr1.type == VR_UNDEFINED))
+    {
+      set_value_range_to_varying (vr);
+      return;
+    }
+
   /* The resulting value range is the union of the operand ranges */
   copy_value_range (vr, &vr0);
   vrp_meet (vr, &vr1);
@@ -3594,7 +3643,8 @@ extract_range_from_cond_expr (value_range *vr, gassign *stmt)
    on the range of its operand and the expression code.  */
 
 static void
-extract_range_from_comparison (value_range *vr, enum tree_code code,
+extract_range_from_comparison (value_range *vr,
+			       enum tree_code code,
 			       tree type, tree op0, tree op1)
 {
   bool sop = false;
@@ -3631,7 +3681,8 @@ extract_range_from_comparison (value_range *vr, enum tree_code code,
    overflow.  */
 
 static bool
-check_for_binary_op_overflow (enum tree_code subcode, tree type,
+check_for_binary_op_overflow (enum tree_code subcode,
+			      tree type,
 			      tree op0, tree op1, bool *ovf)
 {
   value_range vr0 = VR_INITIALIZER;
@@ -3736,7 +3787,9 @@ check_for_binary_op_overflow (enum tree_code subcode, tree type,
    Store the result in *VR */
 
 static void
-extract_range_basic (value_range *vr, gimple *stmt)
+extract_range_basic (value_range *vr,
+		     bool dom_p,
+		     gimple *stmt)
 {
   bool sop = false;
   tree type = gimple_expr_type (stmt);
@@ -3960,7 +4013,7 @@ extract_range_basic (value_range *vr, gimple *stmt)
 	     any overflow, we'll complain, but will actually do
 	     wrapping operation.  */
 	  flag_wrapv = 1;
-	  extract_range_from_binary_expr (vr, subcode, type,
+	  extract_range_from_binary_expr (vr, dom_p, subcode, type,
 					  gimple_call_arg (stmt, 0),
 					  gimple_call_arg (stmt, 1));
 	  flag_wrapv = saved_flag_wrapv;
@@ -4032,7 +4085,7 @@ extract_range_basic (value_range *vr, gimple *stmt)
 		      /* Pretend the arithmetics is wrapping.  If there is
 			 any overflow, IMAGPART_EXPR will be set.  */
 		      flag_wrapv = 1;
-		      extract_range_from_binary_expr (vr, subcode, type,
+		      extract_range_from_binary_expr (vr, dom_p, subcode, type,
 						      op0, op1);
 		      flag_wrapv = saved_flag_wrapv;
 		    }
@@ -4044,12 +4097,12 @@ extract_range_basic (value_range *vr, gimple *stmt)
 		      /* Pretend the arithmetics is wrapping.  If there is
 			 any overflow, IMAGPART_EXPR will be set.  */
 		      flag_wrapv = 1;
-		      extract_range_from_unary_expr (&vr0, NOP_EXPR,
+		      extract_range_from_unary_expr (&vr0, dom_p, NOP_EXPR,
 						     type, op0);
-		      extract_range_from_unary_expr (&vr1, NOP_EXPR,
+		      extract_range_from_unary_expr (&vr1, dom_p, NOP_EXPR,
 						     type, op1);
-		      extract_range_from_binary_expr_1 (vr, subcode, type,
-							&vr0, &vr1);
+		      extract_range_from_binary_expr_1 (vr, dom_p, subcode,
+							type, &vr0, &vr1);
 		      flag_wrapv = saved_flag_wrapv;
 		    }
 		  return;
@@ -4073,25 +4126,27 @@ extract_range_basic (value_range *vr, gimple *stmt)
    in *VR.  */
 
 static void
-extract_range_from_assignment (value_range *vr, gassign *stmt)
+extract_range_from_assignment (value_range *vr,
+			       bool dom_p,
+			       gassign *stmt)
 {
   enum tree_code code = gimple_assign_rhs_code (stmt);
 
   if (code == ASSERT_EXPR)
     extract_range_from_assert (vr, gimple_assign_rhs1 (stmt));
   else if (code == SSA_NAME)
-    extract_range_from_ssa_name (vr, gimple_assign_rhs1 (stmt));
+    extract_range_from_ssa_name (vr, dom_p, gimple_assign_rhs1 (stmt));
   else if (TREE_CODE_CLASS (code) == tcc_binary)
-    extract_range_from_binary_expr (vr, gimple_assign_rhs_code (stmt),
+    extract_range_from_binary_expr (vr, dom_p, gimple_assign_rhs_code (stmt),
 				    gimple_expr_type (stmt),
 				    gimple_assign_rhs1 (stmt),
 				    gimple_assign_rhs2 (stmt));
   else if (TREE_CODE_CLASS (code) == tcc_unary)
-    extract_range_from_unary_expr (vr, gimple_assign_rhs_code (stmt),
+    extract_range_from_unary_expr (vr, dom_p, gimple_assign_rhs_code (stmt),
 				   gimple_expr_type (stmt),
 				   gimple_assign_rhs1 (stmt));
   else if (code == COND_EXPR)
-    extract_range_from_cond_expr (vr, stmt);
+    extract_range_from_cond_expr (vr, dom_p, stmt);
   else if (TREE_CODE_CLASS (code) == tcc_comparison)
     extract_range_from_comparison (vr, gimple_assign_rhs_code (stmt),
 				   gimple_expr_type (stmt),
@@ -4104,7 +4159,7 @@ extract_range_from_assignment (value_range *vr, gassign *stmt)
     set_value_range_to_varying (vr);
 
   if (vr->type == VR_VARYING)
-    extract_range_basic (vr, stmt);
+    extract_range_basic (vr, dom_p, stmt);
 }
 
 /* Given a range VR, a LOOP and a variable VAR, determine whether it
@@ -4112,7 +4167,9 @@ extract_range_from_assignment (value_range *vr, gassign *stmt)
    for VAR.  If so, update VR with the new limits.  */
 
 static void
-adjust_range_with_scev (value_range *vr, struct loop *loop,
+adjust_range_with_scev (value_range *vr,
+			bool dom_p,
+			struct loop *loop,
 			gimple *stmt, tree var)
 {
   tree init, step, chrec, tmin, tmax, min, max, type, tem;
@@ -4207,7 +4264,7 @@ adjust_range_with_scev (value_range *vr, struct loop *loop,
 		  || wi::gts_p (wtmp, 0) == wi::gts_p (step, 0)))
 	    {
 	      tem = wide_int_to_tree (TREE_TYPE (init), wtmp);
-	      extract_range_from_binary_expr (&maxvr, PLUS_EXPR,
+	      extract_range_from_binary_expr (&maxvr, dom_p, PLUS_EXPR,
 					      TREE_TYPE (init), init, tem);
 	      /* Likewise if the addition did.  */
 	      if (maxvr.type == VR_RANGE)
@@ -6936,10 +6993,14 @@ stmt_interesting_for_vrp (gimple *stmt)
 }
 
 
-/* Initialize local data structures for VRP.  */
+/* Initialize local data structures for VRP.  If DOM_P is true,
+   we will be calling this from early_vrp where value range propagation
+   is done by visiting stmts in dominator tree.  ssa_propagate engine
+   is not used in this case and that part of the ininitialization will
+   be skipped.  */
 
 static void
-vrp_initialize (void)
+vrp_initialize (bool dom_p)
 {
   basic_block bb;
 
@@ -6949,6 +7010,9 @@ vrp_initialize (void)
   vr_phi_edge_counts = XCNEWVEC (int, num_ssa_names);
   bitmap_obstack_initialize (&vrp_equiv_obstack);
 
+  if (dom_p)
+    return;
+
   FOR_EACH_BB_FN (bb, cfun)
     {
       for (gphi_iterator si = gsi_start_phis (bb); !gsi_end_p (si);
@@ -7031,7 +7095,9 @@ vrp_valueize_1 (tree name)
    the SSA name in *OUTPUT_P.  */
 
 static enum ssa_prop_result
-vrp_visit_assignment_or_call (gimple *stmt, tree *output_p)
+vrp_visit_assignment_or_call (gimple *stmt,
+			      bool dom_p,
+			      tree *output_p)
 {
   tree def, lhs;
   ssa_op_iter iter;
@@ -7056,9 +7122,9 @@ vrp_visit_assignment_or_call (gimple *stmt, tree *output_p)
 	set_value_range_to_value (&new_vr, tem, NULL);
       /* Then dispatch to value-range extracting functions.  */
       else if (code == GIMPLE_CALL)
-	extract_range_basic (&new_vr, stmt);
+	extract_range_basic (&new_vr, dom_p, stmt);
       else
-	extract_range_from_assignment (&new_vr, as_a <gassign *> (stmt));
+	extract_range_from_assignment (&new_vr, dom_p, as_a <gassign *> (stmt));
 
       if (update_value_range (lhs, &new_vr))
 	{
@@ -7126,7 +7192,7 @@ vrp_visit_assignment_or_call (gimple *stmt, tree *output_p)
 		   {REAL,IMAG}PART_EXPR uses at all,
 		   return SSA_PROP_VARYING.  */
 		value_range new_vr = VR_INITIALIZER;
-		extract_range_basic (&new_vr, use_stmt);
+		extract_range_basic (&new_vr, dom_p, use_stmt);
 		value_range *old_vr = get_value_range (use_lhs);
 		if (old_vr->type != new_vr.type
 		    || !vrp_operand_equal_p (old_vr->min, new_vr.min)
@@ -7926,7 +7992,8 @@ vrp_visit_switch_stmt (gswitch *stmt, edge *taken_edge_p)
    If STMT produces a varying value, return SSA_PROP_VARYING.  */
 
 static enum ssa_prop_result
-vrp_visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
+vrp_visit_stmt_worker (gimple *stmt, bool dom_p,  edge *taken_edge_p,
+		       tree *output_p)
 {
   tree def;
   ssa_op_iter iter;
@@ -7940,7 +8007,7 @@ vrp_visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
   if (!stmt_interesting_for_vrp (stmt))
     gcc_assert (stmt_ends_bb_p (stmt));
   else if (is_gimple_assign (stmt) || is_gimple_call (stmt))
-    return vrp_visit_assignment_or_call (stmt, output_p);
+    return vrp_visit_assignment_or_call (stmt, dom_p, output_p);
   else if (gimple_code (stmt) == GIMPLE_COND)
     return vrp_visit_cond_stmt (as_a <gcond *> (stmt), taken_edge_p);
   else if (gimple_code (stmt) == GIMPLE_SWITCH)
@@ -7954,6 +8021,12 @@ vrp_visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
   return SSA_PROP_VARYING;
 }
 
+static enum ssa_prop_result
+vrp_visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
+{
+  return vrp_visit_stmt_worker (stmt, false, taken_edge_p, output_p);
+}
+
 /* Union the two value-ranges { *VR0TYPE, *VR0MIN, *VR0MAX } and
    { VR1TYPE, VR0MIN, VR0MAX } and store the result
    in { *VR0TYPE, *VR0MIN, *VR0MAX }.  This may not be the smallest
@@ -8679,7 +8752,8 @@ vrp_meet (value_range *vr0, const value_range *vr1)
    value ranges, set a new range for the LHS of PHI.  */
 
 static enum ssa_prop_result
-vrp_visit_phi_node (gphi *phi)
+vrp_visit_phi_node_worker (gphi *phi,
+			   bool dom_p)
 {
   size_t i;
   tree lhs = PHI_RESULT (phi);
@@ -8768,6 +8842,12 @@ vrp_visit_phi_node (gphi *phi)
 	      fprintf (dump_file, "\n");
 	    }
 
+	  if (dom_p && vr_arg.type == VR_UNDEFINED)
+	    {
+	      set_value_range_to_varying (&vr_result);
+	      break;
+	    }
+
 	  if (first)
 	    copy_value_range (&vr_result, &vr_arg);
 	  else
@@ -8794,6 +8874,7 @@ vrp_visit_phi_node (gphi *phi)
      which are not in a loop.  If the old value-range was VR_UNDEFINED
      use the updated range and iterate one more time.  */
   if (edges > 0
+      && !dom_p
       && gimple_phi_num_args (phi) > 1
       && edges == old_edges
       && lhs_vr->type != VR_UNDEFINED)
@@ -8881,9 +8962,10 @@ scev_check:
      scev_check can be reached from two paths, one is a fall through from above
      "varying" label, the other is direct goto from code block which tries to
      avoid infinite simulation.  */
-  if ((l = loop_containing_stmt (phi))
+  if (!dom_p
+      && (l = loop_containing_stmt (phi))
       && l->header == gimple_bb (phi))
-    adjust_range_with_scev (&vr_result, l, phi, lhs);
+    adjust_range_with_scev (&vr_result, false, l, phi, lhs);
 
 infinite_check:
   /* If we will end up with a (-INF, +INF) range, set it to
@@ -8899,6 +8981,12 @@ infinite_check:
   return SSA_PROP_VARYING;
 }
 
+static enum ssa_prop_result
+vrp_visit_phi_node (gphi *phi)
+{
+  return vrp_visit_phi_node_worker (phi, false);
+}
+
 /* Simplify boolean operations if the source is known
    to be already a boolean.  */
 static bool
@@ -9179,7 +9267,8 @@ simplify_abs_using_ranges (gimple *stmt)
    operation is redundant.  */
 
 static bool
-simplify_bit_ops_using_ranges (gimple_stmt_iterator *gsi, gimple *stmt)
+simplify_bit_ops_using_ranges (gimple_stmt_iterator *gsi,
+			       gimple *stmt)
 {
   tree op0 = gimple_assign_rhs1 (stmt);
   tree op1 = gimple_assign_rhs2 (stmt);
@@ -10082,7 +10171,7 @@ simplify_stmt_for_jump_threading (gimple *stmt, gimple *within_stmt,
 	  && (INTEGRAL_TYPE_P (TREE_TYPE (lhs))
 	      || POINTER_TYPE_P (TREE_TYPE (lhs))))
 	{
-	  extract_range_from_assignment (&new_vr, assign_stmt);
+	  extract_range_from_assignment (&new_vr, false, assign_stmt);
 	  if (range_int_cst_singleton_p (&new_vr))
 	    return new_vr.min;
 	}
@@ -10225,10 +10314,15 @@ finalize_jump_threads (void)
 }
 
 
-/* Traverse all the blocks folding conditionals with known ranges.  */
+/* Traverse all the blocks folding conditionals with known ranges.
+   If DOM_P is true this will be called from dominator based early_vrp.
+   In that case, value ranges would have been set for SSA_NAME as part
+   of the traversal.  And also, substitute_and_fold which is part of
+   the ssa_propagation engine will not be called.  Jump threading is also
+   not done during early_vrp.  */
 
 static void
-vrp_finalize (bool jump_thread_p, bool warn_array_bounds_p)
+vrp_finalize (bool dom_p, bool warn_array_bounds_p)
 {
   size_t i;
 
@@ -10242,34 +10336,36 @@ vrp_finalize (bool jump_thread_p, bool warn_array_bounds_p)
     }
 
   /* Set value range to non pointer SSA_NAMEs.  */
-  for (i  = 0; i < num_vr_values; i++)
-    if (vr_value[i])
-      {
-	tree name = ssa_name (i);
+  if (!dom_p)
+    for (i  = 0; i < num_vr_values; i++)
+      if (vr_value[i])
+	{
+	  tree name = ssa_name (i);
 
-      if (!name
-	  || POINTER_TYPE_P (TREE_TYPE (name))
-	  || (vr_value[i]->type == VR_VARYING)
-	  || (vr_value[i]->type == VR_UNDEFINED))
-	continue;
+	  if (!name
+	      || POINTER_TYPE_P (TREE_TYPE (name))
+	      || (vr_value[i]->type == VR_VARYING)
+	      || (vr_value[i]->type == VR_UNDEFINED))
+	    continue;
 
-      if ((TREE_CODE (vr_value[i]->min) == INTEGER_CST)
-	  && (TREE_CODE (vr_value[i]->max) == INTEGER_CST)
-	  && (vr_value[i]->type == VR_RANGE
-	      || vr_value[i]->type == VR_ANTI_RANGE))
-	set_range_info (name, vr_value[i]->type, vr_value[i]->min,
-			vr_value[i]->max);
-      }
+	  if ((TREE_CODE (vr_value[i]->min) == INTEGER_CST)
+	      && (TREE_CODE (vr_value[i]->max) == INTEGER_CST)
+	      && (vr_value[i]->type == VR_RANGE
+		  || vr_value[i]->type == VR_ANTI_RANGE))
+	    set_range_info (name, vr_value[i]->type, vr_value[i]->min,
+			    vr_value[i]->max);
+	}
 
-  substitute_and_fold (op_with_constant_singleton_value_range,
-		       vrp_fold_stmt, false);
+  if (!dom_p)
+    substitute_and_fold (op_with_constant_singleton_value_range,
+			 vrp_fold_stmt, false);
 
   if (warn_array_bounds && warn_array_bounds_p)
     check_all_array_refs ();
 
   /* We must identify jump threading opportunities before we release
      the datastructures built by VRP.  */
-  if (jump_thread_p)
+  if (!dom_p)
     identify_jump_threads ();
 
   /* Free allocated memory.  */
@@ -10285,6 +10381,227 @@ vrp_finalize (bool jump_thread_p, bool warn_array_bounds_p)
 }
 
 
+/* Visit the basic blocks in the dominance order and set the Value Ranges (VR)
+   for SSA_NAMEs in the scope.  Use this VR to discover more VRs.  Restore the
+   old VR once the scope is exited.  */
+
+static bool
+visit_phi_node_p (gphi *phi)
+{
+  for (unsigned int i = 0; i < gimple_phi_num_args (phi); i++)
+    {
+      edge e = gimple_phi_arg_edge (phi, i);
+      if (e->flags & (EDGE_DFS_BACK | EDGE_COMPLEX))
+	return false;
+    }
+  return true;
+}
+
+/* evrp_dom_walker visits the basic blocks in the dominance order and set
+   the Value Ranges (VR) for SSA_NAMEs in the scope.  Use this VR to
+   discover more VRs.  */
+
+class evrp_dom_walker : public dom_walker
+{
+public:
+  evrp_dom_walker ()
+    : dom_walker (CDI_DOMINATORS), stack (10) {}
+
+  virtual edge before_dom_children (basic_block);
+  virtual void after_dom_children (basic_block);
+  void push_value_range (const_tree var, value_range *vr);
+  value_range *pop_value_range (const_tree var);
+
+  /* Cond_stack holds the old VR.  */
+  auto_vec<std::pair <const_tree, value_range*> > stack;
+};
+
+/* See if there is any new scope is entered with new VR and set that VR to
+   ssa_name before visiting the statements in the scope.  */
+
+edge
+evrp_dom_walker::before_dom_children (basic_block bb)
+{
+  value_range *new_vr = NULL;
+  tree op0 = NULL_TREE;
+  push_value_range (NULL_TREE, NULL);
+  if (single_pred_p (bb))
+    {
+      edge e = single_pred_edge (bb);
+      value_range vr = VR_INITIALIZER;
+      gimple *stmt = last_stmt (e->src);
+
+      if (stmt
+	  && gimple_code (stmt) == GIMPLE_COND
+	  && (op0 = gimple_cond_lhs (stmt))
+	  && TREE_CODE (op0) == SSA_NAME
+	  && INTEGRAL_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt))))
+	{
+	  /* Entering a new scope.  Try to see if we can find a VR
+	     here.  */ 
+	  tree op1 = gimple_cond_rhs (stmt);
+	  tree_code code = gimple_cond_code (stmt);
+	  value_range *old_vr = get_value_range (op0);
+
+	  if (TREE_OVERFLOW_P (op1))
+	    op1 = drop_tree_overflow (op1);
+
+	  /* If condition is false, invert the cond.  */
+	  if (e->flags & EDGE_FALSE_VALUE)
+	    code = invert_tree_comparison (gimple_cond_code (stmt),
+					   HONOR_NANS (op0));
+	  /* Discover VR when condition is true.  */
+	  extract_range_for_var_from_comparison_expr (op0, code, op0, op1, &vr);
+	  if (old_vr->type == VR_RANGE || old_vr->type == VR_ANTI_RANGE)
+	    vrp_intersect_ranges (&vr, old_vr);
+
+	  /* If we found any usable VR, set the VR to ssa_name and create a
+	     PUSH old value in the stack with the old VR.  */
+	  if (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE)
+	    {
+	      new_vr = vrp_value_range_pool.allocate ();
+	      *new_vr = vr;
+	      push_value_range (op0, new_vr);
+	    }
+	}
+    }
+
+  /* Visit PHI stmts and discover any new VRs possible.  */
+  gimple_stmt_iterator gsi;
+  for (gphi_iterator gpi = gsi_start_phis (bb);
+       !gsi_end_p (gpi); gsi_next (&gpi))
+    {
+      gphi *phi = gpi.phi ();
+      if (stmt_interesting_for_vrp (phi))
+	{
+	  /* See if the PHI has any back edges.  If there is any
+	     backedges we will have to set the lattice to
+	     VR_VARYING as we will not be traversing it till it
+	     reach fix point.  */
+	  if (visit_phi_node_p (phi))
+	    vrp_visit_phi_node_worker (phi, true);
+	  else
+	    {
+	      tree lhs = PHI_RESULT (phi);
+	      value_range vr_result = VR_INITIALIZER;
+	      set_value_range_to_varying (&vr_result);
+	      update_value_range (lhs, &vr_result);
+	    }
+	}
+    }
+
+  /* Visit all other stmts and discover any new VRs possible.  */
+  for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+    {
+      gimple *stmt = gsi_stmt (gsi);
+      edge taken_edge;
+      tree output;
+      /* TODO, if found taken_edge, we should visit (return it) and travel
+	 again to improve VR as done in DOM/SCCVN optimizations.  It should
+	 be done carefully as stmts might prematurely leave a BB like
+	 in EH.  */
+      if (stmt_interesting_for_vrp (stmt))
+	{
+	  vrp_visit_stmt_worker (stmt, true, &taken_edge, &output);
+	  /* Try folding stmts with the VR discovered.  */
+	  if (fold_stmt (&gsi, follow_single_use_edges))
+	    update_stmt (gsi_stmt (gsi));
+	  def_operand_p def_p;
+	  def_p = SINGLE_SSA_DEF_OPERAND (stmt, SSA_OP_DEF);
+	  /* Set the SSA with the value range.  */
+	  if (def_p
+	      && TREE_CODE (DEF_FROM_PTR (def_p)) == SSA_NAME
+	      && INTEGRAL_TYPE_P (TREE_TYPE (DEF_FROM_PTR (def_p))))
+	    {
+	      tree def = DEF_FROM_PTR (def_p);
+	      unsigned ver = SSA_NAME_VERSION (def);
+	      if ((vr_value[ver]->type == VR_RANGE
+		   || vr_value[ver]->type == VR_ANTI_RANGE)
+		  && (TREE_CODE (vr_value[ver]->min) == INTEGER_CST)
+		  && (TREE_CODE (vr_value[ver]->max) == INTEGER_CST))
+		set_range_info (def, vr_value[ver]->type, vr_value[ver]->min,
+				vr_value[ver]->max);
+	    }
+	}
+    }
+  return NULL;
+}
+
+/* Restore/Pop VRs valid only for BB when we leave BB.  */
+
+void
+evrp_dom_walker::after_dom_children (basic_block bb ATTRIBUTE_UNUSED)
+{
+  gcc_checking_assert (!stack.is_empty ());
+  while (stack.last ().first != NULL_TREE)
+    pop_value_range (stack.last ().first);
+  pop_value_range (stack.last ().first);
+}
+
+/* Push the Value Range of VAR to the stack and update it with new VR.  */
+
+void
+evrp_dom_walker::push_value_range (const_tree var, value_range *vr)
+{
+  if (vr != NULL)
+    {
+      unsigned ver = SSA_NAME_VERSION (var);
+      gcc_checking_assert (vr_value);
+      stack.safe_push (std::make_pair (var, vr_value[ver]));
+
+      if (ver < num_vr_values)
+	vr_value[ver] = vr;
+    }
+  else
+    stack.safe_push (std::make_pair (var, vr));
+}
+
+/* Pop the Value Range from the vrp_stack and update VAR with it.  */
+
+value_range *
+evrp_dom_walker::pop_value_range (const_tree var)
+{
+  value_range *vr = stack.last ().second;
+  if (vr != NULL)
+    {
+      unsigned ver = SSA_NAME_VERSION (var);
+      gcc_checking_assert (var == stack.last ().first);
+      gcc_checking_assert (vr_value);
+
+      if (ver < num_vr_values)
+	vr_value[ver] = vr;
+    }
+  stack.pop ();
+  return vr;
+}
+
+
+/* Main entry point for the early vrp pass which is a simplified non-iterative
+   version of VRP where basic blocks are visited in dominance order.  Value
+   ranges discovered in early vrp will also be used by ipa-vrp.  */
+
+static unsigned int
+execute_early_vrp ()
+{
+  edge e;
+  edge_iterator ei;
+  basic_block bb;
+
+  calculate_dominance_info (CDI_DOMINATORS);
+  FOR_EACH_BB_FN (bb, cfun)
+    {
+      FOR_EACH_EDGE (e, ei, bb->preds)
+	e->flags |= EDGE_EXECUTABLE;
+    }
+  vrp_initialize (true);
+
+  /* Walk stmts in dominance order and propagate VRP.  */
+  evrp_dom_walker walker;
+  walker.walk (ENTRY_BLOCK_PTR_FOR_FN (cfun));
+  vrp_finalize (true, false);
+  return 0;
+}
+
 /* Main entry point to VRP (Value Range Propagation).  This pass is
    loosely based on J. R. C. Patterson, ``Accurate Static Branch
    Prediction by Value Range Propagation,'' in SIGPLAN Conference on
@@ -10352,9 +10669,9 @@ execute_vrp (bool warn_array_bounds_p)
   /* For visiting PHI nodes we need EDGE_DFS_BACK computed.  */
   mark_dfs_back_edges ();
 
-  vrp_initialize ();
+  vrp_initialize (false);
   ssa_propagate (vrp_visit_stmt, vrp_visit_phi_node);
-  vrp_finalize (true, warn_array_bounds_p);
+  vrp_finalize (false, warn_array_bounds_p);
 
   free_numbers_of_iterations_estimates (cfun);
 
@@ -10452,3 +10769,44 @@ make_pass_vrp (gcc::context *ctxt)
 {
   return new pass_vrp (ctxt);
 }
+
+namespace {
+
+const pass_data pass_data_early_vrp =
+{
+  GIMPLE_PASS, /* type */
+  "evrp", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_TREE_EARLY_VRP, /* tv_id */
+  PROP_ssa, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  ( TODO_cleanup_cfg | TODO_update_ssa | TODO_verify_all ),
+};
+
+class pass_early_vrp : public gimple_opt_pass
+{
+public:
+  pass_early_vrp (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_early_vrp, ctxt)
+    {}
+
+  /* opt_pass methods: */
+  opt_pass * clone () { return new pass_early_vrp (m_ctxt); }
+  virtual bool gate (function *)
+    {
+      return !flag_disable_early_vrp && flag_tree_vrp != 0;
+    }
+  virtual unsigned int execute (function *)
+    { return execute_early_vrp (); }
+
+}; // class pass_vrp
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_early_vrp (gcc::context *ctxt)
+{
+  return new pass_early_vrp (ctxt);
+}
+
-- 
1.9.1


^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Early VRP Implementation
  2016-08-03  1:17                         ` kugan
@ 2016-08-12 10:43                           ` Richard Biener
  2016-08-16  7:39                             ` [RFC][IPA-VRP] splits out the update_value_range calls from vrp_visit_stmt kugan
  2016-08-16  7:45                             ` [RFC][IPA-VRP] Early VRP Implementation kugan
  0 siblings, 2 replies; 67+ messages in thread
From: Richard Biener @ 2016-08-12 10:43 UTC (permalink / raw)
  To: kugan; +Cc: Andrew Pinski, gcc-patches, Jan Hubicka, Martin Jambor

On Wed, Aug 3, 2016 at 3:17 AM, kugan <kugan.vivekanandarajah@linaro.org> wrote:
> Hi Richard,
>
> Thanks for the review.
>
> On 28/07/16 21:34, Richard Biener wrote:
>>
>> On Thu, Jul 28, 2016 at 9:35 AM, kugan
>> <kugan.vivekanandarajah@linaro.org> wrote:
>>>
>>> Hi Richard,
>>>
>>> Thanks for the review.
>>>>
>>>>
>>>>
>>>> It seems that in your pop_value_range you assume you only pop one
>>>> range per BB - while that's likely true at the moment it will be a
>>>> limitation
>>>> in the future.  You want to pop ranges until you hit the NULL marker
>>>> in after_dom_children and unconditionally push a NULL marker.
>>>>
>>> I understand. Right now, I am adding only one assert based on the
>>> condition.
>>> But in future, we will be adding more so this is needed. I will do that.
>>>
>>>> For example to match current VRPs behavior on say
>>>>
>>>>    i_2 = (int) j_3;
>>>>    if (i_2 < 0)
>>>>      ...
>>>>
>>>> which can register an assert for j_3 when i_2 < 0 is true we'd do that
>>>> by re-simulating DEFs of uses we figured out new ranges of (and all
>>>> their uses).  All those ranges would be temporary as well, thus they'd
>>>> need to be pushed/popped.  In my quick prototype this was done
>>>> using a worklist seeded by the names we can derive a range from from
>>>> conditionals and "SSA propagating" from it.  Note that for this
>>>> the generic vrp_visit_stmt cannot be re-used as it doesn't push/pop,
>>>> factoring out the lattice update is what is needed here.
>>>>
>>>
>>> I dont think I understand this part. vrp_visit_stmt is going to add value
>>> ranges for the variables defined in the if-block (in the example below it
>>> is
>>> for t). If we push the value range for i_2 and j_3 when we enter
>>> if-block,
>>> vrp_visit_stmt should compute "t" correctly. When we leave the if-block,
>>> we
>>> will pop i_2 and j_3.
>>>
>>>     i_2 = (int) j_3;
>>>     if (i_2 < 0)
>>>     {
>>>       t = j_2 * 2;
>>>     }
>>> Am I missing something here?
>>
>>
>> It works if you push the old value before calling vrp_visit_stmt, yes.
>> But I think
>> you want to do that only if the value-range changed to avoid too many
>> changes
>> on the stack.  I guess we can defer further refactoring and
>> optimization of this case
>> to the point where we consider looking back very aggressively.
>>
>>>> +/* Visit the basic blocks in the dominance order and set the Value
>>>> Ranges
>>>> (VR)
>>>> +   for SSA_NAMEs in the scope.  Use this VR to discover more VRs.
>>>> Restore the
>>>> +   old VR once the scope is exited.  */
>>>> +
>>>> +static bool
>>>> +evrp_visit_phi_node_local (gphi *phi)
>>>> +{
>>>> +  size_t i;
>>>> +  tree lhs = PHI_RESULT (phi);
>>>> +  value_range vr_result = VR_INITIALIZER;
>>>> +  bool first = true;
>>>> +  int edges;
>>>> +
>>>> +  edges = 0;
>>>> +  for (i = 0; i < gimple_phi_num_args (phi); i++)
>>>> +    {
>>>> +      edge e = gimple_phi_arg_edge (phi, i);
>>>> +      tree arg = PHI_ARG_DEF (phi, i);
>>>> +      value_range vr_arg = VR_INITIALIZER;
>>>> +      ++edges;
>>>> +
>>>> +      /* If there is a back-edge, set the result to VARYING.  */
>>>> +      if (e->flags & (EDGE_DFS_BACK | EDGE_COMPLEX))
>>>> +       {
>>>> +         set_value_range_to_varying (&vr_result);
>>>> +         break;
>>>> +       }
>>>> ...
>>>> +      /* If any of the RHS value is VARYING, set the result to VARYING.
>>>> */
>>>> +      if ((vr_arg.type != VR_RANGE)
>>>> +         && (vr_arg.type != VR_ANTI_RANGE))
>>>> +       {
>>>> +         set_value_range_to_varying (&vr_result);
>>>> +         break;
>>>> +       }
>>>>
>>>> this shows that you need to start conservative for a DOM based VRP,
>>>> thus with all lattice values initialized to VARYING (but undefined SSA
>>>> names of course still can be UNDEFINED) rather than UNDEFINED.
>>>>
>>>> +      if (TREE_CODE (arg) == SSA_NAME)
>>>> +       vr_arg = *(get_value_range (arg));
>>>> +      else
>>>> +       set_value_range_to_varying (&vr_arg);
>>>>
>>>> err - what about constants?  When you initialize the lattice properly
>>>> you should be able to re-use vrp_visit_phi_node (maybe split out
>>>> its head to avoid using SCEV or the iteration limitation).
>>>
>>>
>>>
>>> I also like re-using vrp_visit_phi_node but the issue is, we will have to
>>> keep a work-list of nodes to be re-evaluated till the lattice reach a
>>> fixpoint. Is that OK with you?
>>
>>
>> No, why would you need to iterate here?  As said, the key point is to
>> initialize value-ranges as VARYING rather than UNDEFINED.
>>
>>> If we are to do this, we should be able to reuse the callbacks
>>> vrp_visit_phi_node and vrp_visit_stmt as it is.
>>>
>>> Do you have a reference to your DOM based prototype?
>>
>>
>> I never posted it I think, it's structure is similar to yours with lots
>> of ??? comments ;)
>>
>
>
> Here is an updated patch which addresses the earlier review comments.
>
> Just to see the effectiveness of this, I did a simple test.
>
> That is, I built gcc with --enable-languages=c,c++ --disable-bootstrap
> --disable-multilib and added -fdump-ipa-cp to the compiler flag and grepped
> for number of times ipa-vrp (with the ipa-vrp patch) is setting the value
> range for argument. I also did the same with tree-vrp used in place of
> tree-evrp as an early vrp. tree-evrp is setting 186 times compared to
> tree-vrp which is setting 207 times. I didn't see the actual value ranges
> which can also make lots of difference.
>
> In future we might want to iterate on dom based vrp till fixed point is
> reached if there is a need.

diff --git a/gcc/common.opt b/gcc/common.opt
index 8a292ed..7028cd4 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2482,6 +2482,10 @@ ftree-vrp
 Common Report Var(flag_tree_vrp) Init(0) Optimization
 Perform Value Range Propagation on trees.

+fdisable-tree-evrp
+Common Report Var(flag_disable_early_vrp) Init(0) Optimization
+Disable Early Value Range Propagation on trees.
+

no please, this is automatically supported via -fdisable-

@@ -1728,11 +1736,12 @@ extract_range_from_assert (value_range *vr_p, tree expr)
     always false.  */

 static void
-extract_range_from_ssa_name (value_range *vr, tree var)
+extract_range_from_ssa_name (value_range *vr, bool dom_p, tree var)
 {
   value_range *var_vr = get_value_range (var);

-  if (var_vr->type != VR_VARYING)
+  if (var_vr->type != VR_VARYING
+      && (!dom_p || var_vr->type != VR_UNDEFINED))
     copy_value_range (vr, var_vr);
   else
     set_value_range (vr, VR_RANGE, var, var, NULL);

why do you need these changes?  I think I already told you you need to
initialize the lattice to sth else than VR_UNDEFINED and that you can't
fully re-use update_value_range.  If you don't want to do that then instead
of doing changes all over the place do it in get_value_range and have a
global flag.


@@ -3594,7 +3643,8 @@ extract_range_from_cond_expr (value_range *vr,
gassign *stmt)
    on the range of its operand and the expression code.  */

 static void
-extract_range_from_comparison (value_range *vr, enum tree_code code,
+extract_range_from_comparison (value_range *vr,
+                              enum tree_code code,
                               tree type, tree op0, tree op1)
 {
   bool sop = false;

remove these kind of no-op changes.

+/* Initialize local data structures for VRP.  If DOM_P is true,
+   we will be calling this from early_vrp where value range propagation
+   is done by visiting stmts in dominator tree.  ssa_propagate engine
+   is not used in this case and that part of the ininitialization will
+   be skipped.  */

 static void
-vrp_initialize (void)
+vrp_initialize (bool dom_p)
 {
   basic_block bb;

@@ -6949,6 +7010,9 @@ vrp_initialize (void)
   vr_phi_edge_counts = XCNEWVEC (int, num_ssa_names);
   bitmap_obstack_initialize (&vrp_equiv_obstack);

+  if (dom_p)
+    return;
+

split the function instead.

@@ -7926,7 +7992,8 @@ vrp_visit_switch_stmt (gswitch *stmt, edge *taken_edge_p)
    If STMT produces a varying value, return SSA_PROP_VARYING.  */

 static enum ssa_prop_result
-vrp_visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
+vrp_visit_stmt_worker (gimple *stmt, bool dom_p,  edge *taken_edge_p,
+                      tree *output_p)
 {
   tree def;
   ssa_op_iter iter;
@@ -7940,7 +8007,7 @@ vrp_visit_stmt (gimple *stmt, edge
*taken_edge_p, tree *output_p)
   if (!stmt_interesting_for_vrp (stmt))
     gcc_assert (stmt_ends_bb_p (stmt));
   else if (is_gimple_assign (stmt) || is_gimple_call (stmt))
-    return vrp_visit_assignment_or_call (stmt, output_p);
+    return vrp_visit_assignment_or_call (stmt, dom_p, output_p);
   else if (gimple_code (stmt) == GIMPLE_COND)
     return vrp_visit_cond_stmt (as_a <gcond *> (stmt), taken_edge_p);
   else if (gimple_code (stmt) == GIMPLE_SWITCH)
@@ -7954,6 +8021,12 @@ vrp_visit_stmt (gimple *stmt, edge
*taken_edge_p, tree *output_p)
   return SSA_PROP_VARYING;
 }

+static enum ssa_prop_result
+vrp_visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
+{
+  return vrp_visit_stmt_worker (stmt, false, taken_edge_p, output_p);
+}

as said the refactoring that would be appreciated is to split out the
update_value_range calls
from the worker functions so you can call the respective functions
from the DOM implementations.
That they are globbed in vrp_visit_stmt currently is due to the API of
the SSA propagator.

@@ -8768,6 +8842,12 @@ vrp_visit_phi_node (gphi *phi)
              fprintf (dump_file, "\n");
            }

+         if (dom_p && vr_arg.type == VR_UNDEFINED)
+           {
+             set_value_range_to_varying (&vr_result);
+             break;
+           }
+

eh...  ok, so another way to attack this is, instead of initializing
the lattice to sth else
than VR_UNDEFINED, make sure to drop the lattice to varying for all PHI args on
yet unvisited incoming edges (you're not doing optimistic VRP).  That's the only
place you _have_ to do it.

Richard.



> Thanks,
> Kugan
>
>

^ permalink raw reply	[flat|nested] 67+ messages in thread

* [RFC][IPA-VRP] splits out the update_value_range calls from vrp_visit_stmt
  2016-08-12 10:43                           ` Richard Biener
@ 2016-08-16  7:39                             ` kugan
  2016-08-16 10:58                               ` Richard Biener
  2016-08-16  7:45                             ` [RFC][IPA-VRP] Early VRP Implementation kugan
  1 sibling, 1 reply; 67+ messages in thread
From: kugan @ 2016-08-16  7:39 UTC (permalink / raw)
  To: Richard Biener; +Cc: Andrew Pinski, gcc-patches, Jan Hubicka, Martin Jambor

[-- Attachment #1: Type: text/plain, Size: 1043 bytes --]

Hi,

> as said the refactoring that would be appreciated is to split out the
> update_value_range calls
> from the worker functions so you can call the respective functions
> from the DOM implementations.
> That they are globbed in vrp_visit_stmt currently is due to the API of
> the SSA propagator.

Here is a patch that just splits out the update_value_range calls 
visit_stmts. Bootstrapped and regression tested on x86_64-linux with no 
new regressions.

I also verified few random fdump-tree-vrp1-details from stage2 to make 
sure they are same.

Is this OK for trunk?

Thanks,
Kugan

gcc/ChangeLog:

2016-08-16  Kugan Vivekanandarajah  <kuganv@linaro.org>

	* tree-vrp.c (vrp_visit_assignment_or_call): Changed to Return VR.
	(vrp_visit_cond_stmt): Just sets TAKEN_EDGE_P.
	(vrp_visit_switch_stmt): Likewise.
	(vrp_visit_stmt_worker): Factored out from vrp_visit_stmt.
	(vrp_visit_phi_node_worker): Factored out from vrp_visit_phi_stmt.
	(vrp_visit_stmt): Use vrp_visit_stmt_worker.
	(vrp_visit_phi_node): Use vrp_visit_phi_node_worker.

[-- Attachment #2: 0002-Refactor-vrp_visit_stmt.patch --]
[-- Type: text/x-patch, Size: 15784 bytes --]

From 0355d191c1141847a59589f9df267d0ee9d9ddb2 Mon Sep 17 00:00:00 2001
From: Kugan Vivekanandarajah <kugan.vivekanandarajah@linaro.org>
Date: Tue, 16 Aug 2016 13:48:21 +1000
Subject: [PATCH 2/5] Refactor vrp_visit_stmt

---
 gcc/tree-vrp.c | 222 +++++++++++++++++++++++++++++++++------------------------
 1 file changed, 130 insertions(+), 92 deletions(-)

diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index cf04bec..5a37579 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -7030,16 +7030,18 @@ vrp_valueize_1 (tree name)
   return name;
 }
 
-/* Visit assignment STMT.  If it produces an interesting range, record
-   the SSA name in *OUTPUT_P.  */
+/* Visit assignment STMt.  If it produces an interesting range, record
+   the range in VR and return true. If the immediate uses might be interesting
+   set SSA name in *OUTPUT_P.  */
 
-static enum ssa_prop_result
-vrp_visit_assignment_or_call (gimple *stmt, tree *output_p)
+static bool
+vrp_visit_assignment_or_call (gimple *stmt, tree *output_p, value_range *vr)
 {
   tree def, lhs;
   ssa_op_iter iter;
   enum gimple_code code = gimple_code (stmt);
   lhs = gimple_get_lhs (stmt);
+  *output_p = NULL_TREE;
 
   /* We only keep track of ranges in integral and pointer types.  */
   if (TREE_CODE (lhs) == SSA_NAME
@@ -7050,39 +7052,17 @@ vrp_visit_assignment_or_call (gimple *stmt, tree *output_p)
 	   && TYPE_MAX_VALUE (TREE_TYPE (lhs)))
 	  || POINTER_TYPE_P (TREE_TYPE (lhs))))
     {
-      value_range new_vr = VR_INITIALIZER;
-
       /* Try folding the statement to a constant first.  */
       tree tem = gimple_fold_stmt_to_constant_1 (stmt, vrp_valueize,
 						 vrp_valueize_1);
       if (tem && is_gimple_min_invariant (tem))
-	set_value_range_to_value (&new_vr, tem, NULL);
+	set_value_range_to_value (vr, tem, NULL);
       /* Then dispatch to value-range extracting functions.  */
       else if (code == GIMPLE_CALL)
-	extract_range_basic (&new_vr, stmt);
+	extract_range_basic (vr, stmt);
       else
-	extract_range_from_assignment (&new_vr, as_a <gassign *> (stmt));
-
-      if (update_value_range (lhs, &new_vr))
-	{
-	  *output_p = lhs;
-
-	  if (dump_file && (dump_flags & TDF_DETAILS))
-	    {
-	      fprintf (dump_file, "Found new range for ");
-	      print_generic_expr (dump_file, lhs, 0);
-	      fprintf (dump_file, ": ");
-	      dump_value_range (dump_file, &new_vr);
-	      fprintf (dump_file, "\n");
-	    }
-
-	  if (new_vr.type == VR_VARYING)
-	    return SSA_PROP_VARYING;
-
-	  return SSA_PROP_INTERESTING;
-	}
-
-      return SSA_PROP_NOT_INTERESTING;
+	extract_range_from_assignment (vr, as_a <gassign *> (stmt));
+      return true;
     }
   else if (is_gimple_call (stmt) && gimple_call_internal_p (stmt))
     switch (gimple_call_internal_fn (stmt))
@@ -7097,7 +7077,7 @@ vrp_visit_assignment_or_call (gimple *stmt, tree *output_p)
 	  {
 	    imm_use_iterator iter;
 	    use_operand_p use_p;
-	    enum ssa_prop_result res = SSA_PROP_VARYING;
+	    bool changed = false;
 
 	    set_value_range_to_varying (get_value_range (lhs));
 
@@ -7135,18 +7115,18 @@ vrp_visit_assignment_or_call (gimple *stmt, tree *output_p)
 		    || !vrp_operand_equal_p (old_vr->min, new_vr.min)
 		    || !vrp_operand_equal_p (old_vr->max, new_vr.max)
 		    || !vrp_bitmap_equal_p (old_vr->equiv, new_vr.equiv))
-		  res = SSA_PROP_INTERESTING;
+		  changed = true;
 		else
-		  res = SSA_PROP_NOT_INTERESTING;
+		  changed = false;
 		BITMAP_FREE (new_vr.equiv);
-		if (res == SSA_PROP_INTERESTING)
+		if (changed)
 		  {
 		    *output_p = lhs;
-		    return res;
+		    return false;
 		  }
 	      }
 
-	    return res;
+	    return false;
 	  }
 	break;
       default:
@@ -7157,7 +7137,7 @@ vrp_visit_assignment_or_call (gimple *stmt, tree *output_p)
   FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_DEF)
     set_value_range_to_varying (get_value_range (def));
 
-  return SSA_PROP_VARYING;
+  return false;
 }
 
 /* Helper that gets the value range of the SSA_NAME with version I
@@ -7529,10 +7509,9 @@ vrp_evaluate_conditional (tree_code code, tree op0, tree op1, gimple *stmt)
 
 /* Visit conditional statement STMT.  If we can determine which edge
    will be taken out of STMT's basic block, record it in
-   *TAKEN_EDGE_P and return SSA_PROP_INTERESTING.  Otherwise, return
-   SSA_PROP_VARYING.  */
+   *TAKEN_EDGE_P.  Otherwise, set *TAKEN_EDGE_P to NULL.  */
 
-static enum ssa_prop_result
+static void
 vrp_visit_cond_stmt (gcond *stmt, edge *taken_edge_p)
 {
   tree val;
@@ -7630,8 +7609,6 @@ vrp_visit_cond_stmt (gcond *stmt, edge *taken_edge_p)
       else
 	print_generic_stmt (dump_file, val, 0);
     }
-
-  return (*taken_edge_p) ? SSA_PROP_INTERESTING : SSA_PROP_VARYING;
 }
 
 /* Searches the case label vector VEC for the index *IDX of the CASE_LABEL
@@ -7828,10 +7805,9 @@ find_case_label_ranges (gswitch *stmt, value_range *vr, size_t *min_idx1,
 
 /* Visit switch statement STMT.  If we can determine which edge
    will be taken out of STMT's basic block, record it in
-   *TAKEN_EDGE_P and return SSA_PROP_INTERESTING.  Otherwise, return
-   SSA_PROP_VARYING.  */
+   *TAKEN_EDGE_P.  Otherwise, *TAKEN_EDGE_P set to NULL.  */
 
-static enum ssa_prop_result
+static void
 vrp_visit_switch_stmt (gswitch *stmt, edge *taken_edge_p)
 {
   tree op, val;
@@ -7842,7 +7818,7 @@ vrp_visit_switch_stmt (gswitch *stmt, edge *taken_edge_p)
   *taken_edge_p = NULL;
   op = gimple_switch_index (stmt);
   if (TREE_CODE (op) != SSA_NAME)
-    return SSA_PROP_VARYING;
+    return;
 
   vr = get_value_range (op);
   if (dump_file && (dump_flags & TDF_DETAILS))
@@ -7857,7 +7833,7 @@ vrp_visit_switch_stmt (gswitch *stmt, edge *taken_edge_p)
   if ((vr->type != VR_RANGE
        && vr->type != VR_ANTI_RANGE)
       || symbolic_range_p (vr))
-    return SSA_PROP_VARYING;
+    return;
 
   /* Find the single edge that is taken from the switch expression.  */
   take_default = !find_case_label_ranges (stmt, vr, &i, &j, &k, &l);
@@ -7882,7 +7858,7 @@ vrp_visit_switch_stmt (gswitch *stmt, edge *taken_edge_p)
 	  if (dump_file && (dump_flags & TDF_DETAILS))
 	    fprintf (dump_file, "  not a single destination for this "
 		     "range\n");
-          return SSA_PROP_VARYING;
+          return;
 	}
       for (++i; i <= j; ++i)
         {
@@ -7891,7 +7867,7 @@ vrp_visit_switch_stmt (gswitch *stmt, edge *taken_edge_p)
 	      if (dump_file && (dump_flags & TDF_DETAILS))
 		fprintf (dump_file, "  not a single destination for this "
 			 "range\n");
-	      return SSA_PROP_VARYING;
+	      return;
 	    }
         }
       for (; k <= l; ++k)
@@ -7901,7 +7877,7 @@ vrp_visit_switch_stmt (gswitch *stmt, edge *taken_edge_p)
 	      if (dump_file && (dump_flags & TDF_DETAILS))
 		fprintf (dump_file, "  not a single destination for this "
 			 "range\n");
-	      return SSA_PROP_VARYING;
+	      return;
 	    }
         }
     }
@@ -7914,22 +7890,21 @@ vrp_visit_switch_stmt (gswitch *stmt, edge *taken_edge_p)
       fprintf (dump_file, "  will take edge to ");
       print_generic_stmt (dump_file, CASE_LABEL (val), 0);
     }
-
-  return SSA_PROP_INTERESTING;
 }
 
 
 /* Evaluate statement STMT.  If the statement produces a useful range,
-   return SSA_PROP_INTERESTING and record the SSA name with the
-   interesting range into *OUTPUT_P.
+   return true.
 
-   If STMT is a conditional branch and we can determine its truth
-   value, the taken edge is recorded in *TAKEN_EDGE_P.
+   If the immediate uses might be interesting
+   set SSA name in *OUTPUT_P.
 
-   If STMT produces a varying value, return SSA_PROP_VARYING.  */
+   If STMT is a conditional branch and we can determine its truth
+   value, the taken edge is recorded in *TAKEN_EDGE_P.  */
 
-static enum ssa_prop_result
-vrp_visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
+static bool
+vrp_visit_stmt_worker (gimple *stmt, edge *taken_edge_p,
+		       tree *output_p, value_range *vr)
 {
   tree def;
   ssa_op_iter iter;
@@ -7943,18 +7918,69 @@ vrp_visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
   if (!stmt_interesting_for_vrp (stmt))
     gcc_assert (stmt_ends_bb_p (stmt));
   else if (is_gimple_assign (stmt) || is_gimple_call (stmt))
-    return vrp_visit_assignment_or_call (stmt, output_p);
+    return vrp_visit_assignment_or_call (stmt, output_p, vr);
   else if (gimple_code (stmt) == GIMPLE_COND)
-    return vrp_visit_cond_stmt (as_a <gcond *> (stmt), taken_edge_p);
+    {
+      vrp_visit_cond_stmt (as_a <gcond *> (stmt), taken_edge_p);
+      return false;
+    }
   else if (gimple_code (stmt) == GIMPLE_SWITCH)
-    return vrp_visit_switch_stmt (as_a <gswitch *> (stmt), taken_edge_p);
-
+    {
+      vrp_visit_switch_stmt (as_a <gswitch *> (stmt), taken_edge_p);
+      return false;
+    }
   /* All other statements produce nothing of interest for VRP, so mark
      their outputs varying and prevent further simulation.  */
   FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_DEF)
     set_value_range_to_varying (get_value_range (def));
+  return false;
+}
+
+/* Evaluate statement STMT.  If the statement produces a useful range,
+   return SSA_PROP_INTERESTING and record the SSA name with the
+   interesting range into *OUTPUT_P.
+
+   If STMT is a conditional branch and we can determine its truth
+   value, the taken edge is recorded in *TAKEN_EDGE_P.
+
+   If STMT produces a varying value, return SSA_PROP_VARYING.  */
+
+static enum ssa_prop_result
+vrp_visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
+{
+  value_range vr = VR_INITIALIZER;
+  tree lhs = gimple_get_lhs (stmt);
+  bool vr_found = vrp_visit_stmt_worker (stmt, taken_edge_p,
+					 output_p, &vr);
+
+  if (lhs)
+    {
+      if (vr_found
+	  && update_value_range (lhs, &vr))
+	{
+	  *output_p = lhs;
+	  if (dump_file && (dump_flags & TDF_DETAILS))
+	    {
+	      fprintf (dump_file, "Found new range for ");
+	      print_generic_expr (dump_file, lhs, 0);
+	      fprintf (dump_file, ": ");
+	      dump_value_range (dump_file, &vr);
+	      fprintf (dump_file, "\n");
+	    }
+
+	  if (vr.type == VR_VARYING)
+	    return SSA_PROP_VARYING;
+
+	  return SSA_PROP_INTERESTING;
+	}
 
-  return SSA_PROP_VARYING;
+      if (*output_p)
+	return SSA_PROP_INTERESTING;
+
+      return SSA_PROP_NOT_INTERESTING;
+    }
+
+  return (*taken_edge_p) ? SSA_PROP_INTERESTING : SSA_PROP_VARYING;
 }
 
 /* Union the two value-ranges { *VR0TYPE, *VR0MIN, *VR0MAX } and
@@ -8679,15 +8705,14 @@ vrp_meet (value_range *vr0, const value_range *vr1)
 
 /* Visit all arguments for PHI node PHI that flow through executable
    edges.  If a valid value range can be derived from all the incoming
-   value ranges, set a new range for the LHS of PHI.  */
+   value ranges, set a new range in VR_RESULT.  */
 
-static enum ssa_prop_result
-vrp_visit_phi_node (gphi *phi)
+static void
+vrp_visit_phi_node_worker (gphi *phi, value_range *vr_result)
 {
   size_t i;
   tree lhs = PHI_RESULT (phi);
   value_range *lhs_vr = get_value_range (lhs);
-  value_range vr_result = VR_INITIALIZER;
   bool first = true;
   int edges, old_edges;
   struct loop *l;
@@ -8779,19 +8804,19 @@ vrp_visit_phi_node (gphi *phi)
 	    }
 
 	  if (first)
-	    copy_value_range (&vr_result, &vr_arg);
+	    copy_value_range (vr_result, &vr_arg);
 	  else
-	    vrp_meet (&vr_result, &vr_arg);
+	    vrp_meet (vr_result, &vr_arg);
 	  first = false;
 
-	  if (vr_result.type == VR_VARYING)
+	  if (vr_result->type == VR_VARYING)
 	    break;
 	}
     }
 
-  if (vr_result.type == VR_VARYING)
+  if (vr_result->type == VR_VARYING)
     goto varying;
-  else if (vr_result.type == VR_UNDEFINED)
+  else if (vr_result->type == VR_UNDEFINED)
     goto update_range;
 
   old_edges = vr_phi_edge_counts[SSA_NAME_VERSION (lhs)];
@@ -8813,16 +8838,16 @@ vrp_visit_phi_node (gphi *phi)
     {
       /* Compare old and new ranges, fall back to varying if the
          values are not comparable.  */
-      int cmp_min = compare_values (lhs_vr->min, vr_result.min);
+      int cmp_min = compare_values (lhs_vr->min, vr_result->min);
       if (cmp_min == -2)
 	goto varying;
-      int cmp_max = compare_values (lhs_vr->max, vr_result.max);
+      int cmp_max = compare_values (lhs_vr->max, vr_result->max);
       if (cmp_max == -2)
 	goto varying;
 
       /* For non VR_RANGE or for pointers fall back to varying if
 	 the range changed.  */
-      if ((lhs_vr->type != VR_RANGE || vr_result.type != VR_RANGE
+      if ((lhs_vr->type != VR_RANGE || vr_result->type != VR_RANGE
 	   || POINTER_TYPE_P (TREE_TYPE (lhs)))
 	  && (cmp_min != 0 || cmp_max != 0))
 	goto varying;
@@ -8836,23 +8861,23 @@ vrp_visit_phi_node (gphi *phi)
 	 iteration compute whether there will be any overflow, at the
 	 expense of one additional iteration.  */
       if (cmp_min < 0)
-	vr_result.min = lhs_vr->min;
+	vr_result->min = lhs_vr->min;
       else if (cmp_min > 0
-	       && !vrp_val_is_min (vr_result.min))
-	vr_result.min
+	       && !vrp_val_is_min (vr_result->min))
+	vr_result->min
 	  = int_const_binop (PLUS_EXPR,
-			     vrp_val_min (TREE_TYPE (vr_result.min)),
-			     build_int_cst (TREE_TYPE (vr_result.min), 1));
+			     vrp_val_min (TREE_TYPE (vr_result->min)),
+			     build_int_cst (TREE_TYPE (vr_result->min), 1));
 
       /* Similarly for the maximum value.  */
       if (cmp_max > 0)
-	vr_result.max = lhs_vr->max;
+	vr_result->max = lhs_vr->max;
       else if (cmp_max < 0
-	       && !vrp_val_is_max (vr_result.max))
-	vr_result.max
+	       && !vrp_val_is_max (vr_result->max))
+	vr_result->max
 	  = int_const_binop (MINUS_EXPR,
-			     vrp_val_max (TREE_TYPE (vr_result.min)),
-			     build_int_cst (TREE_TYPE (vr_result.min), 1));
+			     vrp_val_max (TREE_TYPE (vr_result->min)),
+			     build_int_cst (TREE_TYPE (vr_result->min), 1));
 
       /* If we dropped either bound to +-INF then if this is a loop
 	 PHI node SCEV may known more about its value-range.  */
@@ -8866,7 +8891,7 @@ vrp_visit_phi_node (gphi *phi)
   goto update_range;
 
 varying:
-  set_value_range_to_varying (&vr_result);
+  set_value_range_to_varying (vr_result);
 
 scev_check:
   /* If this is a loop PHI node SCEV may known more about its value-range.
@@ -8875,22 +8900,35 @@ scev_check:
      avoid infinite simulation.  */
   if ((l = loop_containing_stmt (phi))
       && l->header == gimple_bb (phi))
-    adjust_range_with_scev (&vr_result, l, phi, lhs);
+    adjust_range_with_scev (vr_result, l, phi, lhs);
 
 infinite_check:
   /* If we will end up with a (-INF, +INF) range, set it to
      VARYING.  Same if the previous max value was invalid for
      the type and we end up with vr_result.min > vr_result.max.  */
-  if ((vr_result.type == VR_RANGE || vr_result.type == VR_ANTI_RANGE)
-      && !((vrp_val_is_max (vr_result.max) && vrp_val_is_min (vr_result.min))
-	   || compare_values (vr_result.min, vr_result.max) > 0))
+  if ((vr_result->type == VR_RANGE || vr_result->type == VR_ANTI_RANGE)
+      && !((vrp_val_is_max (vr_result->max) && vrp_val_is_min (vr_result->min))
+	   || compare_values (vr_result->min, vr_result->max) > 0))
     ;
   else
-    set_value_range_to_varying (&vr_result);
+    set_value_range_to_varying (vr_result);
 
   /* If the new range is different than the previous value, keep
      iterating.  */
 update_range:
+  return;
+}
+
+/* Visit all arguments for PHI node PHI that flow through executable
+   edges.  If a valid value range can be derived from all the incoming
+   value ranges, set a new range for the LHS of PHI.  */
+
+static enum ssa_prop_result
+vrp_visit_phi_node (gphi *phi)
+{
+  tree lhs = PHI_RESULT (phi);
+  value_range vr_result = VR_INITIALIZER;
+  vrp_visit_phi_node_worker (phi, &vr_result);
   if (update_value_range (lhs, &vr_result))
     {
       if (dump_file && (dump_flags & TDF_DETAILS))
-- 
2.7.4


^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Early VRP Implementation
  2016-08-12 10:43                           ` Richard Biener
  2016-08-16  7:39                             ` [RFC][IPA-VRP] splits out the update_value_range calls from vrp_visit_stmt kugan
@ 2016-08-16  7:45                             ` kugan
  2016-08-19 11:41                               ` Richard Biener
  1 sibling, 1 reply; 67+ messages in thread
From: kugan @ 2016-08-16  7:45 UTC (permalink / raw)
  To: Richard Biener; +Cc: Andrew Pinski, gcc-patches, Jan Hubicka, Martin Jambor

[-- Attachment #1: Type: text/plain, Size: 5609 bytes --]

Hi Richard,

On 12/08/16 20:43, Richard Biener wrote:
> On Wed, Aug 3, 2016 at 3:17 AM, kugan <kugan.vivekanandarajah@linaro.org> wrote:

[SNIP]

>
> diff --git a/gcc/common.opt b/gcc/common.opt
> index 8a292ed..7028cd4 100644
> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -2482,6 +2482,10 @@ ftree-vrp
>  Common Report Var(flag_tree_vrp) Init(0) Optimization
>  Perform Value Range Propagation on trees.
>
> +fdisable-tree-evrp
> +Common Report Var(flag_disable_early_vrp) Init(0) Optimization
> +Disable Early Value Range Propagation on trees.
> +
>
> no please, this is automatically supported via -fdisable-

I am now having -ftree-evrp which is enabled all the time. But This will 
only be used for disabling the early-vrp. That is, early-vrp will be run 
when ftree-vrp is enabled and ftree-evrp is not explicitly disabled. Is 
this OK?

>
> @@ -1728,11 +1736,12 @@ extract_range_from_assert (value_range *vr_p, tree expr)
>      always false.  */
>
>  static void
> -extract_range_from_ssa_name (value_range *vr, tree var)
> +extract_range_from_ssa_name (value_range *vr, bool dom_p, tree var)
>  {
>    value_range *var_vr = get_value_range (var);
>
> -  if (var_vr->type != VR_VARYING)
> +  if (var_vr->type != VR_VARYING
> +      && (!dom_p || var_vr->type != VR_UNDEFINED))
>      copy_value_range (vr, var_vr);
>    else
>      set_value_range (vr, VR_RANGE, var, var, NULL);
>
> why do you need these changes?  I think I already told you you need to
> initialize the lattice to sth else than VR_UNDEFINED and that you can't
> fully re-use update_value_range.  If you don't want to do that then instead
> of doing changes all over the place do it in get_value_range and have a
> global flag.

I have now added a global early_vrp_p and use this to initialize 
VR_INITIALIZER and get_value_range default to VR_VARYING.

>
>
> @@ -3594,7 +3643,8 @@ extract_range_from_cond_expr (value_range *vr,
> gassign *stmt)
>     on the range of its operand and the expression code.  */
>
>  static void
> -extract_range_from_comparison (value_range *vr, enum tree_code code,
> +extract_range_from_comparison (value_range *vr,
> +                              enum tree_code code,
>                                tree type, tree op0, tree op1)
>  {
>    bool sop = false;
>
> remove these kind of no-op changes.

Done.

>
> +/* Initialize local data structures for VRP.  If DOM_P is true,
> +   we will be calling this from early_vrp where value range propagation
> +   is done by visiting stmts in dominator tree.  ssa_propagate engine
> +   is not used in this case and that part of the ininitialization will
> +   be skipped.  */
>
>  static void
> -vrp_initialize (void)
> +vrp_initialize (bool dom_p)
>  {
>    basic_block bb;
>
> @@ -6949,6 +7010,9 @@ vrp_initialize (void)
>    vr_phi_edge_counts = XCNEWVEC (int, num_ssa_names);
>    bitmap_obstack_initialize (&vrp_equiv_obstack);
>
> +  if (dom_p)
> +    return;
> +
>
> split the function instead.
>
> @@ -7926,7 +7992,8 @@ vrp_visit_switch_stmt (gswitch *stmt, edge *taken_edge_p)
>     If STMT produces a varying value, return SSA_PROP_VARYING.  */
>
>  static enum ssa_prop_result
> -vrp_visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
> +vrp_visit_stmt_worker (gimple *stmt, bool dom_p,  edge *taken_edge_p,
> +                      tree *output_p)
>  {
>    tree def;
>    ssa_op_iter iter;
> @@ -7940,7 +8007,7 @@ vrp_visit_stmt (gimple *stmt, edge
> *taken_edge_p, tree *output_p)
>    if (!stmt_interesting_for_vrp (stmt))
>      gcc_assert (stmt_ends_bb_p (stmt));
>    else if (is_gimple_assign (stmt) || is_gimple_call (stmt))
> -    return vrp_visit_assignment_or_call (stmt, output_p);
> +    return vrp_visit_assignment_or_call (stmt, dom_p, output_p);
>    else if (gimple_code (stmt) == GIMPLE_COND)
>      return vrp_visit_cond_stmt (as_a <gcond *> (stmt), taken_edge_p);
>    else if (gimple_code (stmt) == GIMPLE_SWITCH)
> @@ -7954,6 +8021,12 @@ vrp_visit_stmt (gimple *stmt, edge
> *taken_edge_p, tree *output_p)
>    return SSA_PROP_VARYING;
>  }
>
> +static enum ssa_prop_result
> +vrp_visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
> +{
> +  return vrp_visit_stmt_worker (stmt, false, taken_edge_p, output_p);
> +}
>
> as said the refactoring that would be appreciated is to split out the
> update_value_range calls
> from the worker functions so you can call the respective functions
> from the DOM implementations.
> That they are globbed in vrp_visit_stmt currently is due to the API of
> the SSA propagator.
Sent this as separate patch for easy reviewing and testing.

>
> @@ -8768,6 +8842,12 @@ vrp_visit_phi_node (gphi *phi)
>               fprintf (dump_file, "\n");
>             }
>
> +         if (dom_p && vr_arg.type == VR_UNDEFINED)
> +           {
> +             set_value_range_to_varying (&vr_result);
> +             break;
> +           }
> +
>
> eh...  ok, so another way to attack this is, instead of initializing
> the lattice to sth else
> than VR_UNDEFINED, make sure to drop the lattice to varying for all PHI args on
> yet unvisited incoming edges (you're not doing optimistic VRP).  That's the only
> place you _have_ to do it.

Even when it is initialize (as I am doing now), we can still end up with 
VR_UNDEFINED during the propagation.  I have just left the above so that 
we dont end up with the wrong VR.

I also noticed that g++.dg/warn/pr33738.C testcase is now failing. This 
is because, with early-vrp setting value range ccp2 is optimizing 
without issuing a warning. I will look into it.

bootstrap and regression testing is in progress.

Thanks,
Kugan

[-- Attachment #2: 0003-Add-Early-VRP.patch --]
[-- Type: text/x-patch, Size: 25506 bytes --]

From 255054400db3f6cd20abc89f3735c7e488985c1e Mon Sep 17 00:00:00 2001
From: Kugan Vivekanandarajah <kugan.vivekanandarajah@linaro.org>
Date: Mon, 15 Aug 2016 10:11:36 +1000
Subject: [PATCH 3/5] Add Early VRP

---
 gcc/common.opt                            |   4 +
 gcc/doc/invoke.texi                       |   9 +
 gcc/passes.def                            |   1 +
 gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C |   2 +-
 gcc/testsuite/gcc.dg/tree-ssa/evrp1.c     |  13 +
 gcc/testsuite/gcc.dg/tree-ssa/evrp2.c     |  18 ++
 gcc/testsuite/gcc.dg/tree-ssa/evrp3.c     |  15 ++
 gcc/testsuite/gcc.dg/tree-ssa/pr22117.c   |   2 +-
 gcc/testsuite/gcc.dg/tree-ssa/pr25382.c   |   2 +-
 gcc/testsuite/gcc.dg/tree-ssa/vrp58.c     |   4 +-
 gcc/testsuite/gcc.dg/tree-ssa/vrp67.c     |   5 +-
 gcc/timevar.def                           |   1 +
 gcc/tree-pass.h                           |   1 +
 gcc/tree-vrp.c                            | 419 ++++++++++++++++++++++++++----
 14 files changed, 434 insertions(+), 62 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/evrp1.c
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/evrp2.c
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/evrp3.c

diff --git a/gcc/common.opt b/gcc/common.opt
index 65a9762..aec618e 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2499,6 +2499,10 @@ ftree-vrp
 Common Report Var(flag_tree_vrp) Init(0) Optimization
 Perform Value Range Propagation on trees.
 
+ftree-evrp
+Common Report Var(flag_early_vrp) Init(1) Optimization
+This can be used to disable Early Value Range Propagation on trees.
+
 fsplit-paths
 Common Report Var(flag_split_paths) Init(0) Optimization
 Split paths leading to loop backedges.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index d04be6f..3cad409 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -7715,6 +7715,10 @@ enabled by default at @option{-O2} and higher.  Null pointer check
 elimination is only done if @option{-fdelete-null-pointer-checks} is
 enabled.
 
+@item -fdisable-tree-evrp
+@opindex fdisable-tree-evrp
+Disables Early Value Range Propagation on trees.
+
 @item -fsplit-paths
 @opindex fsplit-paths
 Split paths leading to loop backedges.  This can improve dead code
@@ -12350,6 +12354,11 @@ is made by appending @file{.slp} to the source file name.
 Dump each function after Value Range Propagation (VRP).  The file name
 is made by appending @file{.vrp} to the source file name.
 
+@item early vrp
+@opindex fdump-tree-evrp
+Dump each function after Early Value Range Propagation (EVRP).  The file name
+is made by appending @file{.evrp} to the source file name.
+
 @item oaccdevlow
 @opindex fdump-tree-oaccdevlow
 Dump each function after applying device-specific OpenACC transformations.
diff --git a/gcc/passes.def b/gcc/passes.def
index 3647e90..ebd360b 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -89,6 +89,7 @@ along with GCC; see the file COPYING3.  If not see
 	     execute TODO_rebuild_alias at this point.  */
 	  NEXT_PASS (pass_build_ealias);
 	  NEXT_PASS (pass_fre);
+	  NEXT_PASS (pass_early_vrp);
 	  NEXT_PASS (pass_merge_phi);
           NEXT_PASS (pass_dse);
 	  NEXT_PASS (pass_cd_dce);
diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C b/gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C
index 5e09583..dce05d6 100644
--- a/gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C
+++ b/gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O -fdump-tree-forwprop1" } */
+/* { dg-options "-O -fno-tree-evrp -fdump-tree-forwprop1" } */
 
 #include <new>
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/evrp1.c b/gcc/testsuite/gcc.dg/tree-ssa/evrp1.c
new file mode 100644
index 0000000..8c6e4e6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/evrp1.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+int foo (int i);
+int bar (int j)
+{
+  if (j > 2)
+    return foo (j + 2);
+  else
+    return j;
+}
+
+/* { dg-final { scan-tree-dump "\\\[5, \\+INF" "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/evrp2.c b/gcc/testsuite/gcc.dg/tree-ssa/evrp2.c
new file mode 100644
index 0000000..e6d4235
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/evrp2.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+int foo (int i);
+int bar2 (int j)
+{
+  if (j > 2)
+    {
+      if (j < 7)
+	return foo (j + 1);
+      else
+	return foo (j + 2);
+    }
+  return j;
+}
+
+
+/* { dg-final { scan-tree-dump "\\\[4, 7\\\]" "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/evrp3.c b/gcc/testsuite/gcc.dg/tree-ssa/evrp3.c
new file mode 100644
index 0000000..1a3bbd5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/evrp3.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+int foo (int i);
+void bar (int j)
+{
+  unsigned int i;
+  for (i = 0; i < 10; ++i)
+    {
+      bar (i + 1);
+    }
+}
+
+/* { dg-final { scan-tree-dump "\\\[1, 10\\\]" "evrp" } } */
+
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c b/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c
index 7efdd63..d4fcdfe 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c
@@ -3,7 +3,7 @@
    known to be zero after entering the first two "if" statements.  */
 
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1" } */
+/* { dg-options "-O2 -fno-tree-evrp -fdump-tree-vrp1" } */
 
 void link_error (void);
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c b/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c
index dcf9148..c4fda8b 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c
@@ -3,7 +3,7 @@
    Check that VRP now gets ranges from BIT_AND_EXPRs.  */
 
 /* { dg-do compile } */
-/* { dg-options "-O2 -fno-tree-ccp -fdump-tree-vrp1" } */
+/* { dg-options "-O2 -fno-tree-ccp -fdump-tree-vrp" } */
 
 int
 foo (int a)
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp58.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp58.c
index 5b44ae2..6df91ca 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp58.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp58.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1-details" } */
+/* { dg-options "-O2 -fdump-tree-evrp-details" } */
 
 long long
 foo (long long a, signed char b, signed char c)
@@ -9,4 +9,4 @@ foo (long long a, signed char b, signed char c)
 }
 
 /* { dg-final { scan-tree-dump "Folded into" "vrp1" { target int32plus } } } */
-/* { dg-final { scan-tree-dump "Folding statement: _\[0-9\]\* = \\(long long int\\) bc_\[0-9\]\*;" "vrp1" { target int16 } } } */
+/* { dg-final { scan-tree-dump "Folding statement: _\[0-9\]\* = \\(long long int\\) bc_\[0-9\]\*;" "evrp" { target int16 } } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp67.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp67.c
index ef5e8f9..ec1cc9a 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp67.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp67.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1" } */
+/* { dg-options "-O2 -fdump-tree-ccp2 -fdump-tree-vrp1" } */
 
 extern void link_error (void);
 
@@ -36,4 +36,5 @@ unsigned baz (unsigned i)
   return i;
 }
 
-/* { dg-final { scan-tree-dump-times "Folding predicate" 3 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "Folding predicate" 1 "ccp2" } } */
+/* { dg-final { scan-tree-dump-times "Folding predicate" 2 "vrp1" } } */
diff --git a/gcc/timevar.def b/gcc/timevar.def
index 5f12118..8837832 100644
--- a/gcc/timevar.def
+++ b/gcc/timevar.def
@@ -149,6 +149,7 @@ DEFTIMEVAR (TV_TREE_CFG		     , "tree CFG construction")
 DEFTIMEVAR (TV_TREE_CLEANUP_CFG	     , "tree CFG cleanup")
 DEFTIMEVAR (TV_TREE_TAIL_MERGE       , "tree tail merge")
 DEFTIMEVAR (TV_TREE_VRP              , "tree VRP")
+DEFTIMEVAR (TV_TREE_EARLY_VRP        , "tree Early VRP")
 DEFTIMEVAR (TV_TREE_COPY_PROP        , "tree copy propagation")
 DEFTIMEVAR (TV_FIND_REFERENCED_VARS  , "tree find ref. vars")
 DEFTIMEVAR (TV_TREE_PTA		     , "tree PTA")
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index 36299a6..d836d57 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -440,6 +440,7 @@ extern gimple_opt_pass *make_pass_fre (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_check_data_deps (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_copy_prop (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_isolate_erroneous_paths (gcc::context *ctxt);
+extern gimple_opt_pass *make_pass_early_vrp (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_vrp (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_uncprop (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_return_slot (gcc::context *ctxt);
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index b56ceec..1eb0fa7 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -62,7 +62,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "alloc-pool.h"
 #include "domwalk.h"
 
-#define VR_INITIALIZER { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL }
+#define VR_INITIALIZER { early_vrp_p ? VR_VARYING: VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL }
 
 /* Allocation pools for tree-vrp allocations.  */
 static object_allocator<value_range> vrp_value_range_pool ("Tree VRP value ranges");
@@ -72,6 +72,9 @@ static bitmap_obstack vrp_equiv_obstack;
    for still active basic-blocks.  */
 static sbitmap *live;
 
+/* True if we are in DOM based Early VRP.  */
+static bool early_vrp_p = false;
+
 /* Return true if the SSA name NAME is live on the edge E.  */
 
 static bool
@@ -669,6 +672,8 @@ get_value_range (const_tree var)
   /* Create a default value range.  */
   vr_value[ver] = vr = vrp_value_range_pool.allocate ();
   memset (vr, 0, sizeof (*vr));
+  if (early_vrp_p)
+    vr->type = VR_VARYING;
 
   /* Defer allocating the equivalence set.  */
   vr->equiv = NULL;
@@ -1441,44 +1446,17 @@ op_with_boolean_value_range_p (tree op)
 	  && integer_onep (vr->max));
 }
 
-/* Extract value range information from an ASSERT_EXPR EXPR and store
-   it in *VR_P.  */
+/* Extract value range information for VAR when (OP COND_CODE LIMIT) is
+   true and store it in *VR_P.  */
 
 static void
-extract_range_from_assert (value_range *vr_p, tree expr)
+extract_range_for_var_from_comparison_expr (tree var, enum tree_code cond_code,
+					    tree op, tree limit,
+					    value_range *vr_p)
 {
-  tree var, cond, limit, min, max, type;
+  tree  min, max, type;
   value_range *limit_vr;
-  enum tree_code cond_code;
-
-  var = ASSERT_EXPR_VAR (expr);
-  cond = ASSERT_EXPR_COND (expr);
-
-  gcc_assert (COMPARISON_CLASS_P (cond));
-
-  /* Find VAR in the ASSERT_EXPR conditional.  */
-  if (var == TREE_OPERAND (cond, 0)
-      || TREE_CODE (TREE_OPERAND (cond, 0)) == PLUS_EXPR
-      || TREE_CODE (TREE_OPERAND (cond, 0)) == NOP_EXPR)
-    {
-      /* If the predicate is of the form VAR COMP LIMIT, then we just
-	 take LIMIT from the RHS and use the same comparison code.  */
-      cond_code = TREE_CODE (cond);
-      limit = TREE_OPERAND (cond, 1);
-      cond = TREE_OPERAND (cond, 0);
-    }
-  else
-    {
-      /* If the predicate is of the form LIMIT COMP VAR, then we need
-	 to flip around the comparison code to create the proper range
-	 for VAR.  */
-      cond_code = swap_tree_comparison (TREE_CODE (cond));
-      limit = TREE_OPERAND (cond, 0);
-      cond = TREE_OPERAND (cond, 1);
-    }
-
   limit = avoid_overflow_infinity (limit);
-
   type = TREE_TYPE (var);
   gcc_assert (limit != var);
 
@@ -1524,15 +1502,15 @@ extract_range_from_assert (value_range *vr_p, tree expr)
      as well build the range [b_4, +INF] for it.
      One special case we handle is extracting a range from a
      range test encoded as (unsigned)var + CST <= limit.  */
-  if (TREE_CODE (cond) == NOP_EXPR
-      || TREE_CODE (cond) == PLUS_EXPR)
+  if (TREE_CODE (op) == NOP_EXPR
+      || TREE_CODE (op) == PLUS_EXPR)
     {
-      if (TREE_CODE (cond) == PLUS_EXPR)
+      if (TREE_CODE (op) == PLUS_EXPR)
         {
-          min = fold_build1 (NEGATE_EXPR, TREE_TYPE (TREE_OPERAND (cond, 1)),
-			     TREE_OPERAND (cond, 1));
+	  min = fold_build1 (NEGATE_EXPR, TREE_TYPE (TREE_OPERAND (op, 1)),
+			     TREE_OPERAND (op, 1));
           max = int_const_binop (PLUS_EXPR, limit, min);
-	  cond = TREE_OPERAND (cond, 0);
+	  op = TREE_OPERAND (op, 0);
 	}
       else
 	{
@@ -1716,6 +1694,41 @@ extract_range_from_assert (value_range *vr_p, tree expr)
   vrp_intersect_ranges (vr_p, get_value_range (var));
 }
 
+/* Extract value range information from an ASSERT_EXPR EXPR and store
+   it in *VR_P.  */
+
+static void
+extract_range_from_assert (value_range *vr_p, tree expr)
+{
+  tree var = ASSERT_EXPR_VAR (expr);
+  tree cond = ASSERT_EXPR_COND (expr);
+  tree limit, op;
+  enum tree_code cond_code;
+  gcc_assert (COMPARISON_CLASS_P (cond));
+
+  /* Find VAR in the ASSERT_EXPR conditional.  */
+  if (var == TREE_OPERAND (cond, 0)
+      || TREE_CODE (TREE_OPERAND (cond, 0)) == PLUS_EXPR
+      || TREE_CODE (TREE_OPERAND (cond, 0)) == NOP_EXPR)
+    {
+      /* If the predicate is of the form VAR COMP LIMIT, then we just
+	 take LIMIT from the RHS and use the same comparison code.  */
+      cond_code = TREE_CODE (cond);
+      limit = TREE_OPERAND (cond, 1);
+      op = TREE_OPERAND (cond, 0);
+    }
+  else
+    {
+      /* If the predicate is of the form LIMIT COMP VAR, then we need
+	 to flip around the comparison code to create the proper range
+	 for VAR.  */
+      cond_code = swap_tree_comparison (TREE_CODE (cond));
+      limit = TREE_OPERAND (cond, 0);
+      op = TREE_OPERAND (cond, 1);
+    }
+  extract_range_for_var_from_comparison_expr (var, cond_code, op,
+					      limit, vr_p);
+}
 
 /* Extract range information from SSA name VAR and store it in VR.  If
    VAR has an interesting range, use it.  Otherwise, create the
@@ -6938,19 +6951,28 @@ stmt_interesting_for_vrp (gimple *stmt)
   return false;
 }
 
-
-/* Initialize local data structures for VRP.  */
+/* Initialize VRP lattice.  */
 
 static void
-vrp_initialize (void)
+vrp_initialize_lattice ()
 {
-  basic_block bb;
-
   values_propagated = false;
   num_vr_values = num_ssa_names;
   vr_value = XCNEWVEC (value_range *, num_vr_values);
   vr_phi_edge_counts = XCNEWVEC (int, num_ssa_names);
   bitmap_obstack_initialize (&vrp_equiv_obstack);
+}
+
+/* Initialize local data structures for VRP.  If DOM_P is true,
+   we will be calling this from early_vrp where value range propagation
+   is done by visiting stmts in dominator tree.  ssa_propagate engine
+   is not used in this case and that part of the ininitialization will
+   be skipped.  */
+
+static void
+vrp_initialize ()
+{
+  basic_block bb;
 
   FOR_EACH_BB_FN (bb, cfun)
     {
@@ -8803,6 +8825,12 @@ vrp_visit_phi_node_worker (gphi *phi, value_range *vr_result)
 	      fprintf (dump_file, "\n");
 	    }
 
+	  if (early_vrp_p && vr_arg.type == VR_UNDEFINED)
+	    {
+	      set_value_range_to_varying (vr_result);
+	      break;
+	    }
+
 	  if (first)
 	    copy_value_range (vr_result, &vr_arg);
 	  else
@@ -8831,6 +8859,7 @@ vrp_visit_phi_node_worker (gphi *phi, value_range *vr_result)
      simulate this PHI again with the same number of edges then iterate
      one more time.  */
   if (edges > 0
+      && !early_vrp_p
       && gimple_phi_num_args (phi) > 1
       && edges == old_edges
       && lhs_vr->type != VR_UNDEFINED
@@ -8898,7 +8927,8 @@ scev_check:
      scev_check can be reached from two paths, one is a fall through from above
      "varying" label, the other is direct goto from code block which tries to
      avoid infinite simulation.  */
-  if ((l = loop_containing_stmt (phi))
+  if (!early_vrp_p
+      && (l = loop_containing_stmt (phi))
       && l->header == gimple_bb (phi))
     adjust_range_with_scev (vr_result, l, phi, lhs);
 
@@ -10419,6 +10449,22 @@ finalize_jump_threads (void)
   delete equiv_stack;
 }
 
+/* Free VRP lattice.  */
+
+static void
+vrp_free_lattice ()
+{
+  /* Free allocated memory.  */
+  free (vr_value);
+  free (vr_phi_edge_counts);
+  bitmap_obstack_release (&vrp_equiv_obstack);
+  vrp_value_range_pool.release ();
+
+  /* So that we can distinguish between VRP data being available
+     and not available.  */
+  vr_value = NULL;
+  vr_phi_edge_counts = NULL;
+}
 
 /* Traverse all the blocks folding conditionals with known ranges.  */
 
@@ -10465,17 +10511,237 @@ vrp_finalize (bool warn_array_bounds_p)
   /* We must identify jump threading opportunities before we release
      the datastructures built by VRP.  */
   identify_jump_threads ();
+}
 
-  /* Free allocated memory.  */
-  free (vr_value);
-  free (vr_phi_edge_counts);
-  bitmap_obstack_release (&vrp_equiv_obstack);
-  vrp_value_range_pool.release ();
+/* Check to see if the PHI stmt has any back edges.  In dominator based
+   VRP, if we have back-edges, we will have to set the resulting VR to
+   varying.  This is because we dont iteratetively visit the stmt till
+   we reach fixed point.  */
 
-  /* So that we can distinguish between VRP data being available
-     and not available.  */
-  vr_value = NULL;
-  vr_phi_edge_counts = NULL;
+static bool
+visit_phi_node_p (gphi *phi)
+{
+  for (unsigned int i = 0; i < gimple_phi_num_args (phi); i++)
+    {
+      edge e = gimple_phi_arg_edge (phi, i);
+      if (e->flags & (EDGE_DFS_BACK | EDGE_COMPLEX))
+	return false;
+    }
+  return true;
+}
+
+/* evrp_dom_walker visits the basic blocks in the dominance order and set
+   the Value Ranges (VR) for SSA_NAMEs in the scope.  Use this VR to
+   discover more VRs.  */
+
+class evrp_dom_walker : public dom_walker
+{
+public:
+  evrp_dom_walker ()
+    : dom_walker (CDI_DOMINATORS), stack (10) {}
+
+  virtual edge before_dom_children (basic_block);
+  virtual void after_dom_children (basic_block);
+  void push_value_range (const_tree var, value_range *vr);
+  value_range *pop_value_range (const_tree var);
+
+  /* Cond_stack holds the old VR.  */
+  auto_vec<std::pair <const_tree, value_range*> > stack;
+};
+
+/* See if there is any new scope is entered with new VR and set that VR to
+   ssa_name before visiting the statements in the scope.  */
+
+edge
+evrp_dom_walker::before_dom_children (basic_block bb)
+{
+  value_range *new_vr = NULL;
+  tree op0 = NULL_TREE;
+  push_value_range (NULL_TREE, NULL);
+  if (single_pred_p (bb))
+    {
+      edge e = single_pred_edge (bb);
+      value_range vr = VR_INITIALIZER;
+      gimple *stmt = last_stmt (e->src);
+      if (stmt
+	  && gimple_code (stmt) == GIMPLE_COND
+	  && (op0 = gimple_cond_lhs (stmt))
+	  && TREE_CODE (op0) == SSA_NAME
+	  && INTEGRAL_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt))))
+	{
+	  /* Entering a new scope.  Try to see if we can find a VR
+	     here.  */
+	  tree op1 = gimple_cond_rhs (stmt);
+	  tree_code code = gimple_cond_code (stmt);
+	  value_range *old_vr = get_value_range (op0);
+
+	  if (TREE_OVERFLOW_P (op1))
+	    op1 = drop_tree_overflow (op1);
+
+	  /* If condition is false, invert the cond.  */
+	  if (e->flags & EDGE_FALSE_VALUE)
+	    code = invert_tree_comparison (gimple_cond_code (stmt),
+					   HONOR_NANS (op0));
+	  /* Discover VR when condition is true.  */
+	  extract_range_for_var_from_comparison_expr (op0, code, op0, op1, &vr);
+	  if (old_vr->type == VR_RANGE || old_vr->type == VR_ANTI_RANGE)
+	    vrp_intersect_ranges (&vr, old_vr);
+
+	  /* If we found any usable VR, set the VR to ssa_name and create a
+	     PUSH old value in the stack with the old VR.  */
+	  if (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE)
+	    {
+	      new_vr = vrp_value_range_pool.allocate ();
+	      *new_vr = vr;
+	      push_value_range (op0, new_vr);
+	    }
+	}
+    }
+
+  /* Visit PHI stmts and discover any new VRs possible.  */
+  gimple_stmt_iterator gsi;
+  for (gphi_iterator gpi = gsi_start_phis (bb);
+       !gsi_end_p (gpi); gsi_next (&gpi))
+    {
+      gphi *phi = gpi.phi ();
+      if (stmt_interesting_for_vrp (phi))
+	{
+	  tree lhs = PHI_RESULT (phi);
+	  value_range vr_result = VR_INITIALIZER;
+	  /* See if the PHI has any back edges.  If there is any
+	     backedges we will have to set the lattice to
+	     VR_VARYING as we will not be traversing it till it
+	     reach fix point.  */
+	  if (visit_phi_node_p (phi))
+	    vrp_visit_phi_node_worker (phi, &vr_result);
+	  else
+	    set_value_range_to_varying (&vr_result);
+	  update_value_range (lhs, &vr_result);
+	}
+    }
+
+  /* Visit all other stmts and discover any new VRs possible.  */
+  for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+    {
+      gimple *stmt = gsi_stmt (gsi);
+      edge taken_edge;
+      tree output;
+      /* TODO, if found taken_edge, we should visit (return it) and travel
+	 again to improve VR as done in DOM/SCCVN optimizations.  It should
+	 be done carefully as stmts might prematurely leave a BB like
+	 in EH.  */
+      if (stmt_interesting_for_vrp (stmt))
+	{
+	  tree lhs = gimple_get_lhs (stmt);
+	  value_range vr = VR_INITIALIZER;
+	  vrp_visit_stmt_worker (stmt, &taken_edge, &output, &vr);
+	  update_value_range (lhs, &vr);
+
+	  /* Try folding stmts with the VR discovered.  */
+	  if (fold_stmt (&gsi, follow_single_use_edges))
+	    update_stmt (gsi_stmt (gsi));
+
+	  def_operand_p def_p = SINGLE_SSA_DEF_OPERAND (stmt, SSA_OP_DEF);
+	  /* Set the SSA with the value range.  */
+	  if (def_p
+	      && TREE_CODE (DEF_FROM_PTR (def_p)) == SSA_NAME
+	      && INTEGRAL_TYPE_P (TREE_TYPE (DEF_FROM_PTR (def_p))))
+	    {
+	      tree def = DEF_FROM_PTR (def_p);
+	      unsigned ver = SSA_NAME_VERSION (def);
+	      if ((vr_value[ver]->type == VR_RANGE
+		   || vr_value[ver]->type == VR_ANTI_RANGE)
+		  && (TREE_CODE (vr_value[ver]->min) == INTEGER_CST)
+		  && (TREE_CODE (vr_value[ver]->max) == INTEGER_CST))
+		set_range_info (def, vr_value[ver]->type, vr_value[ver]->min,
+				vr_value[ver]->max);
+	    }
+	}
+    }
+  return NULL;
+}
+
+/* Restore/pop VRs valid only for BB when we leave BB.  */
+
+void
+evrp_dom_walker::after_dom_children (basic_block bb ATTRIBUTE_UNUSED)
+{
+  gcc_checking_assert (!stack.is_empty ());
+  while (stack.last ().first != NULL_TREE)
+    pop_value_range (stack.last ().first);
+  pop_value_range (stack.last ().first);
+}
+
+/* Push the Value Range of VAR to the stack and update it with new VR.  */
+
+void
+evrp_dom_walker::push_value_range (const_tree var, value_range *vr)
+{
+  if (vr != NULL)
+    {
+      unsigned ver = SSA_NAME_VERSION (var);
+      gcc_checking_assert (vr_value);
+      stack.safe_push (std::make_pair (var, vr_value[ver]));
+
+      if (ver < num_vr_values)
+	vr_value[ver] = vr;
+    }
+  else
+    stack.safe_push (std::make_pair (var, vr));
+}
+
+/* Pop the Value Range from the vrp_stack and update VAR with it.  */
+
+value_range *
+evrp_dom_walker::pop_value_range (const_tree var)
+{
+  value_range *vr = stack.last ().second;
+  if (vr != NULL)
+    {
+      unsigned ver = SSA_NAME_VERSION (var);
+      gcc_checking_assert (var == stack.last ().first);
+      gcc_checking_assert (vr_value);
+
+      if (ver < num_vr_values)
+	vr_value[ver] = vr;
+    }
+  stack.pop ();
+  return vr;
+}
+
+
+/* Main entry point for the early vrp pass which is a simplified non-iterative
+   version of VRP where basic blocks are visited in dominance order.  Value
+   ranges discovered in early vrp will also be used by ipa-vrp.  */
+
+static unsigned int
+execute_early_vrp ()
+{
+  edge e;
+  edge_iterator ei;
+  basic_block bb;
+  early_vrp_p = true;
+
+  calculate_dominance_info (CDI_DOMINATORS);
+  FOR_EACH_BB_FN (bb, cfun)
+    {
+      FOR_EACH_EDGE (e, ei, bb->preds)
+	e->flags |= EDGE_EXECUTABLE;
+    }
+  vrp_initialize_lattice ();
+
+  /* Walk stmts in dominance order and propagate VRP.  */
+  evrp_dom_walker walker;
+  walker.walk (ENTRY_BLOCK_PTR_FOR_FN (cfun));
+  if (dump_file)
+    {
+      fprintf (dump_file, "\nValue ranges after Early VRP:\n\n");
+      dump_all_value_ranges (dump_file);
+      fprintf (dump_file, "\n");
+    }
+  vrp_free_lattice ();
+  early_vrp_p = false;
+  return 0;
 }
 
 
@@ -10546,9 +10812,11 @@ execute_vrp (bool warn_array_bounds_p)
   /* For visiting PHI nodes we need EDGE_DFS_BACK computed.  */
   mark_dfs_back_edges ();
 
+  vrp_initialize_lattice ();
   vrp_initialize ();
   ssa_propagate (vrp_visit_stmt, vrp_visit_phi_node);
   vrp_finalize (warn_array_bounds_p);
+  vrp_free_lattice ();
 
   free_numbers_of_iterations_estimates (cfun);
 
@@ -10646,3 +10914,44 @@ make_pass_vrp (gcc::context *ctxt)
 {
   return new pass_vrp (ctxt);
 }
+
+namespace {
+
+const pass_data pass_data_early_vrp =
+{
+  GIMPLE_PASS, /* type */
+  "evrp", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_TREE_EARLY_VRP, /* tv_id */
+  PROP_ssa, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  ( TODO_cleanup_cfg | TODO_update_ssa | TODO_verify_all ),
+};
+
+class pass_early_vrp : public gimple_opt_pass
+{
+public:
+  pass_early_vrp (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_early_vrp, ctxt)
+    {}
+
+  /* opt_pass methods: */
+  opt_pass * clone () { return new pass_early_vrp (m_ctxt); }
+  virtual bool gate (function *)
+    {
+      return flag_early_vrp != 0 && flag_tree_vrp != 0;
+    }
+  virtual unsigned int execute (function *)
+    { return execute_early_vrp (); }
+
+}; // class pass_vrp
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_early_vrp (gcc::context *ctxt)
+{
+  return new pass_early_vrp (ctxt);
+}
+
-- 
2.7.4


^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Re-factor tree-vrp to factor out common code
  2016-07-23 10:12         ` kugan
@ 2016-08-16  8:09           ` kugan
  2016-08-16 11:56             ` Richard Biener
  0 siblings, 1 reply; 67+ messages in thread
From: kugan @ 2016-08-16  8:09 UTC (permalink / raw)
  To: Richard Biener; +Cc: gcc-patches, Jan Hubicka, Martin Jambor

[-- Attachment #1: Type: text/plain, Size: 1006 bytes --]




On 23/07/16 20:12, kugan wrote:
> Hi Richard,
>
>>> As we had value_range_type in tree-ssanames.h why not put value_range there?
>>>
>> For IPA_VRP, we now need value_range used in ipa-prop.h (in ipa-vrp
>> patch). Based on this, attached patch now adds struct value_range to
>> tree-ssanames.h and fixes the header files. Please note that I also had
>> to add other headers in few places due to the dependency. Are you OK
>> with this ?
> Here is alternate patch where we keep struct value_range and enum
> value_range_type to tree-vrp.h. May be it is a better approach? Please
> let me know what is your preference.
>

Ping?

This patch places value_range_type and value_range in tree-vrp.h. May be 
this is better?

Alternate patch which keeps value_range_type and value_range in 
tree-ssanames.h is in:
https://gcc.gnu.org/ml/gcc-patches/2016-07/msg01491.html

I also added the necessary header files changed needed for ipa-vrp as 
part of this patch so that changes needed are clear.

Thaks,
Kugan

[-- Attachment #2: 0001-Factor-out-and-expose-value_range-api-for-IPA-VRP.patch --]
[-- Type: text/x-patch, Size: 16494 bytes --]

From b2d81fdf31df08ca94da46fe93faf1a7f2d0ac1a Mon Sep 17 00:00:00 2001
From: Kugan Vivekanandarajah <kugan.vivekanandarajah@linaro.org>
Date: Mon, 15 Aug 2016 09:19:52 +1000
Subject: [PATCH 1/5] Factor out and expose value_range api for IPA-VRP

---
 gcc/Makefile.in            |  1 +
 gcc/asan.c                 |  1 +
 gcc/builtins.c             |  1 +
 gcc/cgraph.c               |  1 +
 gcc/cgraphunit.c           |  1 +
 gcc/fold-const.c           |  1 +
 gcc/gengtype.c             |  2 +-
 gcc/gimple-builder.c       |  1 +
 gcc/gimple-laddress.c      |  1 +
 gcc/hsa-gen.c              |  1 +
 gcc/internal-fn.c          |  1 +
 gcc/ipa-cp.c               |  1 +
 gcc/ipa-devirt.c           |  1 +
 gcc/ipa-inline-transform.c |  1 +
 gcc/ipa-inline.c           |  1 +
 gcc/ipa-profile.c          |  1 +
 gcc/ipa-utils.c            |  1 +
 gcc/ipa.c                  |  1 +
 gcc/lto/lto-partition.c    |  1 +
 gcc/lto/lto.c              |  1 +
 gcc/ssa.h                  |  1 +
 gcc/targhooks.c            |  1 +
 gcc/toplev.c               |  1 +
 gcc/tree-ssa-address.c     |  1 +
 gcc/tree-ssanames.h        |  5 -----
 gcc/tree-vrp.c             | 43 +++++++-----------------------------
 gcc/tree-vrp.h             | 54 ++++++++++++++++++++++++++++++++++++++++++++++
 27 files changed, 86 insertions(+), 41 deletions(-)
 create mode 100644 gcc/tree-vrp.h

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 7a0160f..8d7cc51 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -2456,6 +2456,7 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
   $(srcdir)/tree-phinodes.c \
   $(srcdir)/tree-ssa-alias.h \
   $(srcdir)/tree-ssanames.h \
+  $(srcdir)/tree-vrp.h \
   $(srcdir)/ipa-prop.h \
   $(srcdir)/trans-mem.c \
   $(srcdir)/lto-streamer.h \
diff --git a/gcc/asan.c b/gcc/asan.c
index 9047e1b..4fe2447 100644
--- a/gcc/asan.c
+++ b/gcc/asan.c
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-pass.h"
 #include "tm_p.h"
 #include "stringpool.h"
+#include "tree-vrp.h"
 #include "tree-ssanames.h"
 #include "optabs.h"
 #include "emit-rtl.h"
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 03a0dc8..abc934b 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "predict.h"
 #include "tm_p.h"
 #include "stringpool.h"
+#include "tree-vrp.h"
 #include "tree-ssanames.h"
 #include "expmed.h"
 #include "optabs.h"
diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index 9bc5b6b..0a43850 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -49,6 +49,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "value-prof.h"
 #include "ipa-utils.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "ipa-inline.h"
 #include "cfgloop.h"
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index d8f7903..5bb6904 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -190,6 +190,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "toplev.h"
 #include "debug.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "gimple-pretty-print.h"
 #include "plugin.h"
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 30c1e0d..103ed2d 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -75,6 +75,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "md5.h"
 #include "case-cfn-macros.h"
 #include "stringpool.h"
+#include "tree-vrp.h"
 #include "tree-ssanames.h"
 #include "selftest.h"
 
diff --git a/gcc/gengtype.c b/gcc/gengtype.c
index 0518355..cecd552 100644
--- a/gcc/gengtype.c
+++ b/gcc/gengtype.c
@@ -1713,7 +1713,7 @@ open_base_files (void)
       "explow.h", "calls.h", "cilk.h", "emit-rtl.h", "varasm.h", "stmt.h",
       "expr.h", "alloc-pool.h", "cselib.h", "insn-addr.h", "optabs.h",
       "libfuncs.h", "debug.h", "internal-fn.h", "gimple-fold.h", "tree-eh.h",
-      "gimple-iterator.h", "gimple-ssa.h", "tree-cfg.h",
+      "gimple-iterator.h", "gimple-ssa.h", "tree-cfg.h", "tree-vrp.h",
       "tree-phinodes.h", "ssa-iterators.h", "stringpool.h", "tree-ssanames.h",
       "tree-ssa-loop.h", "tree-ssa-loop-ivopts.h", "tree-ssa-loop-manip.h",
       "tree-ssa-loop-niter.h", "tree-into-ssa.h", "tree-dfa.h", 
diff --git a/gcc/gimple-builder.c b/gcc/gimple-builder.c
index f124554..4fb21e4 100644
--- a/gcc/gimple-builder.c
+++ b/gcc/gimple-builder.c
@@ -24,6 +24,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree.h"
 #include "gimple.h"
 #include "stringpool.h"
+#include "tree-vrp.h"
 #include "tree-ssanames.h"
 
 
diff --git a/gcc/gimple-laddress.c b/gcc/gimple-laddress.c
index 4cc57cf..1a3c8e1 100644
--- a/gcc/gimple-laddress.c
+++ b/gcc/gimple-laddress.c
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "symtab.h"
 #include "tree.h"
 #include "stringpool.h"
+#include "tree-vrp.h"
 #include "tree-ssanames.h"
 #include "fold-const.h"
 #include "gimple-expr.h"
diff --git a/gcc/hsa-gen.c b/gcc/hsa-gen.c
index fb6d8a2..314bb5b 100644
--- a/gcc/hsa-gen.c
+++ b/gcc/hsa-gen.c
@@ -42,6 +42,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-ssa.h"
 #include "tree-phinodes.h"
 #include "stringpool.h"
+#include "tree-vrp.h"
 #include "tree-ssanames.h"
 #include "tree-dfa.h"
 #include "ssa-iterators.h"
diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c
index 49f3495..cd4b625 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -27,6 +27,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple.h"
 #include "predict.h"
 #include "stringpool.h"
+#include "tree-vrp.h"
 #include "tree-ssanames.h"
 #include "expmed.h"
 #include "optabs.h"
diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
index 5b6cb9a..e9562a5 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"
diff --git a/gcc/ipa-devirt.c b/gcc/ipa-devirt.c
index 2cf018b..62a08f8 100644
--- a/gcc/ipa-devirt.c
+++ b/gcc/ipa-devirt.c
@@ -122,6 +122,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-utils.h"
 #include "gimple-fold.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "ipa-inline.h"
 #include "demangle.h"
diff --git a/gcc/ipa-inline-transform.c b/gcc/ipa-inline-transform.c
index 98c7f96..efe7421 100644
--- a/gcc/ipa-inline-transform.c
+++ b/gcc/ipa-inline-transform.c
@@ -39,6 +39,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "cgraph.h"
 #include "tree-cfg.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "ipa-inline.h"
 #include "tree-inline.h"
diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
index 5c9366a..82bb94f 100644
--- a/gcc/ipa-inline.c
+++ b/gcc/ipa-inline.c
@@ -108,6 +108,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "params.h"
 #include "profile.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "ipa-inline.h"
 #include "ipa-utils.h"
diff --git a/gcc/ipa-profile.c b/gcc/ipa-profile.c
index da17bcd..e87615a 100644
--- a/gcc/ipa-profile.c
+++ b/gcc/ipa-profile.c
@@ -62,6 +62,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "value-prof.h"
 #include "tree-inline.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "ipa-inline.h"
 
diff --git a/gcc/ipa-utils.c b/gcc/ipa-utils.c
index 5eb7d5f..61d8dd1 100644
--- a/gcc/ipa-utils.c
+++ b/gcc/ipa-utils.c
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "splay-tree.h"
 #include "ipa-utils.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "ipa-inline.h"
 
diff --git a/gcc/ipa.c b/gcc/ipa.c
index 6f4693f..b02713f 100644
--- a/gcc/ipa.c
+++ b/gcc/ipa.c
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-iterator.h"
 #include "ipa-utils.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "ipa-inline.h"
 #include "dbgcnt.h"
diff --git a/gcc/lto/lto-partition.c b/gcc/lto/lto-partition.c
index 453343a..b52d175 100644
--- a/gcc/lto/lto-partition.c
+++ b/gcc/lto/lto-partition.c
@@ -31,6 +31,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "lto-streamer.h"
 #include "params.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "ipa-inline.h"
 #include "lto-partition.h"
diff --git a/gcc/lto/lto.c b/gcc/lto/lto.c
index 73d1e26..bbf02e8 100644
--- a/gcc/lto/lto.c
+++ b/gcc/lto/lto.c
@@ -36,6 +36,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "toplev.h"
 #include "stor-layout.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "common.h"
 #include "debug.h"
diff --git a/gcc/ssa.h b/gcc/ssa.h
index 40bc1c7..0ec1bf0 100644
--- a/gcc/ssa.h
+++ b/gcc/ssa.h
@@ -25,6 +25,7 @@ along with GCC; see the file COPYING3.  If not see
 
 #include "stringpool.h"
 #include "gimple-ssa.h"
+#include "tree-vrp.h"
 #include "tree-ssanames.h"
 #include "tree-phinodes.h"
 #include "ssa-iterators.h" 
diff --git a/gcc/targhooks.c b/gcc/targhooks.c
index 69037c1..6f67210 100644
--- a/gcc/targhooks.c
+++ b/gcc/targhooks.c
@@ -57,6 +57,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-expr.h"
 #include "tm_p.h"
 #include "stringpool.h"
+#include "tree-vrp.h"
 #include "tree-ssanames.h"
 #include "optabs.h"
 #include "regs.h"
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 2607904..668eccd 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -71,6 +71,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "dwarf2out.h"
 #include "ipa-reference.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "gcse.h"
 #include "tree-chkp.h"
diff --git a/gcc/tree-ssa-address.c b/gcc/tree-ssa-address.c
index b04545c..30f0c32 100644
--- a/gcc/tree-ssa-address.c
+++ b/gcc/tree-ssa-address.c
@@ -29,6 +29,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree.h"
 #include "gimple.h"
 #include "stringpool.h"
+#include "tree-vrp.h"
 #include "tree-ssanames.h"
 #include "expmed.h"
 #include "insn-config.h"
diff --git a/gcc/tree-ssanames.h b/gcc/tree-ssanames.h
index c81b1a1..8e66ce6 100644
--- a/gcc/tree-ssanames.h
+++ b/gcc/tree-ssanames.h
@@ -62,11 +62,6 @@ struct GTY ((variable_size)) range_info_def {
 #define num_ssa_names (vec_safe_length (cfun->gimple_df->ssa_names))
 #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 };
-
 /* Sets the value range to SSA.  */
 extern void set_range_info (tree, enum value_range_type, const wide_int_ref &,
 			    const wide_int_ref &);
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index 6934914..cf04bec 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -60,32 +60,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "case-cfn-macros.h"
 #include "params.h"
 #include "alloc-pool.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;
-};
+#include "domwalk.h"
 
 #define VR_INITIALIZER { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL }
 
@@ -109,8 +84,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 *,
 						     bool *);
@@ -4633,7 +4606,7 @@ compare_range_with_value (enum tree_code comp, value_range *vr, tree val,
 
 /* Debugging dumps.  */
 
-void dump_value_range (FILE *, value_range *);
+void dump_value_range (FILE *, const value_range *);
 void debug_value_range (value_range *);
 void dump_all_value_ranges (FILE *);
 void debug_all_value_ranges (void);
@@ -4644,7 +4617,7 @@ void debug_vr_equiv (bitmap);
 /* Dump value range VR to FILE.  */
 
 void
-dump_value_range (FILE *file, value_range *vr)
+dump_value_range (FILE *file, const value_range *vr)
 {
   if (vr == NULL)
     fprintf (file, "[]");
@@ -8534,7 +8507,7 @@ intersect_ranges (enum value_range_type *vr0type,
 /* Intersect the two value-ranges *VR0 and *VR1 and store the result
    in *VR0.  This may not be the smallest possible such range.  */
 
-static void
+void
 vrp_intersect_ranges_1 (value_range *vr0, value_range *vr1)
 {
   value_range saved;
@@ -8586,7 +8559,7 @@ vrp_intersect_ranges_1 (value_range *vr0, value_range *vr1)
     bitmap_copy (vr0->equiv, vr1->equiv);
 }
 
-static void
+void
 vrp_intersect_ranges (value_range *vr0, value_range *vr1)
 {
   if (dump_file && (dump_flags & TDF_DETAILS))
@@ -8611,7 +8584,7 @@ vrp_intersect_ranges (value_range *vr0, value_range *vr1)
    may not be the smallest possible such range.  */
 
 static void
-vrp_meet_1 (value_range *vr0, value_range *vr1)
+vrp_meet_1 (value_range *vr0, const value_range *vr1)
 {
   value_range saved;
 
@@ -8683,8 +8656,8 @@ vrp_meet_1 (value_range *vr0, value_range *vr1)
     bitmap_clear (vr0->equiv);
 }
 
-static void
-vrp_meet (value_range *vr0, value_range *vr1)
+void
+vrp_meet (value_range *vr0, const value_range *vr1)
 {
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
diff --git a/gcc/tree-vrp.h b/gcc/tree-vrp.h
new file mode 100644
index 0000000..e514c1e
--- /dev/null
+++ b/gcc/tree-vrp.h
@@ -0,0 +1,54 @@
+/* Support routines for Value Range Propagation (VRP).
+   Copyright (C) Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+/* 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;
+};
+
+extern void vrp_intersect_ranges (value_range *vr0, value_range *vr1);
+extern void vrp_meet (value_range *vr0, const value_range *vr1);
+extern void dump_value_range (FILE *, const value_range *);
+
-- 
2.7.4


^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] splits out the update_value_range calls from vrp_visit_stmt
  2016-08-16  7:39                             ` [RFC][IPA-VRP] splits out the update_value_range calls from vrp_visit_stmt kugan
@ 2016-08-16 10:58                               ` Richard Biener
  2016-08-17  2:27                                 ` kugan
  0 siblings, 1 reply; 67+ messages in thread
From: Richard Biener @ 2016-08-16 10:58 UTC (permalink / raw)
  To: kugan; +Cc: Andrew Pinski, gcc-patches, Jan Hubicka, Martin Jambor

On Tue, Aug 16, 2016 at 9:39 AM, kugan
<kugan.vivekanandarajah@linaro.org> wrote:
> Hi,
>
>> as said the refactoring that would be appreciated is to split out the
>> update_value_range calls
>> from the worker functions so you can call the respective functions
>> from the DOM implementations.
>> That they are globbed in vrp_visit_stmt currently is due to the API of
>> the SSA propagator.
>
>
> Here is a patch that just splits out the update_value_range calls
> visit_stmts. Bootstrapped and regression tested on x86_64-linux with no new
> regressions.
>
> I also verified few random fdump-tree-vrp1-details from stage2 to make sure
> they are same.
>
> Is this OK for trunk?

For vrp_visit_assignment_or_call please defer the question whether the update
is interesting (for the internal call stuff) to the caller and always
return new_vr.

Also do not perform the "not handled stmt" handling here but make the return
value reflect whether we handled the stmt or not and put

  /* Every other statement produces no useful ranges.  */
  FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_DEF)
    set_value_range_to_varying (get_value_range (def));

into the caller (as that's also a lattice-updating thing).

+static enum ssa_prop_result
+vrp_visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
+{
+  value_range vr = VR_INITIALIZER;
+  tree lhs = gimple_get_lhs (stmt);
+  bool vr_found = vrp_visit_stmt_worker (stmt, taken_edge_p,
+                                        output_p, &vr);
+
+  if (lhs)
+    {
+      if (vr_found
+         && update_value_range (lhs, &vr))
+       {
+         *output_p = lhs;

I think rather than computing LHS here you should use *output_p.

Otherwise this looks good though I'd rename the _worker variants
to extract_range_from_phi_node, extract_range_from_stmt and
extract_range_from_assignment_or_call.

Thanks,
Richard.

> Thanks,
> Kugan
>
> gcc/ChangeLog:
>
> 2016-08-16  Kugan Vivekanandarajah  <kuganv@linaro.org>
>
>         * tree-vrp.c (vrp_visit_assignment_or_call): Changed to Return VR.
>         (vrp_visit_cond_stmt): Just sets TAKEN_EDGE_P.
>         (vrp_visit_switch_stmt): Likewise.
>         (vrp_visit_stmt_worker): Factored out from vrp_visit_stmt.
>         (vrp_visit_phi_node_worker): Factored out from vrp_visit_phi_stmt.
>         (vrp_visit_stmt): Use vrp_visit_stmt_worker.
>         (vrp_visit_phi_node): Use vrp_visit_phi_node_worker.

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Re-factor tree-vrp to factor out common code
  2016-08-16  8:09           ` kugan
@ 2016-08-16 11:56             ` Richard Biener
  2016-08-16 22:20               ` kugan
  0 siblings, 1 reply; 67+ messages in thread
From: Richard Biener @ 2016-08-16 11:56 UTC (permalink / raw)
  To: kugan; +Cc: gcc-patches, Jan Hubicka, Martin Jambor

On Tue, Aug 16, 2016 at 10:09 AM, kugan
<kugan.vivekanandarajah@linaro.org> wrote:
>
>
>
> On 23/07/16 20:12, kugan wrote:
>>
>> Hi Richard,
>>
>>>> As we had value_range_type in tree-ssanames.h why not put value_range
>>>> there?
>>>>
>>> For IPA_VRP, we now need value_range used in ipa-prop.h (in ipa-vrp
>>> patch). Based on this, attached patch now adds struct value_range to
>>> tree-ssanames.h and fixes the header files. Please note that I also had
>>> to add other headers in few places due to the dependency. Are you OK
>>> with this ?
>>
>> Here is alternate patch where we keep struct value_range and enum
>> value_range_type to tree-vrp.h. May be it is a better approach? Please
>> let me know what is your preference.
>>
>
> Ping?
>
> This patch places value_range_type and value_range in tree-vrp.h. May be
> this is better?
>
> Alternate patch which keeps value_range_type and value_range in
> tree-ssanames.h is in:
> https://gcc.gnu.org/ml/gcc-patches/2016-07/msg01491.html
>
> I also added the necessary header files changed needed for ipa-vrp as part
> of this patch so that changes needed are clear.

I think tree-vrp.h is a better place.  Please don't export functions
you don't need
(the _1 helpers).

I still believe sharing vrp_initialize/finalize is wrong and the
lattice setup / teardown
should be split out.

Richard.

> Thaks,
> Kugan

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Re-factor tree-vrp to factor out common code
  2016-08-16 11:56             ` Richard Biener
@ 2016-08-16 22:20               ` kugan
  2016-08-17  2:50                 ` kugan
  0 siblings, 1 reply; 67+ messages in thread
From: kugan @ 2016-08-16 22:20 UTC (permalink / raw)
  To: Richard Biener; +Cc: gcc-patches, Jan Hubicka, Martin Jambor

Hi,

On 16/08/16 21:56, Richard Biener wrote:
> On Tue, Aug 16, 2016 at 10:09 AM, kugan
> <kugan.vivekanandarajah@linaro.org> wrote:
>>
>>
>>
>> On 23/07/16 20:12, kugan wrote:
>>>
>>> Hi Richard,
>>>
>>>>> As we had value_range_type in tree-ssanames.h why not put value_range
>>>>> there?
>>>>>
>>>> For IPA_VRP, we now need value_range used in ipa-prop.h (in ipa-vrp
>>>> patch). Based on this, attached patch now adds struct value_range to
>>>> tree-ssanames.h and fixes the header files. Please note that I also had
>>>> to add other headers in few places due to the dependency. Are you OK
>>>> with this ?
>>>
>>> Here is alternate patch where we keep struct value_range and enum
>>> value_range_type to tree-vrp.h. May be it is a better approach? Please
>>> let me know what is your preference.
>>>
>>
>> Ping?
>>
>> This patch places value_range_type and value_range in tree-vrp.h. May be
>> this is better?
>>
>> Alternate patch which keeps value_range_type and value_range in
>> tree-ssanames.h is in:
>> https://gcc.gnu.org/ml/gcc-patches/2016-07/msg01491.html
>>
>> I also added the necessary header files changed needed for ipa-vrp as part
>> of this patch so that changes needed are clear.
>
> I think tree-vrp.h is a better place.  Please don't export functions
> you don't need
> (the _1 helpers).
Agreed.

I have exported the following for now:
+extern void vrp_intersect_ranges (value_range *vr0, value_range *vr1);
+extern void vrp_meet (value_range *vr0, const value_range *vr1);
+extern void dump_value_range (FILE *, const value_range *);

It might be useful to add vrp_unary_op, vrp_binary_op on value_range. 
But that is for later if that is needed.

>
> I still believe sharing vrp_initialize/finalize is wrong and the
> lattice setup / teardown
> should be split out.

I have done that too as part of the early-vrp patch in:

https://gcc.gnu.org/ml/gcc-patches/2016-08/msg01155.html

I just wanted to focus on the functionality required for the IPA-VRP on 
this patch.


Thanks,
Kugan

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] splits out the update_value_range calls from vrp_visit_stmt
  2016-08-16 10:58                               ` Richard Biener
@ 2016-08-17  2:27                                 ` kugan
  2016-08-17 13:44                                   ` Richard Biener
  0 siblings, 1 reply; 67+ messages in thread
From: kugan @ 2016-08-17  2:27 UTC (permalink / raw)
  To: Richard Biener; +Cc: Andrew Pinski, gcc-patches, Jan Hubicka, Martin Jambor

[-- Attachment #1: Type: text/plain, Size: 2624 bytes --]

Hi,

On 16/08/16 20:58, Richard Biener wrote:
> On Tue, Aug 16, 2016 at 9:39 AM, kugan
> <kugan.vivekanandarajah@linaro.org> wrote:
>> Hi,
>>
>>> as said the refactoring that would be appreciated is to split out the
>>> update_value_range calls
>>> from the worker functions so you can call the respective functions
>>> from the DOM implementations.
>>> That they are globbed in vrp_visit_stmt currently is due to the API of
>>> the SSA propagator.
>>
>>
>> Here is a patch that just splits out the update_value_range calls
>> visit_stmts. Bootstrapped and regression tested on x86_64-linux with no new
>> regressions.
>>
>> I also verified few random fdump-tree-vrp1-details from stage2 to make sure
>> they are same.
>>
>> Is this OK for trunk?
>
> For vrp_visit_assignment_or_call please defer the question whether the update
> is interesting (for the internal call stuff) to the caller and always
> return new_vr.
>
> Also do not perform the "not handled stmt" handling here but make the return
> value reflect whether we handled the stmt or not and put
>
>   /* Every other statement produces no useful ranges.  */
>   FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_DEF)
>     set_value_range_to_varying (get_value_range (def));
>
> into the caller (as that's also a lattice-updating thing).
>
> +static enum ssa_prop_result
> +vrp_visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
> +{
> +  value_range vr = VR_INITIALIZER;
> +  tree lhs = gimple_get_lhs (stmt);
> +  bool vr_found = vrp_visit_stmt_worker (stmt, taken_edge_p,
> +                                        output_p, &vr);
> +
> +  if (lhs)
> +    {
> +      if (vr_found
> +         && update_value_range (lhs, &vr))
> +       {
> +         *output_p = lhs;
>
> I think rather than computing LHS here you should use *output_p.
>
> Otherwise this looks good though I'd rename the _worker variants
> to extract_range_from_phi_node, extract_range_from_stmt and
> extract_range_from_assignment_or_call.
>

Please find the patch attached which addresses the comments above. 
Bootstrap and regression testing is ongoing. Is this of if there is no 
new regressions?

Thanks,
Kugan


gcc/ChangeLog:

2016-08-17  Kugan Vivekanandarajah  <kuganv@linaro.org>

	* tree-vrp.c (vrp_visit_assignment_or_call): Changed to Return VR.
	(vrp_visit_cond_stmt): Just sets TAKEN_EDGE_P.
	(vrp_visit_switch_stmt): Likewise.
	(extract_range_from_stmt): Factored out from vrp_visit_stmt.
	(extract_range_from_phi_node): Factored out from vrp_visit_phi_stmt.
	(vrp_visit_stmt): Use extract_range_from_stmt.
	(vrp_visit_phi_node): Use extract_range_from_phi_node.


[-- Attachment #2: 0002-Refactor-vrp_visit_stmt.patch --]
[-- Type: text/x-patch, Size: 18965 bytes --]

From 78c6fd33b9440c6748e32216b1c205015f276b49 Mon Sep 17 00:00:00 2001
From: Kugan Vivekanandarajah <kugan.vivekanandarajah@linaro.org>
Date: Tue, 16 Aug 2016 13:48:21 +1000
Subject: [PATCH 2/5] Refactor vrp_visit_stmt

---
 gcc/tree-vrp.c | 335 ++++++++++++++++++++++++++++++---------------------------
 1 file changed, 175 insertions(+), 160 deletions(-)

diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index ccfccef..89b1e7a 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -7030,15 +7030,15 @@ vrp_valueize_1 (tree name)
 }
 
 /* Visit assignment STMT.  If it produces an interesting range, record
-   the SSA name in *OUTPUT_P.  */
+   the range in VR and set LHS to OUTPUT_P.  */
 
-static enum ssa_prop_result
-vrp_visit_assignment_or_call (gimple *stmt, tree *output_p)
+static void
+vrp_visit_assignment_or_call (gimple *stmt, tree *output_p, value_range *vr)
 {
-  tree def, lhs;
-  ssa_op_iter iter;
+  tree lhs;
   enum gimple_code code = gimple_code (stmt);
   lhs = gimple_get_lhs (stmt);
+  *output_p = NULL_TREE;
 
   /* We only keep track of ranges in integral and pointer types.  */
   if (TREE_CODE (lhs) == SSA_NAME
@@ -7049,114 +7049,18 @@ vrp_visit_assignment_or_call (gimple *stmt, tree *output_p)
 	   && TYPE_MAX_VALUE (TREE_TYPE (lhs)))
 	  || POINTER_TYPE_P (TREE_TYPE (lhs))))
     {
-      value_range new_vr = VR_INITIALIZER;
-
       /* Try folding the statement to a constant first.  */
       tree tem = gimple_fold_stmt_to_constant_1 (stmt, vrp_valueize,
 						 vrp_valueize_1);
       if (tem && is_gimple_min_invariant (tem))
-	set_value_range_to_value (&new_vr, tem, NULL);
+	set_value_range_to_value (vr, tem, NULL);
       /* Then dispatch to value-range extracting functions.  */
       else if (code == GIMPLE_CALL)
-	extract_range_basic (&new_vr, stmt);
+	extract_range_basic (vr, stmt);
       else
-	extract_range_from_assignment (&new_vr, as_a <gassign *> (stmt));
-
-      if (update_value_range (lhs, &new_vr))
-	{
-	  *output_p = lhs;
-
-	  if (dump_file && (dump_flags & TDF_DETAILS))
-	    {
-	      fprintf (dump_file, "Found new range for ");
-	      print_generic_expr (dump_file, lhs, 0);
-	      fprintf (dump_file, ": ");
-	      dump_value_range (dump_file, &new_vr);
-	      fprintf (dump_file, "\n");
-	    }
-
-	  if (new_vr.type == VR_VARYING)
-	    return SSA_PROP_VARYING;
-
-	  return SSA_PROP_INTERESTING;
-	}
-
-      return SSA_PROP_NOT_INTERESTING;
+	extract_range_from_assignment (vr, as_a <gassign *> (stmt));
+      *output_p = lhs;
     }
-  else if (is_gimple_call (stmt) && gimple_call_internal_p (stmt))
-    switch (gimple_call_internal_fn (stmt))
-      {
-      case IFN_ADD_OVERFLOW:
-      case IFN_SUB_OVERFLOW:
-      case IFN_MUL_OVERFLOW:
-	/* These internal calls return _Complex integer type,
-	   which VRP does not track, but the immediate uses
-	   thereof might be interesting.  */
-	if (lhs && TREE_CODE (lhs) == SSA_NAME)
-	  {
-	    imm_use_iterator iter;
-	    use_operand_p use_p;
-	    enum ssa_prop_result res = SSA_PROP_VARYING;
-
-	    set_value_range_to_varying (get_value_range (lhs));
-
-	    FOR_EACH_IMM_USE_FAST (use_p, iter, lhs)
-	      {
-		gimple *use_stmt = USE_STMT (use_p);
-		if (!is_gimple_assign (use_stmt))
-		  continue;
-		enum tree_code rhs_code = gimple_assign_rhs_code (use_stmt);
-		if (rhs_code != REALPART_EXPR && rhs_code != IMAGPART_EXPR)
-		  continue;
-		tree rhs1 = gimple_assign_rhs1 (use_stmt);
-		tree use_lhs = gimple_assign_lhs (use_stmt);
-		if (TREE_CODE (rhs1) != rhs_code
-		    || TREE_OPERAND (rhs1, 0) != lhs
-		    || TREE_CODE (use_lhs) != SSA_NAME
-		    || !stmt_interesting_for_vrp (use_stmt)
-		    || (!INTEGRAL_TYPE_P (TREE_TYPE (use_lhs))
-			|| !TYPE_MIN_VALUE (TREE_TYPE (use_lhs))
-			|| !TYPE_MAX_VALUE (TREE_TYPE (use_lhs))))
-		  continue;
-
-		/* If there is a change in the value range for any of the
-		   REALPART_EXPR/IMAGPART_EXPR immediate uses, return
-		   SSA_PROP_INTERESTING.  If there are any REALPART_EXPR
-		   or IMAGPART_EXPR immediate uses, but none of them have
-		   a change in their value ranges, return
-		   SSA_PROP_NOT_INTERESTING.  If there are no
-		   {REAL,IMAG}PART_EXPR uses at all,
-		   return SSA_PROP_VARYING.  */
-		value_range new_vr = VR_INITIALIZER;
-		extract_range_basic (&new_vr, use_stmt);
-		value_range *old_vr = get_value_range (use_lhs);
-		if (old_vr->type != new_vr.type
-		    || !vrp_operand_equal_p (old_vr->min, new_vr.min)
-		    || !vrp_operand_equal_p (old_vr->max, new_vr.max)
-		    || !vrp_bitmap_equal_p (old_vr->equiv, new_vr.equiv))
-		  res = SSA_PROP_INTERESTING;
-		else
-		  res = SSA_PROP_NOT_INTERESTING;
-		BITMAP_FREE (new_vr.equiv);
-		if (res == SSA_PROP_INTERESTING)
-		  {
-		    *output_p = lhs;
-		    return res;
-		  }
-	      }
-
-	    return res;
-	  }
-	break;
-      default:
-	break;
-      }
-
-  /* Every other statement produces no useful ranges.  */
-  FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_DEF)
-    set_value_range_to_varying (get_value_range (def));
-
-  return SSA_PROP_VARYING;
 }
 
 /* Helper that gets the value range of the SSA_NAME with version I
@@ -7528,10 +7432,9 @@ vrp_evaluate_conditional (tree_code code, tree op0, tree op1, gimple *stmt)
 
 /* Visit conditional statement STMT.  If we can determine which edge
    will be taken out of STMT's basic block, record it in
-   *TAKEN_EDGE_P and return SSA_PROP_INTERESTING.  Otherwise, return
-   SSA_PROP_VARYING.  */
+   *TAKEN_EDGE_P.  Otherwise, set *TAKEN_EDGE_P to NULL.  */
 
-static enum ssa_prop_result
+static void
 vrp_visit_cond_stmt (gcond *stmt, edge *taken_edge_p)
 {
   tree val;
@@ -7629,8 +7532,6 @@ vrp_visit_cond_stmt (gcond *stmt, edge *taken_edge_p)
       else
 	print_generic_stmt (dump_file, val, 0);
     }
-
-  return (*taken_edge_p) ? SSA_PROP_INTERESTING : SSA_PROP_VARYING;
 }
 
 /* Searches the case label vector VEC for the index *IDX of the CASE_LABEL
@@ -7827,10 +7728,9 @@ find_case_label_ranges (gswitch *stmt, value_range *vr, size_t *min_idx1,
 
 /* Visit switch statement STMT.  If we can determine which edge
    will be taken out of STMT's basic block, record it in
-   *TAKEN_EDGE_P and return SSA_PROP_INTERESTING.  Otherwise, return
-   SSA_PROP_VARYING.  */
+   *TAKEN_EDGE_P.  Otherwise, *TAKEN_EDGE_P set to NULL.  */
 
-static enum ssa_prop_result
+static void
 vrp_visit_switch_stmt (gswitch *stmt, edge *taken_edge_p)
 {
   tree op, val;
@@ -7841,7 +7741,7 @@ vrp_visit_switch_stmt (gswitch *stmt, edge *taken_edge_p)
   *taken_edge_p = NULL;
   op = gimple_switch_index (stmt);
   if (TREE_CODE (op) != SSA_NAME)
-    return SSA_PROP_VARYING;
+    return;
 
   vr = get_value_range (op);
   if (dump_file && (dump_flags & TDF_DETAILS))
@@ -7856,7 +7756,7 @@ vrp_visit_switch_stmt (gswitch *stmt, edge *taken_edge_p)
   if ((vr->type != VR_RANGE
        && vr->type != VR_ANTI_RANGE)
       || symbolic_range_p (vr))
-    return SSA_PROP_VARYING;
+    return;
 
   /* Find the single edge that is taken from the switch expression.  */
   take_default = !find_case_label_ranges (stmt, vr, &i, &j, &k, &l);
@@ -7881,7 +7781,7 @@ vrp_visit_switch_stmt (gswitch *stmt, edge *taken_edge_p)
 	  if (dump_file && (dump_flags & TDF_DETAILS))
 	    fprintf (dump_file, "  not a single destination for this "
 		     "range\n");
-          return SSA_PROP_VARYING;
+	  return;
 	}
       for (++i; i <= j; ++i)
         {
@@ -7890,7 +7790,7 @@ vrp_visit_switch_stmt (gswitch *stmt, edge *taken_edge_p)
 	      if (dump_file && (dump_flags & TDF_DETAILS))
 		fprintf (dump_file, "  not a single destination for this "
 			 "range\n");
-	      return SSA_PROP_VARYING;
+	      return;
 	    }
         }
       for (; k <= l; ++k)
@@ -7900,7 +7800,7 @@ vrp_visit_switch_stmt (gswitch *stmt, edge *taken_edge_p)
 	      if (dump_file && (dump_flags & TDF_DETAILS))
 		fprintf (dump_file, "  not a single destination for this "
 			 "range\n");
-	      return SSA_PROP_VARYING;
+	      return;
 	    }
         }
     }
@@ -7913,12 +7813,37 @@ vrp_visit_switch_stmt (gswitch *stmt, edge *taken_edge_p)
       fprintf (dump_file, "  will take edge to ");
       print_generic_stmt (dump_file, CASE_LABEL (val), 0);
     }
-
-  return SSA_PROP_INTERESTING;
 }
 
 
 /* Evaluate statement STMT.  If the statement produces a useful range,
+   set VR and corepsponding OUTPUT_P.
+
+   If STMT is a conditional branch and we can determine its truth
+   value, the taken edge is recorded in *TAKEN_EDGE_P.  */
+
+static void
+extract_range_from_stmt (gimple *stmt, edge *taken_edge_p,
+			 tree *output_p, value_range *vr)
+{
+
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      fprintf (dump_file, "\nVisiting statement:\n");
+      print_gimple_stmt (dump_file, stmt, 0, dump_flags);
+    }
+
+  if (!stmt_interesting_for_vrp (stmt))
+    gcc_assert (stmt_ends_bb_p (stmt));
+  else if (is_gimple_assign (stmt) || is_gimple_call (stmt))
+    vrp_visit_assignment_or_call (stmt, output_p, vr);
+  else if (gimple_code (stmt) == GIMPLE_COND)
+    vrp_visit_cond_stmt (as_a <gcond *> (stmt), taken_edge_p);
+  else if (gimple_code (stmt) == GIMPLE_SWITCH)
+    vrp_visit_switch_stmt (as_a <gswitch *> (stmt), taken_edge_p);
+}
+
+/* Evaluate statement STMT.  If the statement produces a useful range,
    return SSA_PROP_INTERESTING and record the SSA name with the
    interesting range into *OUTPUT_P.
 
@@ -7930,30 +7855,108 @@ vrp_visit_switch_stmt (gswitch *stmt, edge *taken_edge_p)
 static enum ssa_prop_result
 vrp_visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
 {
+  value_range vr = VR_INITIALIZER;
+  tree lhs = gimple_get_lhs (stmt);
   tree def;
   ssa_op_iter iter;
+  extract_range_from_stmt (stmt, taken_edge_p, output_p, &vr);
 
-  if (dump_file && (dump_flags & TDF_DETAILS))
+  if (*output_p)
     {
-      fprintf (dump_file, "\nVisiting statement:\n");
-      print_gimple_stmt (dump_file, stmt, 0, dump_flags);
+      if (update_value_range (*output_p, &vr))
+	{
+	  if (dump_file && (dump_flags & TDF_DETAILS))
+	    {
+	      fprintf (dump_file, "Found new range for ");
+	      print_generic_expr (dump_file, *output_p, 0);
+	      fprintf (dump_file, ": ");
+	      dump_value_range (dump_file, &vr);
+	      fprintf (dump_file, "\n");
+	    }
+
+	  if (vr.type == VR_VARYING)
+	    return SSA_PROP_VARYING;
+
+	  return SSA_PROP_INTERESTING;
+	}
+      return SSA_PROP_NOT_INTERESTING;
     }
 
-  if (!stmt_interesting_for_vrp (stmt))
-    gcc_assert (stmt_ends_bb_p (stmt));
-  else if (is_gimple_assign (stmt) || is_gimple_call (stmt))
-    return vrp_visit_assignment_or_call (stmt, output_p);
-  else if (gimple_code (stmt) == GIMPLE_COND)
-    return vrp_visit_cond_stmt (as_a <gcond *> (stmt), taken_edge_p);
-  else if (gimple_code (stmt) == GIMPLE_SWITCH)
-    return vrp_visit_switch_stmt (as_a <gswitch *> (stmt), taken_edge_p);
+  if (is_gimple_call (stmt) && gimple_call_internal_p (stmt))
+    switch (gimple_call_internal_fn (stmt))
+      {
+      case IFN_ADD_OVERFLOW:
+      case IFN_SUB_OVERFLOW:
+      case IFN_MUL_OVERFLOW:
+	/* These internal calls return _Complex integer type,
+	   which VRP does not track, but the immediate uses
+	   thereof might be interesting.  */
+	if (lhs && TREE_CODE (lhs) == SSA_NAME)
+	  {
+	    imm_use_iterator iter;
+	    use_operand_p use_p;
+	    enum ssa_prop_result res = SSA_PROP_VARYING;
+
+	    set_value_range_to_varying (get_value_range (lhs));
+
+	    FOR_EACH_IMM_USE_FAST (use_p, iter, lhs)
+	      {
+		gimple *use_stmt = USE_STMT (use_p);
+		if (!is_gimple_assign (use_stmt))
+		  continue;
+		enum tree_code rhs_code = gimple_assign_rhs_code (use_stmt);
+		if (rhs_code != REALPART_EXPR && rhs_code != IMAGPART_EXPR)
+		  continue;
+		tree rhs1 = gimple_assign_rhs1 (use_stmt);
+		tree use_lhs = gimple_assign_lhs (use_stmt);
+		if (TREE_CODE (rhs1) != rhs_code
+		    || TREE_OPERAND (rhs1, 0) != lhs
+		    || TREE_CODE (use_lhs) != SSA_NAME
+		    || !stmt_interesting_for_vrp (use_stmt)
+		    || (!INTEGRAL_TYPE_P (TREE_TYPE (use_lhs))
+			|| !TYPE_MIN_VALUE (TREE_TYPE (use_lhs))
+			|| !TYPE_MAX_VALUE (TREE_TYPE (use_lhs))))
+		  continue;
+
+		/* If there is a change in the value range for any of the
+		   REALPART_EXPR/IMAGPART_EXPR immediate uses, return
+		   SSA_PROP_INTERESTING.  If there are any REALPART_EXPR
+		   or IMAGPART_EXPR immediate uses, but none of them have
+		   a change in their value ranges, return
+		   SSA_PROP_NOT_INTERESTING.  If there are no
+		   {REAL,IMAG}PART_EXPR uses at all,
+		   return SSA_PROP_VARYING.  */
+		value_range new_vr = VR_INITIALIZER;
+		extract_range_basic (&new_vr, use_stmt);
+		value_range *old_vr = get_value_range (use_lhs);
+		if (old_vr->type != new_vr.type
+		    || !vrp_operand_equal_p (old_vr->min, new_vr.min)
+		    || !vrp_operand_equal_p (old_vr->max, new_vr.max)
+		    || !vrp_bitmap_equal_p (old_vr->equiv, new_vr.equiv))
+		  res = SSA_PROP_INTERESTING;
+		else
+		  res = SSA_PROP_NOT_INTERESTING;
+		BITMAP_FREE (new_vr.equiv);
+		if (res == SSA_PROP_INTERESTING)
+		  {
+		    *output_p = lhs;
+		    return res;
+		  }
+	      }
+
+	    return res;
+	  }
+	break;
+      default:
+	break;
+      }
 
   /* All other statements produce nothing of interest for VRP, so mark
      their outputs varying and prevent further simulation.  */
   FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_DEF)
     set_value_range_to_varying (get_value_range (def));
 
-  return SSA_PROP_VARYING;
+  return (*taken_edge_p) ? SSA_PROP_INTERESTING : SSA_PROP_VARYING;
 }
 
 /* Union the two value-ranges { *VR0TYPE, *VR0MIN, *VR0MAX } and
@@ -8678,15 +8681,14 @@ vrp_meet (value_range *vr0, const value_range *vr1)
 
 /* Visit all arguments for PHI node PHI that flow through executable
    edges.  If a valid value range can be derived from all the incoming
-   value ranges, set a new range for the LHS of PHI.  */
+   value ranges, set a new range in VR_RESULT.  */
 
-static enum ssa_prop_result
-vrp_visit_phi_node (gphi *phi)
+static void
+extract_range_from_phi_node (gphi *phi, value_range *vr_result)
 {
   size_t i;
   tree lhs = PHI_RESULT (phi);
   value_range *lhs_vr = get_value_range (lhs);
-  value_range vr_result = VR_INITIALIZER;
   bool first = true;
   int edges, old_edges;
   struct loop *l;
@@ -8778,19 +8780,19 @@ vrp_visit_phi_node (gphi *phi)
 	    }
 
 	  if (first)
-	    copy_value_range (&vr_result, &vr_arg);
+	    copy_value_range (vr_result, &vr_arg);
 	  else
-	    vrp_meet (&vr_result, &vr_arg);
+	    vrp_meet (vr_result, &vr_arg);
 	  first = false;
 
-	  if (vr_result.type == VR_VARYING)
+	  if (vr_result->type == VR_VARYING)
 	    break;
 	}
     }
 
-  if (vr_result.type == VR_VARYING)
+  if (vr_result->type == VR_VARYING)
     goto varying;
-  else if (vr_result.type == VR_UNDEFINED)
+  else if (vr_result->type == VR_UNDEFINED)
     goto update_range;
 
   old_edges = vr_phi_edge_counts[SSA_NAME_VERSION (lhs)];
@@ -8812,16 +8814,16 @@ vrp_visit_phi_node (gphi *phi)
     {
       /* Compare old and new ranges, fall back to varying if the
          values are not comparable.  */
-      int cmp_min = compare_values (lhs_vr->min, vr_result.min);
+      int cmp_min = compare_values (lhs_vr->min, vr_result->min);
       if (cmp_min == -2)
 	goto varying;
-      int cmp_max = compare_values (lhs_vr->max, vr_result.max);
+      int cmp_max = compare_values (lhs_vr->max, vr_result->max);
       if (cmp_max == -2)
 	goto varying;
 
       /* For non VR_RANGE or for pointers fall back to varying if
 	 the range changed.  */
-      if ((lhs_vr->type != VR_RANGE || vr_result.type != VR_RANGE
+      if ((lhs_vr->type != VR_RANGE || vr_result->type != VR_RANGE
 	   || POINTER_TYPE_P (TREE_TYPE (lhs)))
 	  && (cmp_min != 0 || cmp_max != 0))
 	goto varying;
@@ -8835,23 +8837,23 @@ vrp_visit_phi_node (gphi *phi)
 	 iteration compute whether there will be any overflow, at the
 	 expense of one additional iteration.  */
       if (cmp_min < 0)
-	vr_result.min = lhs_vr->min;
+	vr_result->min = lhs_vr->min;
       else if (cmp_min > 0
-	       && !vrp_val_is_min (vr_result.min))
-	vr_result.min
+	       && !vrp_val_is_min (vr_result->min))
+	vr_result->min
 	  = int_const_binop (PLUS_EXPR,
-			     vrp_val_min (TREE_TYPE (vr_result.min)),
-			     build_int_cst (TREE_TYPE (vr_result.min), 1));
+			     vrp_val_min (TREE_TYPE (vr_result->min)),
+			     build_int_cst (TREE_TYPE (vr_result->min), 1));
 
       /* Similarly for the maximum value.  */
       if (cmp_max > 0)
-	vr_result.max = lhs_vr->max;
+	vr_result->max = lhs_vr->max;
       else if (cmp_max < 0
-	       && !vrp_val_is_max (vr_result.max))
-	vr_result.max
+	       && !vrp_val_is_max (vr_result->max))
+	vr_result->max
 	  = int_const_binop (MINUS_EXPR,
-			     vrp_val_max (TREE_TYPE (vr_result.min)),
-			     build_int_cst (TREE_TYPE (vr_result.min), 1));
+			     vrp_val_max (TREE_TYPE (vr_result->min)),
+			     build_int_cst (TREE_TYPE (vr_result->min), 1));
 
       /* If we dropped either bound to +-INF then if this is a loop
 	 PHI node SCEV may known more about its value-range.  */
@@ -8865,7 +8867,7 @@ vrp_visit_phi_node (gphi *phi)
   goto update_range;
 
 varying:
-  set_value_range_to_varying (&vr_result);
+  set_value_range_to_varying (vr_result);
 
 scev_check:
   /* If this is a loop PHI node SCEV may known more about its value-range.
@@ -8874,22 +8876,35 @@ scev_check:
      avoid infinite simulation.  */
   if ((l = loop_containing_stmt (phi))
       && l->header == gimple_bb (phi))
-    adjust_range_with_scev (&vr_result, l, phi, lhs);
+    adjust_range_with_scev (vr_result, l, phi, lhs);
 
 infinite_check:
   /* If we will end up with a (-INF, +INF) range, set it to
      VARYING.  Same if the previous max value was invalid for
      the type and we end up with vr_result.min > vr_result.max.  */
-  if ((vr_result.type == VR_RANGE || vr_result.type == VR_ANTI_RANGE)
-      && !((vrp_val_is_max (vr_result.max) && vrp_val_is_min (vr_result.min))
-	   || compare_values (vr_result.min, vr_result.max) > 0))
+  if ((vr_result->type == VR_RANGE || vr_result->type == VR_ANTI_RANGE)
+      && !((vrp_val_is_max (vr_result->max) && vrp_val_is_min (vr_result->min))
+	   || compare_values (vr_result->min, vr_result->max) > 0))
     ;
   else
-    set_value_range_to_varying (&vr_result);
+    set_value_range_to_varying (vr_result);
 
   /* If the new range is different than the previous value, keep
      iterating.  */
 update_range:
+  return;
+}
+
+/* Visit all arguments for PHI node PHI that flow through executable
+   edges.  If a valid value range can be derived from all the incoming
+   value ranges, set a new range for the LHS of PHI.  */
+
+static enum ssa_prop_result
+vrp_visit_phi_node (gphi *phi)
+{
+  tree lhs = PHI_RESULT (phi);
+  value_range vr_result = VR_INITIALIZER;
+  extract_range_from_phi_node (phi, &vr_result);
   if (update_value_range (lhs, &vr_result))
     {
       if (dump_file && (dump_flags & TDF_DETAILS))
-- 
2.7.4


^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Re-factor tree-vrp to factor out common code
  2016-08-16 22:20               ` kugan
@ 2016-08-17  2:50                 ` kugan
  2016-08-17 13:46                   ` Richard Biener
  0 siblings, 1 reply; 67+ messages in thread
From: kugan @ 2016-08-17  2:50 UTC (permalink / raw)
  To: Richard Biener; +Cc: gcc-patches, Jan Hubicka, Martin Jambor

[-- Attachment #1: Type: text/plain, Size: 2450 bytes --]

Hi Richard,

On 17/08/16 08:20, kugan wrote:
> Hi,
>
> On 16/08/16 21:56, Richard Biener wrote:
>> On Tue, Aug 16, 2016 at 10:09 AM, kugan
>> <kugan.vivekanandarajah@linaro.org> wrote:
>>>
>>>
>>>
>>> On 23/07/16 20:12, kugan wrote:
>>>>
>>>> Hi Richard,
>>>>
>>>>>> As we had value_range_type in tree-ssanames.h why not put value_range
>>>>>> there?
>>>>>>
>>>>> For IPA_VRP, we now need value_range used in ipa-prop.h (in ipa-vrp
>>>>> patch). Based on this, attached patch now adds struct value_range to
>>>>> tree-ssanames.h and fixes the header files. Please note that I also had
>>>>> to add other headers in few places due to the dependency. Are you OK
>>>>> with this ?
>>>>
>>>> Here is alternate patch where we keep struct value_range and enum
>>>> value_range_type to tree-vrp.h. May be it is a better approach? Please
>>>> let me know what is your preference.
>>>>
>>>
>>> Ping?
>>>
>>> This patch places value_range_type and value_range in tree-vrp.h. May be
>>> this is better?
>>>
>>> Alternate patch which keeps value_range_type and value_range in
>>> tree-ssanames.h is in:
>>> https://gcc.gnu.org/ml/gcc-patches/2016-07/msg01491.html
>>>
>>> I also added the necessary header files changed needed for ipa-vrp as part
>>> of this patch so that changes needed are clear.
>>
>> I think tree-vrp.h is a better place.  Please don't export functions
>> you don't need
>> (the _1 helpers).
I had unintentionally removed a static from a _1 helper. I think thats 
what caused the confusion. I also added constant modifiers to parameters 
mainly due to ipa-vrp passing second parameters to lattice operation as 
const.

> Agreed.
>
> I have exported the following for now:
> +extern void vrp_intersect_ranges (value_range *vr0, value_range *vr1);
> +extern void vrp_meet (value_range *vr0, const value_range *vr1);
> +extern void dump_value_range (FILE *, const value_range *);

This again is the exported operations.

> It might be useful to add vrp_unary_op, vrp_binary_op on value_range.
> But that is for later if that is needed.
>
>>
>> I still believe sharing vrp_initialize/finalize is wrong and the
>> lattice setup / teardown
>> should be split out.
>
> I have done that too as part of the early-vrp patch in:
>
> https://gcc.gnu.org/ml/gcc-patches/2016-08/msg01155.html
>
> I just wanted to focus on the functionality required for the IPA-VRP on
> this patch.


Attaching the latest version of the patch. Is this OK?

Thanks,
Kugan

[-- Attachment #2: 0001-Factor-out-and-expose-value_range-api-for-IPA-VRP.patch --]
[-- Type: text/x-patch, Size: 16174 bytes --]

From 2fc17cbac316f5b5a8aa360e2eecdb0659abc907 Mon Sep 17 00:00:00 2001
From: Kugan Vivekanandarajah <kugan.vivekanandarajah@linaro.org>
Date: Mon, 15 Aug 2016 09:19:52 +1000
Subject: [PATCH 1/5] Factor out and expose value_range api for IPA-VRP

---
 gcc/Makefile.in            |  1 +
 gcc/asan.c                 |  1 +
 gcc/builtins.c             |  1 +
 gcc/cgraph.c               |  1 +
 gcc/cgraphunit.c           |  1 +
 gcc/fold-const.c           |  1 +
 gcc/gengtype.c             |  2 +-
 gcc/gimple-builder.c       |  1 +
 gcc/gimple-laddress.c      |  1 +
 gcc/hsa-gen.c              |  1 +
 gcc/internal-fn.c          |  1 +
 gcc/ipa-cp.c               |  1 +
 gcc/ipa-devirt.c           |  1 +
 gcc/ipa-inline-transform.c |  1 +
 gcc/ipa-inline.c           |  1 +
 gcc/ipa-profile.c          |  1 +
 gcc/ipa-utils.c            |  1 +
 gcc/ipa.c                  |  1 +
 gcc/lto/lto-partition.c    |  1 +
 gcc/lto/lto.c              |  1 +
 gcc/ssa.h                  |  1 +
 gcc/targhooks.c            |  1 +
 gcc/toplev.c               |  1 +
 gcc/tree-ssa-address.c     |  1 +
 gcc/tree-ssanames.h        |  5 -----
 gcc/tree-vrp.c             | 40 ++++++----------------------------
 gcc/tree-vrp.h             | 54 ++++++++++++++++++++++++++++++++++++++++++++++
 27 files changed, 84 insertions(+), 40 deletions(-)
 create mode 100644 gcc/tree-vrp.h

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 7a0160f..8d7cc51 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -2456,6 +2456,7 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
   $(srcdir)/tree-phinodes.c \
   $(srcdir)/tree-ssa-alias.h \
   $(srcdir)/tree-ssanames.h \
+  $(srcdir)/tree-vrp.h \
   $(srcdir)/ipa-prop.h \
   $(srcdir)/trans-mem.c \
   $(srcdir)/lto-streamer.h \
diff --git a/gcc/asan.c b/gcc/asan.c
index 9047e1b..4fe2447 100644
--- a/gcc/asan.c
+++ b/gcc/asan.c
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-pass.h"
 #include "tm_p.h"
 #include "stringpool.h"
+#include "tree-vrp.h"
 #include "tree-ssanames.h"
 #include "optabs.h"
 #include "emit-rtl.h"
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 03a0dc8..abc934b 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "predict.h"
 #include "tm_p.h"
 #include "stringpool.h"
+#include "tree-vrp.h"
 #include "tree-ssanames.h"
 #include "expmed.h"
 #include "optabs.h"
diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index 9bc5b6b..0a43850 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -49,6 +49,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "value-prof.h"
 #include "ipa-utils.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "ipa-inline.h"
 #include "cfgloop.h"
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index d8f7903..5bb6904 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -190,6 +190,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "toplev.h"
 #include "debug.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "gimple-pretty-print.h"
 #include "plugin.h"
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 30c1e0d..103ed2d 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -75,6 +75,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "md5.h"
 #include "case-cfn-macros.h"
 #include "stringpool.h"
+#include "tree-vrp.h"
 #include "tree-ssanames.h"
 #include "selftest.h"
 
diff --git a/gcc/gengtype.c b/gcc/gengtype.c
index 0518355..cecd552 100644
--- a/gcc/gengtype.c
+++ b/gcc/gengtype.c
@@ -1713,7 +1713,7 @@ open_base_files (void)
       "explow.h", "calls.h", "cilk.h", "emit-rtl.h", "varasm.h", "stmt.h",
       "expr.h", "alloc-pool.h", "cselib.h", "insn-addr.h", "optabs.h",
       "libfuncs.h", "debug.h", "internal-fn.h", "gimple-fold.h", "tree-eh.h",
-      "gimple-iterator.h", "gimple-ssa.h", "tree-cfg.h",
+      "gimple-iterator.h", "gimple-ssa.h", "tree-cfg.h", "tree-vrp.h",
       "tree-phinodes.h", "ssa-iterators.h", "stringpool.h", "tree-ssanames.h",
       "tree-ssa-loop.h", "tree-ssa-loop-ivopts.h", "tree-ssa-loop-manip.h",
       "tree-ssa-loop-niter.h", "tree-into-ssa.h", "tree-dfa.h", 
diff --git a/gcc/gimple-builder.c b/gcc/gimple-builder.c
index f124554..4fb21e4 100644
--- a/gcc/gimple-builder.c
+++ b/gcc/gimple-builder.c
@@ -24,6 +24,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree.h"
 #include "gimple.h"
 #include "stringpool.h"
+#include "tree-vrp.h"
 #include "tree-ssanames.h"
 
 
diff --git a/gcc/gimple-laddress.c b/gcc/gimple-laddress.c
index 4cc57cf..1a3c8e1 100644
--- a/gcc/gimple-laddress.c
+++ b/gcc/gimple-laddress.c
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "symtab.h"
 #include "tree.h"
 #include "stringpool.h"
+#include "tree-vrp.h"
 #include "tree-ssanames.h"
 #include "fold-const.h"
 #include "gimple-expr.h"
diff --git a/gcc/hsa-gen.c b/gcc/hsa-gen.c
index fb6d8a2..314bb5b 100644
--- a/gcc/hsa-gen.c
+++ b/gcc/hsa-gen.c
@@ -42,6 +42,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-ssa.h"
 #include "tree-phinodes.h"
 #include "stringpool.h"
+#include "tree-vrp.h"
 #include "tree-ssanames.h"
 #include "tree-dfa.h"
 #include "ssa-iterators.h"
diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c
index 49f3495..cd4b625 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -27,6 +27,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple.h"
 #include "predict.h"
 #include "stringpool.h"
+#include "tree-vrp.h"
 #include "tree-ssanames.h"
 #include "expmed.h"
 #include "optabs.h"
diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
index 5b6cb9a..e9562a5 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"
diff --git a/gcc/ipa-devirt.c b/gcc/ipa-devirt.c
index 2cf018b..62a08f8 100644
--- a/gcc/ipa-devirt.c
+++ b/gcc/ipa-devirt.c
@@ -122,6 +122,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-utils.h"
 #include "gimple-fold.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "ipa-inline.h"
 #include "demangle.h"
diff --git a/gcc/ipa-inline-transform.c b/gcc/ipa-inline-transform.c
index 98c7f96..efe7421 100644
--- a/gcc/ipa-inline-transform.c
+++ b/gcc/ipa-inline-transform.c
@@ -39,6 +39,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "cgraph.h"
 #include "tree-cfg.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "ipa-inline.h"
 #include "tree-inline.h"
diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
index 5c9366a..82bb94f 100644
--- a/gcc/ipa-inline.c
+++ b/gcc/ipa-inline.c
@@ -108,6 +108,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "params.h"
 #include "profile.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "ipa-inline.h"
 #include "ipa-utils.h"
diff --git a/gcc/ipa-profile.c b/gcc/ipa-profile.c
index da17bcd..e87615a 100644
--- a/gcc/ipa-profile.c
+++ b/gcc/ipa-profile.c
@@ -62,6 +62,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "value-prof.h"
 #include "tree-inline.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "ipa-inline.h"
 
diff --git a/gcc/ipa-utils.c b/gcc/ipa-utils.c
index 5eb7d5f..61d8dd1 100644
--- a/gcc/ipa-utils.c
+++ b/gcc/ipa-utils.c
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "splay-tree.h"
 #include "ipa-utils.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "ipa-inline.h"
 
diff --git a/gcc/ipa.c b/gcc/ipa.c
index 6f4693f..b02713f 100644
--- a/gcc/ipa.c
+++ b/gcc/ipa.c
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-iterator.h"
 #include "ipa-utils.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "ipa-inline.h"
 #include "dbgcnt.h"
diff --git a/gcc/lto/lto-partition.c b/gcc/lto/lto-partition.c
index 453343a..b52d175 100644
--- a/gcc/lto/lto-partition.c
+++ b/gcc/lto/lto-partition.c
@@ -31,6 +31,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "lto-streamer.h"
 #include "params.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "ipa-inline.h"
 #include "lto-partition.h"
diff --git a/gcc/lto/lto.c b/gcc/lto/lto.c
index 73d1e26..bbf02e8 100644
--- a/gcc/lto/lto.c
+++ b/gcc/lto/lto.c
@@ -36,6 +36,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "toplev.h"
 #include "stor-layout.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "common.h"
 #include "debug.h"
diff --git a/gcc/ssa.h b/gcc/ssa.h
index 40bc1c7..0ec1bf0 100644
--- a/gcc/ssa.h
+++ b/gcc/ssa.h
@@ -25,6 +25,7 @@ along with GCC; see the file COPYING3.  If not see
 
 #include "stringpool.h"
 #include "gimple-ssa.h"
+#include "tree-vrp.h"
 #include "tree-ssanames.h"
 #include "tree-phinodes.h"
 #include "ssa-iterators.h" 
diff --git a/gcc/targhooks.c b/gcc/targhooks.c
index 69037c1..6f67210 100644
--- a/gcc/targhooks.c
+++ b/gcc/targhooks.c
@@ -57,6 +57,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-expr.h"
 #include "tm_p.h"
 #include "stringpool.h"
+#include "tree-vrp.h"
 #include "tree-ssanames.h"
 #include "optabs.h"
 #include "regs.h"
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 2607904..668eccd 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -71,6 +71,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "dwarf2out.h"
 #include "ipa-reference.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "gcse.h"
 #include "tree-chkp.h"
diff --git a/gcc/tree-ssa-address.c b/gcc/tree-ssa-address.c
index b04545c..30f0c32 100644
--- a/gcc/tree-ssa-address.c
+++ b/gcc/tree-ssa-address.c
@@ -29,6 +29,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree.h"
 #include "gimple.h"
 #include "stringpool.h"
+#include "tree-vrp.h"
 #include "tree-ssanames.h"
 #include "expmed.h"
 #include "insn-config.h"
diff --git a/gcc/tree-ssanames.h b/gcc/tree-ssanames.h
index c81b1a1..8e66ce6 100644
--- a/gcc/tree-ssanames.h
+++ b/gcc/tree-ssanames.h
@@ -62,11 +62,6 @@ struct GTY ((variable_size)) range_info_def {
 #define num_ssa_names (vec_safe_length (cfun->gimple_df->ssa_names))
 #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 };
-
 /* Sets the value range to SSA.  */
 extern void set_range_info (tree, enum value_range_type, const wide_int_ref &,
 			    const wide_int_ref &);
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index 6934914..ccfccef 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -61,32 +61,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "params.h"
 #include "alloc-pool.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 }
 
 /* Allocation pools for tree-vrp allocations.  */
@@ -109,8 +83,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 *,
 						     bool *);
@@ -4633,7 +4605,7 @@ compare_range_with_value (enum tree_code comp, value_range *vr, tree val,
 
 /* Debugging dumps.  */
 
-void dump_value_range (FILE *, value_range *);
+void dump_value_range (FILE *, const value_range *);
 void debug_value_range (value_range *);
 void dump_all_value_ranges (FILE *);
 void debug_all_value_ranges (void);
@@ -4644,7 +4616,7 @@ void debug_vr_equiv (bitmap);
 /* Dump value range VR to FILE.  */
 
 void
-dump_value_range (FILE *file, value_range *vr)
+dump_value_range (FILE *file, const value_range *vr)
 {
   if (vr == NULL)
     fprintf (file, "[]");
@@ -8586,7 +8558,7 @@ vrp_intersect_ranges_1 (value_range *vr0, value_range *vr1)
     bitmap_copy (vr0->equiv, vr1->equiv);
 }
 
-static void
+void
 vrp_intersect_ranges (value_range *vr0, value_range *vr1)
 {
   if (dump_file && (dump_flags & TDF_DETAILS))
@@ -8611,7 +8583,7 @@ vrp_intersect_ranges (value_range *vr0, value_range *vr1)
    may not be the smallest possible such range.  */
 
 static void
-vrp_meet_1 (value_range *vr0, value_range *vr1)
+vrp_meet_1 (value_range *vr0, const value_range *vr1)
 {
   value_range saved;
 
@@ -8683,8 +8655,8 @@ vrp_meet_1 (value_range *vr0, value_range *vr1)
     bitmap_clear (vr0->equiv);
 }
 
-static void
-vrp_meet (value_range *vr0, value_range *vr1)
+void
+vrp_meet (value_range *vr0, const value_range *vr1)
 {
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
diff --git a/gcc/tree-vrp.h b/gcc/tree-vrp.h
new file mode 100644
index 0000000..e514c1e
--- /dev/null
+++ b/gcc/tree-vrp.h
@@ -0,0 +1,54 @@
+/* Support routines for Value Range Propagation (VRP).
+   Copyright (C) Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+/* 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;
+};
+
+extern void vrp_intersect_ranges (value_range *vr0, value_range *vr1);
+extern void vrp_meet (value_range *vr0, const value_range *vr1);
+extern void dump_value_range (FILE *, const value_range *);
+
-- 
2.7.4


^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] splits out the update_value_range calls from vrp_visit_stmt
  2016-08-17  2:27                                 ` kugan
@ 2016-08-17 13:44                                   ` Richard Biener
  0 siblings, 0 replies; 67+ messages in thread
From: Richard Biener @ 2016-08-17 13:44 UTC (permalink / raw)
  To: kugan; +Cc: Andrew Pinski, gcc-patches, Jan Hubicka, Martin Jambor

On Wed, Aug 17, 2016 at 4:27 AM, kugan
<kugan.vivekanandarajah@linaro.org> wrote:
> Hi,
>
>
> On 16/08/16 20:58, Richard Biener wrote:
>>
>> On Tue, Aug 16, 2016 at 9:39 AM, kugan
>> <kugan.vivekanandarajah@linaro.org> wrote:
>>>
>>> Hi,
>>>
>>>> as said the refactoring that would be appreciated is to split out the
>>>> update_value_range calls
>>>> from the worker functions so you can call the respective functions
>>>> from the DOM implementations.
>>>> That they are globbed in vrp_visit_stmt currently is due to the API of
>>>> the SSA propagator.
>>>
>>>
>>>
>>> Here is a patch that just splits out the update_value_range calls
>>> visit_stmts. Bootstrapped and regression tested on x86_64-linux with no
>>> new
>>> regressions.
>>>
>>> I also verified few random fdump-tree-vrp1-details from stage2 to make
>>> sure
>>> they are same.
>>>
>>> Is this OK for trunk?
>>
>>
>> For vrp_visit_assignment_or_call please defer the question whether the
>> update
>> is interesting (for the internal call stuff) to the caller and always
>> return new_vr.
>>
>> Also do not perform the "not handled stmt" handling here but make the
>> return
>> value reflect whether we handled the stmt or not and put
>>
>>   /* Every other statement produces no useful ranges.  */
>>   FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_DEF)
>>     set_value_range_to_varying (get_value_range (def));
>>
>> into the caller (as that's also a lattice-updating thing).
>>
>> +static enum ssa_prop_result
>> +vrp_visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
>> +{
>> +  value_range vr = VR_INITIALIZER;
>> +  tree lhs = gimple_get_lhs (stmt);
>> +  bool vr_found = vrp_visit_stmt_worker (stmt, taken_edge_p,
>> +                                        output_p, &vr);
>> +
>> +  if (lhs)
>> +    {
>> +      if (vr_found
>> +         && update_value_range (lhs, &vr))
>> +       {
>> +         *output_p = lhs;
>>
>> I think rather than computing LHS here you should use *output_p.
>>
>> Otherwise this looks good though I'd rename the _worker variants
>> to extract_range_from_phi_node, extract_range_from_stmt and
>> extract_range_from_assignment_or_call.
>>
>
> Please find the patch attached which addresses the comments above. Bootstrap
> and regression testing is ongoing. Is this of if there is no new
> regressions?

Yes, this looks good to me.

Thanks,
Richard.

> Thanks,
> Kugan
>
>
> gcc/ChangeLog:
>
> 2016-08-17  Kugan Vivekanandarajah  <kuganv@linaro.org>
>
>         * tree-vrp.c (vrp_visit_assignment_or_call): Changed to Return VR.
>         (vrp_visit_cond_stmt): Just sets TAKEN_EDGE_P.
>         (vrp_visit_switch_stmt): Likewise.
>         (extract_range_from_stmt): Factored out from vrp_visit_stmt.
>         (extract_range_from_phi_node): Factored out from vrp_visit_phi_stmt.
>         (vrp_visit_stmt): Use extract_range_from_stmt.
>         (vrp_visit_phi_node): Use extract_range_from_phi_node.
>

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Re-factor tree-vrp to factor out common code
  2016-08-17  2:50                 ` kugan
@ 2016-08-17 13:46                   ` Richard Biener
  0 siblings, 0 replies; 67+ messages in thread
From: Richard Biener @ 2016-08-17 13:46 UTC (permalink / raw)
  To: kugan; +Cc: gcc-patches, Jan Hubicka, Martin Jambor

On Wed, Aug 17, 2016 at 4:50 AM, kugan
<kugan.vivekanandarajah@linaro.org> wrote:
> Hi Richard,
>
>
> On 17/08/16 08:20, kugan wrote:
>>
>> Hi,
>>
>> On 16/08/16 21:56, Richard Biener wrote:
>>>
>>> On Tue, Aug 16, 2016 at 10:09 AM, kugan
>>> <kugan.vivekanandarajah@linaro.org> wrote:
>>>>
>>>>
>>>>
>>>>
>>>> On 23/07/16 20:12, kugan wrote:
>>>>>
>>>>>
>>>>> Hi Richard,
>>>>>
>>>>>>> As we had value_range_type in tree-ssanames.h why not put value_range
>>>>>>> there?
>>>>>>>
>>>>>> For IPA_VRP, we now need value_range used in ipa-prop.h (in ipa-vrp
>>>>>> patch). Based on this, attached patch now adds struct value_range to
>>>>>> tree-ssanames.h and fixes the header files. Please note that I also
>>>>>> had
>>>>>> to add other headers in few places due to the dependency. Are you OK
>>>>>> with this ?
>>>>>
>>>>>
>>>>> Here is alternate patch where we keep struct value_range and enum
>>>>> value_range_type to tree-vrp.h. May be it is a better approach? Please
>>>>> let me know what is your preference.
>>>>>
>>>>
>>>> Ping?
>>>>
>>>> This patch places value_range_type and value_range in tree-vrp.h. May be
>>>> this is better?
>>>>
>>>> Alternate patch which keeps value_range_type and value_range in
>>>> tree-ssanames.h is in:
>>>> https://gcc.gnu.org/ml/gcc-patches/2016-07/msg01491.html
>>>>
>>>> I also added the necessary header files changed needed for ipa-vrp as
>>>> part
>>>> of this patch so that changes needed are clear.
>>>
>>>
>>> I think tree-vrp.h is a better place.  Please don't export functions
>>> you don't need
>>> (the _1 helpers).
>
> I had unintentionally removed a static from a _1 helper. I think thats what
> caused the confusion. I also added constant modifiers to parameters mainly
> due to ipa-vrp passing second parameters to lattice operation as const.
>
>> Agreed.
>>
>> I have exported the following for now:
>> +extern void vrp_intersect_ranges (value_range *vr0, value_range *vr1);
>> +extern void vrp_meet (value_range *vr0, const value_range *vr1);
>> +extern void dump_value_range (FILE *, const value_range *);
>
>
> This again is the exported operations.
>
>> It might be useful to add vrp_unary_op, vrp_binary_op on value_range.
>> But that is for later if that is needed.
>>
>>>
>>> I still believe sharing vrp_initialize/finalize is wrong and the
>>> lattice setup / teardown
>>> should be split out.
>>
>>
>> I have done that too as part of the early-vrp patch in:
>>
>> https://gcc.gnu.org/ml/gcc-patches/2016-08/msg01155.html
>>
>> I just wanted to focus on the functionality required for the IPA-VRP on
>> this patch.
>
>
>
> Attaching the latest version of the patch. Is this OK?

Yes.

Thanks,
Richard.

> Thanks,
> Kugan

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Early VRP Implementation
  2016-08-16  7:45                             ` [RFC][IPA-VRP] Early VRP Implementation kugan
@ 2016-08-19 11:41                               ` Richard Biener
  2016-08-23  2:12                                 ` Kugan Vivekanandarajah
  0 siblings, 1 reply; 67+ messages in thread
From: Richard Biener @ 2016-08-19 11:41 UTC (permalink / raw)
  To: kugan; +Cc: Andrew Pinski, gcc-patches, Jan Hubicka, Martin Jambor

On Tue, Aug 16, 2016 at 9:45 AM, kugan
<kugan.vivekanandarajah@linaro.org> wrote:
> Hi Richard,
>
> On 12/08/16 20:43, Richard Biener wrote:
>>
>> On Wed, Aug 3, 2016 at 3:17 AM, kugan <kugan.vivekanandarajah@linaro.org>
>> wrote:
>
>
> [SNIP]
>
>>
>> diff --git a/gcc/common.opt b/gcc/common.opt
>> index 8a292ed..7028cd4 100644
>> --- a/gcc/common.opt
>> +++ b/gcc/common.opt
>> @@ -2482,6 +2482,10 @@ ftree-vrp
>>  Common Report Var(flag_tree_vrp) Init(0) Optimization
>>  Perform Value Range Propagation on trees.
>>
>> +fdisable-tree-evrp
>> +Common Report Var(flag_disable_early_vrp) Init(0) Optimization
>> +Disable Early Value Range Propagation on trees.
>> +
>>
>> no please, this is automatically supported via -fdisable-
>
>
> I am now having -ftree-evrp which is enabled all the time. But This will
> only be used for disabling the early-vrp. That is, early-vrp will be run
> when ftree-vrp is enabled and ftree-evrp is not explicitly disabled. Is this
> OK?

Why would one want to disable early-vrp?  I see you do this in the testsuite
for non-early VRP unit-tests but using -fdisable-tree-evrp1 there
would be ok as well.

>>
>> @@ -1728,11 +1736,12 @@ extract_range_from_assert (value_range *vr_p, tree
>> expr)
>>      always false.  */
>>
>>  static void
>> -extract_range_from_ssa_name (value_range *vr, tree var)
>> +extract_range_from_ssa_name (value_range *vr, bool dom_p, tree var)
>>  {
>>    value_range *var_vr = get_value_range (var);
>>
>> -  if (var_vr->type != VR_VARYING)
>> +  if (var_vr->type != VR_VARYING
>> +      && (!dom_p || var_vr->type != VR_UNDEFINED))
>>      copy_value_range (vr, var_vr);
>>    else
>>      set_value_range (vr, VR_RANGE, var, var, NULL);
>>
>> why do you need these changes?  I think I already told you you need to
>> initialize the lattice to sth else than VR_UNDEFINED and that you can't
>> fully re-use update_value_range.  If you don't want to do that then
>> instead
>> of doing changes all over the place do it in get_value_range and have a
>> global flag.
>
>
> I have now added a global early_vrp_p and use this to initialize
> VR_INITIALIZER and get_value_range default to VR_VARYING.

ICK.  Ok, I see that this works, but it is quite ugly, so (see below)

>>
>>
>> @@ -3594,7 +3643,8 @@ extract_range_from_cond_expr (value_range *vr,
>> gassign *stmt)
>>     on the range of its operand and the expression code.  */
>>
>>  static void
>> -extract_range_from_comparison (value_range *vr, enum tree_code code,
>> +extract_range_from_comparison (value_range *vr,
>> +                              enum tree_code code,
>>                                tree type, tree op0, tree op1)
>>  {
>>    bool sop = false;
>>
>> remove these kind of no-op changes.
>
>
> Done.
>
>
>>
>> +/* Initialize local data structures for VRP.  If DOM_P is true,
>> +   we will be calling this from early_vrp where value range propagation
>> +   is done by visiting stmts in dominator tree.  ssa_propagate engine
>> +   is not used in this case and that part of the ininitialization will
>> +   be skipped.  */
>>
>>  static void
>> -vrp_initialize (void)
>> +vrp_initialize (bool dom_p)
>>  {
>>    basic_block bb;
>>
>> @@ -6949,6 +7010,9 @@ vrp_initialize (void)
>>    vr_phi_edge_counts = XCNEWVEC (int, num_ssa_names);
>>    bitmap_obstack_initialize (&vrp_equiv_obstack);
>>
>> +  if (dom_p)
>> +    return;
>> +
>>
>> split the function instead.
>>
>> @@ -7926,7 +7992,8 @@ vrp_visit_switch_stmt (gswitch *stmt, edge
>> *taken_edge_p)
>>     If STMT produces a varying value, return SSA_PROP_VARYING.  */
>>
>>  static enum ssa_prop_result
>> -vrp_visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
>> +vrp_visit_stmt_worker (gimple *stmt, bool dom_p,  edge *taken_edge_p,
>> +                      tree *output_p)
>>  {
>>    tree def;
>>    ssa_op_iter iter;
>> @@ -7940,7 +8007,7 @@ vrp_visit_stmt (gimple *stmt, edge
>> *taken_edge_p, tree *output_p)
>>    if (!stmt_interesting_for_vrp (stmt))
>>      gcc_assert (stmt_ends_bb_p (stmt));
>>    else if (is_gimple_assign (stmt) || is_gimple_call (stmt))
>> -    return vrp_visit_assignment_or_call (stmt, output_p);
>> +    return vrp_visit_assignment_or_call (stmt, dom_p, output_p);
>>    else if (gimple_code (stmt) == GIMPLE_COND)
>>      return vrp_visit_cond_stmt (as_a <gcond *> (stmt), taken_edge_p);
>>    else if (gimple_code (stmt) == GIMPLE_SWITCH)
>> @@ -7954,6 +8021,12 @@ vrp_visit_stmt (gimple *stmt, edge
>> *taken_edge_p, tree *output_p)
>>    return SSA_PROP_VARYING;
>>  }
>>
>> +static enum ssa_prop_result
>> +vrp_visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
>> +{
>> +  return vrp_visit_stmt_worker (stmt, false, taken_edge_p, output_p);
>> +}
>>
>> as said the refactoring that would be appreciated is to split out the
>> update_value_range calls
>> from the worker functions so you can call the respective functions
>> from the DOM implementations.
>> That they are globbed in vrp_visit_stmt currently is due to the API of
>> the SSA propagator.
>
> Sent this as separate patch for easy reviewing and testing.

Thanks.

>>
>> @@ -8768,6 +8842,12 @@ vrp_visit_phi_node (gphi *phi)
>>               fprintf (dump_file, "\n");
>>             }
>>
>> +         if (dom_p && vr_arg.type == VR_UNDEFINED)
>> +           {
>> +             set_value_range_to_varying (&vr_result);
>> +             break;
>> +           }
>> +
>>
>> eh...  ok, so another way to attack this is, instead of initializing
>> the lattice to sth else
>> than VR_UNDEFINED, make sure to drop the lattice to varying for all PHI
>> args on
>> yet unvisited incoming edges (you're not doing optimistic VRP).  That's
>> the only
>> place you _have_ to do it.
>
>
> Even when it is initialize (as I am doing now), we can still end up with
> VR_UNDEFINED during the propagation.  I have just left the above so that we
> dont end up with the wrong VR.

How would we end up with wrong VRs?  I see

+         /* Discover VR when condition is true.  */
+         extract_range_for_var_from_comparison_expr (op0, code, op0, op1, &vr);
+         if (old_vr->type == VR_RANGE || old_vr->type == VR_ANTI_RANGE)
+           vrp_intersect_ranges (&vr, old_vr);

where you already disregard UNDEFINED as old_vr.

What you might be missing is to set all DEFs on !stmt_interesting_for_vrp to
VARYING.  Also

+      if (stmt_interesting_for_vrp (stmt))
+       {
+         tree lhs = gimple_get_lhs (stmt);
+         value_range vr = VR_INITIALIZER;
+         vrp_visit_stmt_worker (stmt, &taken_edge, &output, &vr);
+         update_value_range (lhs, &vr);
+
+         /* Try folding stmts with the VR discovered.  */
+         if (fold_stmt (&gsi, follow_single_use_edges))
+           update_stmt (gsi_stmt (gsi));

folding here can introduce additional stmts and thus unvisited SSA defs
which would end up with VR_UNINITIALIZED defs - I don't see exactly
where that would cause issues but I'm not sure it might not.  So better
use fold_stmt_inplace or alternatively if fold_stmt returned true then,
remembering the previous stmt gsi, iterate over all stmts emitted and
set their defs to varying (or re-visit them).  See for example how
tree-ssa-forwprop.c does this re-visiting (it revisits all changed stmts).

Note that you want to have a custom valueize function instead of just
follow_single_use_edges as you want to valueize all SSA names according
to their lattice value (if it has a single value).  You can use vrp_valueize
for this though that gets you non-single-use edge following as well.
Eventually it's going to be cleaner to do what the SSA propagator does and
before folding do

   did_replace = replace_uses_in (stmt, vrp_valueize);
   if (fold_stmt (&gsi, follow_single_use_edges)
       || did_replace)
     update_stmt (gsi_stmt (gsi));

exporting replace_uses_in for this is ok.  I guess I prefer this for now.

Overall this now looks good apart from the folding and the VR_INITIALIZER thing.

You can commit the already approved refactoring changes and combine this
patch with the struct value_range move, this way I can more easily look into
issues with the UNDEFINED thing if you can come up with a testcase that
doesn't work.

Thanks,
Richard.

> I also noticed that g++.dg/warn/pr33738.C testcase is now failing. This is
> because, with early-vrp setting value range ccp2 is optimizing without
> issuing a warning. I will look into it.
>
> bootstrap and regression testing is in progress.
>
> Thanks,
> Kugan

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Early VRP Implementation
  2016-08-19 11:41                               ` Richard Biener
@ 2016-08-23  2:12                                 ` Kugan Vivekanandarajah
  2016-09-02  8:11                                   ` Kugan Vivekanandarajah
  2016-09-14 12:11                                   ` Richard Biener
  0 siblings, 2 replies; 67+ messages in thread
From: Kugan Vivekanandarajah @ 2016-08-23  2:12 UTC (permalink / raw)
  To: Richard Biener; +Cc: Andrew Pinski, gcc-patches, Jan Hubicka, Martin Jambor

[-- Attachment #1: Type: text/plain, Size: 9850 bytes --]

Hi,

On 19 August 2016 at 21:41, Richard Biener <richard.guenther@gmail.com> wrote:
> On Tue, Aug 16, 2016 at 9:45 AM, kugan
> <kugan.vivekanandarajah@linaro.org> wrote:
>> Hi Richard,
>>
>> On 12/08/16 20:43, Richard Biener wrote:
>>>
>>> On Wed, Aug 3, 2016 at 3:17 AM, kugan <kugan.vivekanandarajah@linaro.org>
>>> wrote:
>>
>>
>> [SNIP]
>>
>>>
>>> diff --git a/gcc/common.opt b/gcc/common.opt
>>> index 8a292ed..7028cd4 100644
>>> --- a/gcc/common.opt
>>> +++ b/gcc/common.opt
>>> @@ -2482,6 +2482,10 @@ ftree-vrp
>>>  Common Report Var(flag_tree_vrp) Init(0) Optimization
>>>  Perform Value Range Propagation on trees.
>>>
>>> +fdisable-tree-evrp
>>> +Common Report Var(flag_disable_early_vrp) Init(0) Optimization
>>> +Disable Early Value Range Propagation on trees.
>>> +
>>>
>>> no please, this is automatically supported via -fdisable-
>>
>>
>> I am now having -ftree-evrp which is enabled all the time. But This will
>> only be used for disabling the early-vrp. That is, early-vrp will be run
>> when ftree-vrp is enabled and ftree-evrp is not explicitly disabled. Is this
>> OK?
>
> Why would one want to disable early-vrp?  I see you do this in the testsuite
> for non-early VRP unit-tests but using -fdisable-tree-evrp1 there
> would be ok as well.

Removed it altogether. I though that you wanted a way to disable
early-vrp for testing purposes.

>>>
>>> @@ -1728,11 +1736,12 @@ extract_range_from_assert (value_range *vr_p, tree
>>> expr)
>>>      always false.  */
>>>
>>>  static void
>>> -extract_range_from_ssa_name (value_range *vr, tree var)
>>> +extract_range_from_ssa_name (value_range *vr, bool dom_p, tree var)
>>>  {
>>>    value_range *var_vr = get_value_range (var);
>>>
>>> -  if (var_vr->type != VR_VARYING)
>>> +  if (var_vr->type != VR_VARYING
>>> +      && (!dom_p || var_vr->type != VR_UNDEFINED))
>>>      copy_value_range (vr, var_vr);
>>>    else
>>>      set_value_range (vr, VR_RANGE, var, var, NULL);
>>>
>>> why do you need these changes?  I think I already told you you need to
>>> initialize the lattice to sth else than VR_UNDEFINED and that you can't
>>> fully re-use update_value_range.  If you don't want to do that then
>>> instead
>>> of doing changes all over the place do it in get_value_range and have a
>>> global flag.
>>
>>
>> I have now added a global early_vrp_p and use this to initialize
>> VR_INITIALIZER and get_value_range default to VR_VARYING.
>
> ICK.  Ok, I see that this works, but it is quite ugly, so (see below)
>
>>>
>>>
>>> @@ -3594,7 +3643,8 @@ extract_range_from_cond_expr (value_range *vr,
>>> gassign *stmt)
>>>     on the range of its operand and the expression code.  */
>>>
>>>  static void
>>> -extract_range_from_comparison (value_range *vr, enum tree_code code,
>>> +extract_range_from_comparison (value_range *vr,
>>> +                              enum tree_code code,
>>>                                tree type, tree op0, tree op1)
>>>  {
>>>    bool sop = false;
>>>
>>> remove these kind of no-op changes.
>>
>>
>> Done.
>>
>>
>>>
>>> +/* Initialize local data structures for VRP.  If DOM_P is true,
>>> +   we will be calling this from early_vrp where value range propagation
>>> +   is done by visiting stmts in dominator tree.  ssa_propagate engine
>>> +   is not used in this case and that part of the ininitialization will
>>> +   be skipped.  */
>>>
>>>  static void
>>> -vrp_initialize (void)
>>> +vrp_initialize (bool dom_p)
>>>  {
>>>    basic_block bb;
>>>
>>> @@ -6949,6 +7010,9 @@ vrp_initialize (void)
>>>    vr_phi_edge_counts = XCNEWVEC (int, num_ssa_names);
>>>    bitmap_obstack_initialize (&vrp_equiv_obstack);
>>>
>>> +  if (dom_p)
>>> +    return;
>>> +
>>>
>>> split the function instead.
>>>
>>> @@ -7926,7 +7992,8 @@ vrp_visit_switch_stmt (gswitch *stmt, edge
>>> *taken_edge_p)
>>>     If STMT produces a varying value, return SSA_PROP_VARYING.  */
>>>
>>>  static enum ssa_prop_result
>>> -vrp_visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
>>> +vrp_visit_stmt_worker (gimple *stmt, bool dom_p,  edge *taken_edge_p,
>>> +                      tree *output_p)
>>>  {
>>>    tree def;
>>>    ssa_op_iter iter;
>>> @@ -7940,7 +8007,7 @@ vrp_visit_stmt (gimple *stmt, edge
>>> *taken_edge_p, tree *output_p)
>>>    if (!stmt_interesting_for_vrp (stmt))
>>>      gcc_assert (stmt_ends_bb_p (stmt));
>>>    else if (is_gimple_assign (stmt) || is_gimple_call (stmt))
>>> -    return vrp_visit_assignment_or_call (stmt, output_p);
>>> +    return vrp_visit_assignment_or_call (stmt, dom_p, output_p);
>>>    else if (gimple_code (stmt) == GIMPLE_COND)
>>>      return vrp_visit_cond_stmt (as_a <gcond *> (stmt), taken_edge_p);
>>>    else if (gimple_code (stmt) == GIMPLE_SWITCH)
>>> @@ -7954,6 +8021,12 @@ vrp_visit_stmt (gimple *stmt, edge
>>> *taken_edge_p, tree *output_p)
>>>    return SSA_PROP_VARYING;
>>>  }
>>>
>>> +static enum ssa_prop_result
>>> +vrp_visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
>>> +{
>>> +  return vrp_visit_stmt_worker (stmt, false, taken_edge_p, output_p);
>>> +}
>>>
>>> as said the refactoring that would be appreciated is to split out the
>>> update_value_range calls
>>> from the worker functions so you can call the respective functions
>>> from the DOM implementations.
>>> That they are globbed in vrp_visit_stmt currently is due to the API of
>>> the SSA propagator.
>>
>> Sent this as separate patch for easy reviewing and testing.
>
> Thanks.
>
>>>
>>> @@ -8768,6 +8842,12 @@ vrp_visit_phi_node (gphi *phi)
>>>               fprintf (dump_file, "\n");
>>>             }
>>>
>>> +         if (dom_p && vr_arg.type == VR_UNDEFINED)
>>> +           {
>>> +             set_value_range_to_varying (&vr_result);
>>> +             break;
>>> +           }
>>> +
>>>
>>> eh...  ok, so another way to attack this is, instead of initializing
>>> the lattice to sth else
>>> than VR_UNDEFINED, make sure to drop the lattice to varying for all PHI
>>> args on
>>> yet unvisited incoming edges (you're not doing optimistic VRP).  That's
>>> the only
>>> place you _have_ to do it.
>>
>>
>> Even when it is initialize (as I am doing now), we can still end up with
>> VR_UNDEFINED during the propagation.  I have just left the above so that we
>> dont end up with the wrong VR.
>
> How would we end up with wrong VRs?  I see
>
> +         /* Discover VR when condition is true.  */
> +         extract_range_for_var_from_comparison_expr (op0, code, op0, op1, &vr);
> +         if (old_vr->type == VR_RANGE || old_vr->type == VR_ANTI_RANGE)
> +           vrp_intersect_ranges (&vr, old_vr);
>
> where you already disregard UNDEFINED as old_vr.
>
> What you might be missing is to set all DEFs on !stmt_interesting_for_vrp to
> VARYING.  Also
>
> +      if (stmt_interesting_for_vrp (stmt))
> +       {
> +         tree lhs = gimple_get_lhs (stmt);
> +         value_range vr = VR_INITIALIZER;
> +         vrp_visit_stmt_worker (stmt, &taken_edge, &output, &vr);
> +         update_value_range (lhs, &vr);
> +
> +         /* Try folding stmts with the VR discovered.  */
> +         if (fold_stmt (&gsi, follow_single_use_edges))
> +           update_stmt (gsi_stmt (gsi));
>
> folding here can introduce additional stmts and thus unvisited SSA defs
> which would end up with VR_UNINITIALIZED defs - I don't see exactly
> where that would cause issues but I'm not sure it might not.  So better
> use fold_stmt_inplace or alternatively if fold_stmt returned true then,
> remembering the previous stmt gsi, iterate over all stmts emitted and
> set their defs to varying (or re-visit them).  See for example how
> tree-ssa-forwprop.c does this re-visiting (it revisits all changed stmts).

I am now setting the results of stmts that are not interesting to vrp
to VR_VARYING.

Also, before visiting PHI, if any of the arguments are undefined,
result of the PHI is also set varying.

I have removed all the others. This now bootstraps and passes
regressions (see attached patch).


> Note that you want to have a custom valueize function instead of just
> follow_single_use_edges as you want to valueize all SSA names according
> to their lattice value (if it has a single value).  You can use vrp_valueize
> for this though that gets you non-single-use edge following as well.
> Eventually it's going to be cleaner to do what the SSA propagator does and
> before folding do
>
>    did_replace = replace_uses_in (stmt, vrp_valueize);
>    if (fold_stmt (&gsi, follow_single_use_edges)
>        || did_replace)
>      update_stmt (gsi_stmt (gsi));
>
> exporting replace_uses_in for this is ok.  I guess I prefer this for now.

I also added the above.  I noticed that I need
recompute_tree_invariant_for_addr_expr as in ssa_propagate. My initial
implementation also had gimple_purge_all_dead_eh_edges and
fixup_noreturn_call as in ssa_propagat but I thinj that is not needed
as it would be done at the end of the pass.

With this I noticed more stmts are folded before vrp1. This required
me to adjust some testcases.

>
> Overall this now looks good apart from the folding and the VR_INITIALIZER thing.
>
> You can commit the already approved refactoring changes and combine this
> patch with the struct value_range move, this way I can more easily look into
> issues with the UNDEFINED thing if you can come up with a testcase that
> doesn't work.
>

I have now committed all the dependent patches.

Attached patch passes regression and bootstrap except pr33738.C. This
is an unrelated issue as discussed in
https://gcc.gnu.org/ml/gcc-patches/2016-08/msg01386.html

Is this OK?

Thanks,
Kugan


> Thanks,
> Richard.
>
>> I also noticed that g++.dg/warn/pr33738.C testcase is now failing. This is
>> because, with early-vrp setting value range ccp2 is optimizing without
>> issuing a warning. I will look into it.
>>
>> bootstrap and regression testing is in progress.
>>
>> Thanks,
>> Kugan

[-- Attachment #2: p.txt --]
[-- Type: text/plain, Size: 29830 bytes --]

diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 1f04501..e00688a5 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -12433,6 +12433,11 @@ is made by appending @file{.slp} to the source file name.
 Dump each function after Value Range Propagation (VRP).  The file name
 is made by appending @file{.vrp} to the source file name.
 
+@item early vrp
+@opindex fdump-tree-evrp
+Dump each function after Early Value Range Propagation (EVRP).  The file name
+is made by appending @file{.evrp} to the source file name.
+
 @item oaccdevlow
 @opindex fdump-tree-oaccdevlow
 Dump each function after applying device-specific OpenACC transformations.
diff --git a/gcc/passes.def b/gcc/passes.def
index 533157d..9759fed 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -89,6 +89,7 @@ along with GCC; see the file COPYING3.  If not see
 	     execute TODO_rebuild_alias at this point.  */
 	  NEXT_PASS (pass_build_ealias);
 	  NEXT_PASS (pass_fre);
+	  NEXT_PASS (pass_early_vrp);
 	  NEXT_PASS (pass_merge_phi);
           NEXT_PASS (pass_dse);
 	  NEXT_PASS (pass_cd_dce);
diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C b/gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C
index 5e09583..cf4ed33 100644
--- a/gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C
+++ b/gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O -fdump-tree-forwprop1" } */
+/* { dg-options "-O -fno-tree-vrp -fdump-tree-forwprop1" } */
 
 #include <new>
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/evrp1.c b/gcc/testsuite/gcc.dg/tree-ssa/evrp1.c
index e69de29..8c6e4e6 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/evrp1.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/evrp1.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+int foo (int i);
+int bar (int j)
+{
+  if (j > 2)
+    return foo (j + 2);
+  else
+    return j;
+}
+
+/* { dg-final { scan-tree-dump "\\\[5, \\+INF" "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/evrp2.c b/gcc/testsuite/gcc.dg/tree-ssa/evrp2.c
index e69de29..e6d4235 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/evrp2.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/evrp2.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+int foo (int i);
+int bar2 (int j)
+{
+  if (j > 2)
+    {
+      if (j < 7)
+	return foo (j + 1);
+      else
+	return foo (j + 2);
+    }
+  return j;
+}
+
+
+/* { dg-final { scan-tree-dump "\\\[4, 7\\\]" "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/evrp3.c b/gcc/testsuite/gcc.dg/tree-ssa/evrp3.c
index e69de29..1a3bbd5 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/evrp3.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/evrp3.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+int foo (int i);
+void bar (int j)
+{
+  unsigned int i;
+  for (i = 0; i < 10; ++i)
+    {
+      bar (i + 1);
+    }
+}
+
+/* { dg-final { scan-tree-dump "\\\[1, 10\\\]" "evrp" } } */
+
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr20657.c b/gcc/testsuite/gcc.dg/tree-ssa/pr20657.c
index 727ca4c..e678231 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr20657.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr20657.c
@@ -3,7 +3,7 @@
    statement, which was needed to eliminate the second "if" statement.  */
 
 /* { dg-do compile } */
-/* { dg-options "-O2 -fno-tree-dominator-opts -fno-tree-fre -fdump-tree-vrp1-details" } */
+/* { dg-options "-O2 -fno-tree-dominator-opts -fno-tree-fre -fdump-tree-evrp" } */
 
 int
 foo (int a)
@@ -14,4 +14,4 @@ foo (int a)
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "Folding predicate" 1 "vrp1"} } */
+/* { dg-final { scan-tree-dump-times "if" 1 "evrp"} } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c b/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c
index 7efdd63..3a433d6 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c
@@ -3,7 +3,7 @@
    known to be zero after entering the first two "if" statements.  */
 
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1" } */
+/* { dg-options "-O2  -fdump-tree-vrp1" } */
 
 void link_error (void);
 
@@ -21,4 +21,4 @@ foo (int *p, int q)
     }
 }
 
-/* { dg-final { scan-tree-dump-times "Folding predicate r_.* != 0B to 0" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "link_error" 0 "vrp1" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c b/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c
index dcf9148..c4fda8b 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c
@@ -3,7 +3,7 @@
    Check that VRP now gets ranges from BIT_AND_EXPRs.  */
 
 /* { dg-do compile } */
-/* { dg-options "-O2 -fno-tree-ccp -fdump-tree-vrp1" } */
+/* { dg-options "-O2 -fno-tree-ccp -fdump-tree-vrp" } */
 
 int
 foo (int a)
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr37508.c b/gcc/testsuite/gcc.dg/tree-ssa/pr37508.c
index 0963cd9..2ba09af 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr37508.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr37508.c
@@ -46,4 +46,4 @@ int test4 (struct foo2 *x)
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "Folding" 2 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "if" 2 "vrp1" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr61839_2.c b/gcc/testsuite/gcc.dg/tree-ssa/pr61839_2.c
index ffa00a7..e44dc57 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr61839_2.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr61839_2.c
@@ -1,6 +1,6 @@
 /* PR tree-optimization/61839.  */
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1" } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
 /* { dg-require-effective-target int32plus } */
 
 __attribute__ ((noinline))
@@ -47,8 +47,8 @@ int bar2 ()
 
 
 /* Dont optimize 972195717 / 0 in function foo.  */
-/* { dg-final { scan-tree-dump-times "972195717 / _" 1  "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "972195717 / _" 1  "evrp" } } */
 /* Dont optimize 972195717 % 0 in function bar.  */
-/* { dg-final { scan-tree-dump-times "972195717 % _" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "972195717 % _" 1 "evrp" } } */
 /* Optimize in function bar2.  */
-/* { dg-final { scan-tree-dump-times "972195715 % _" 0 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "972195715 % _" 0 "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr64130.c b/gcc/testsuite/gcc.dg/tree-ssa/pr64130.c
index 0b25466..f39bd17 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr64130.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr64130.c
@@ -1,6 +1,6 @@
 
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1" } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
 
 int funsigned (unsigned a)
 {
@@ -13,6 +13,6 @@ int funsigned2 (unsigned a)
   return (-1 * 0x1ffffffffL) / a == 0;
 }
 
-/* { dg-final { scan-tree-dump ": \\\[2, 8589934591\\\]" "vrp1" } } */
-/* { dg-final { scan-tree-dump ": \\\[-8589934591, -2\\\]" "vrp1" } } */
+/* { dg-final { scan-tree-dump ": \\\[2, 8589934591\\\]" "evrp" } } */
+/* { dg-final { scan-tree-dump ": \\\[-8589934591, -2\\\]" "evrp" } } */
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp04.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp04.c
index 61b7a47..67f8f01 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp04.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp04.c
@@ -10,4 +10,4 @@ foo (int a, int b)
       return a + b;
 }
 
-/* { dg-final { scan-tree-dump-times "Folding predicate a_.*to 1" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "if" 1 "vrp1" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp06.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp06.c
index cdad534..c4ce170 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp06.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp06.c
@@ -28,6 +28,6 @@ foo (int i, int j, int a)
   return i + a + j;
 }
 
-/* { dg-final { scan-tree-dump-times "Folding predicate i_\[0-9\]+.*0 to 0" 1 "vrp1" } } */
-/* { dg-final { scan-tree-dump-times "Folding predicate j_\[0-9\]+.*0 to 1" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "Folding predicate \[i|j\]_\[0-9\]+.*0 to 0" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "Folding predicate \[i|j\]_\[0-9\]+.*0 to 1" 1 "vrp1" } } */
 /* { dg-final { scan-tree-dump-times "Folding predicate i_\[0-9]+.*j_\[0-9\]+.* to 0" 1 "vrp1" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp16.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp16.c
index 8f5d5c8..d09f3ae 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp16.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp16.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fno-tree-fre -fdump-tree-vrp1-details" } */
+/* { dg-options "-O2 -fno-tree-fre -fdump-tree-evrp" } */
 
 
 extern void abort (void) __attribute__ ((__noreturn__));
@@ -19,5 +19,5 @@ nonlocal_mentioned_p (rtx x)
 	abort ();
 }
 
-/* { dg-final { scan-tree-dump-times "Folding predicate .*to 0" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "if" 0 "evrp" } } */
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp25.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp25.c
index cbc4ec3..a49f079 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp25.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp25.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fno-tree-fre -fdump-tree-vrp1-details" } */
+/* { dg-options "-O2 -fno-tree-fre -fdump-tree-vrp1" } */
 
 extern void abort ();
 extern void arf ();
@@ -49,5 +49,5 @@ L9:
 /* The second test of (code1 != 53) and the test (D18670 <= 2) are
    both totally subsumed by earlier tests and thus should be folded
    away using VRP.  */
-/* { dg-final { scan-tree-dump-times "Folding predicate" 2 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "if" 3 "vrp1" } } */
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp46.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp46.c
index d3c9ed1..5b279a1 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp46.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp46.c
@@ -27,6 +27,5 @@ func_18 ( int t )
     }
 }
 
-/* There should be a single if left.  */
 
-/* { dg-final { scan-tree-dump-times "if" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "if" 0 "vrp1" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp67.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp67.c
index ef5e8f9..5155f7b 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp67.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp67.c
@@ -36,4 +36,4 @@ unsigned baz (unsigned i)
   return i;
 }
 
-/* { dg-final { scan-tree-dump-times "Folding predicate" 3 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "if" 3 "vrp1" } } */
diff --git a/gcc/timevar.def b/gcc/timevar.def
index 5f12118..8837832 100644
--- a/gcc/timevar.def
+++ b/gcc/timevar.def
@@ -149,6 +149,7 @@ DEFTIMEVAR (TV_TREE_CFG		     , "tree CFG construction")
 DEFTIMEVAR (TV_TREE_CLEANUP_CFG	     , "tree CFG cleanup")
 DEFTIMEVAR (TV_TREE_TAIL_MERGE       , "tree tail merge")
 DEFTIMEVAR (TV_TREE_VRP              , "tree VRP")
+DEFTIMEVAR (TV_TREE_EARLY_VRP        , "tree Early VRP")
 DEFTIMEVAR (TV_TREE_COPY_PROP        , "tree copy propagation")
 DEFTIMEVAR (TV_FIND_REFERENCED_VARS  , "tree find ref. vars")
 DEFTIMEVAR (TV_TREE_PTA		     , "tree PTA")
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index c0059de..86d797e 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -440,6 +440,7 @@ extern gimple_opt_pass *make_pass_fre (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_check_data_deps (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_copy_prop (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_isolate_erroneous_paths (gcc::context *ctxt);
+extern gimple_opt_pass *make_pass_early_vrp (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_vrp (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_uncprop (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_return_slot (gcc::context *ctxt);
diff --git a/gcc/tree-ssa-propagate.c b/gcc/tree-ssa-propagate.c
index c8cf078..97cfde5 100644
--- a/gcc/tree-ssa-propagate.c
+++ b/gcc/tree-ssa-propagate.c
@@ -863,7 +863,7 @@ static struct prop_stats_d prop_stats;
 /* Replace USE references in statement STMT with the values stored in
    PROP_VALUE. Return true if at least one reference was replaced.  */
 
-static bool
+bool
 replace_uses_in (gimple *stmt, ssa_prop_get_value_fn get_value)
 {
   bool replaced = false;
diff --git a/gcc/tree-ssa-propagate.h b/gcc/tree-ssa-propagate.h
index 30d66a9..1a96976 100644
--- a/gcc/tree-ssa-propagate.h
+++ b/gcc/tree-ssa-propagate.h
@@ -84,5 +84,6 @@ extern void propagate_value (use_operand_p, tree);
 extern void replace_exp (use_operand_p, tree);
 extern void propagate_tree_value (tree *, tree);
 extern void propagate_tree_value_into_stmt (gimple_stmt_iterator *, tree);
+extern bool replace_uses_in (gimple *stmt, ssa_prop_get_value_fn get_value);
 
 #endif /* _TREE_SSA_PROPAGATE_H  */
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index 86f2a8f..e4d789b 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -60,6 +60,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "case-cfn-macros.h"
 #include "params.h"
 #include "alloc-pool.h"
+#include "domwalk.h"
 
 #define VR_INITIALIZER { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL }
 
@@ -1455,44 +1456,17 @@ op_with_boolean_value_range_p (tree op)
 	  && integer_onep (vr->max));
 }
 
-/* Extract value range information from an ASSERT_EXPR EXPR and store
-   it in *VR_P.  */
+/* Extract value range information for VAR when (OP COND_CODE LIMIT) is
+   true and store it in *VR_P.  */
 
 static void
-extract_range_from_assert (value_range *vr_p, tree expr)
+extract_range_for_var_from_comparison_expr (tree var, enum tree_code cond_code,
+					    tree op, tree limit,
+					    value_range *vr_p)
 {
-  tree var, cond, limit, min, max, type;
+  tree  min, max, type;
   value_range *limit_vr;
-  enum tree_code cond_code;
-
-  var = ASSERT_EXPR_VAR (expr);
-  cond = ASSERT_EXPR_COND (expr);
-
-  gcc_assert (COMPARISON_CLASS_P (cond));
-
-  /* Find VAR in the ASSERT_EXPR conditional.  */
-  if (var == TREE_OPERAND (cond, 0)
-      || TREE_CODE (TREE_OPERAND (cond, 0)) == PLUS_EXPR
-      || TREE_CODE (TREE_OPERAND (cond, 0)) == NOP_EXPR)
-    {
-      /* If the predicate is of the form VAR COMP LIMIT, then we just
-	 take LIMIT from the RHS and use the same comparison code.  */
-      cond_code = TREE_CODE (cond);
-      limit = TREE_OPERAND (cond, 1);
-      cond = TREE_OPERAND (cond, 0);
-    }
-  else
-    {
-      /* If the predicate is of the form LIMIT COMP VAR, then we need
-	 to flip around the comparison code to create the proper range
-	 for VAR.  */
-      cond_code = swap_tree_comparison (TREE_CODE (cond));
-      limit = TREE_OPERAND (cond, 0);
-      cond = TREE_OPERAND (cond, 1);
-    }
-
   limit = avoid_overflow_infinity (limit);
-
   type = TREE_TYPE (var);
   gcc_assert (limit != var);
 
@@ -1538,15 +1512,15 @@ extract_range_from_assert (value_range *vr_p, tree expr)
      as well build the range [b_4, +INF] for it.
      One special case we handle is extracting a range from a
      range test encoded as (unsigned)var + CST <= limit.  */
-  if (TREE_CODE (cond) == NOP_EXPR
-      || TREE_CODE (cond) == PLUS_EXPR)
+  if (TREE_CODE (op) == NOP_EXPR
+      || TREE_CODE (op) == PLUS_EXPR)
     {
-      if (TREE_CODE (cond) == PLUS_EXPR)
+      if (TREE_CODE (op) == PLUS_EXPR)
         {
-          min = fold_build1 (NEGATE_EXPR, TREE_TYPE (TREE_OPERAND (cond, 1)),
-			     TREE_OPERAND (cond, 1));
+	  min = fold_build1 (NEGATE_EXPR, TREE_TYPE (TREE_OPERAND (op, 1)),
+			     TREE_OPERAND (op, 1));
           max = int_const_binop (PLUS_EXPR, limit, min);
-	  cond = TREE_OPERAND (cond, 0);
+	  op = TREE_OPERAND (op, 0);
 	}
       else
 	{
@@ -1730,6 +1704,41 @@ extract_range_from_assert (value_range *vr_p, tree expr)
   vrp_intersect_ranges (vr_p, get_value_range (var));
 }
 
+/* Extract value range information from an ASSERT_EXPR EXPR and store
+   it in *VR_P.  */
+
+static void
+extract_range_from_assert (value_range *vr_p, tree expr)
+{
+  tree var = ASSERT_EXPR_VAR (expr);
+  tree cond = ASSERT_EXPR_COND (expr);
+  tree limit, op;
+  enum tree_code cond_code;
+  gcc_assert (COMPARISON_CLASS_P (cond));
+
+  /* Find VAR in the ASSERT_EXPR conditional.  */
+  if (var == TREE_OPERAND (cond, 0)
+      || TREE_CODE (TREE_OPERAND (cond, 0)) == PLUS_EXPR
+      || TREE_CODE (TREE_OPERAND (cond, 0)) == NOP_EXPR)
+    {
+      /* If the predicate is of the form VAR COMP LIMIT, then we just
+	 take LIMIT from the RHS and use the same comparison code.  */
+      cond_code = TREE_CODE (cond);
+      limit = TREE_OPERAND (cond, 1);
+      op = TREE_OPERAND (cond, 0);
+    }
+  else
+    {
+      /* If the predicate is of the form LIMIT COMP VAR, then we need
+	 to flip around the comparison code to create the proper range
+	 for VAR.  */
+      cond_code = swap_tree_comparison (TREE_CODE (cond));
+      limit = TREE_OPERAND (cond, 0);
+      op = TREE_OPERAND (cond, 1);
+    }
+  extract_range_for_var_from_comparison_expr (var, cond_code, op,
+					      limit, vr_p);
+}
 
 /* Extract range information from SSA name VAR and store it in VR.  If
    VAR has an interesting range, use it.  Otherwise, create the
@@ -6952,19 +6961,28 @@ stmt_interesting_for_vrp (gimple *stmt)
   return false;
 }
 
-
-/* Initialize local data structures for VRP.  */
+/* Initialize VRP lattice.  */
 
 static void
-vrp_initialize (void)
+vrp_initialize_lattice ()
 {
-  basic_block bb;
-
   values_propagated = false;
   num_vr_values = num_ssa_names;
   vr_value = XCNEWVEC (value_range *, num_vr_values);
   vr_phi_edge_counts = XCNEWVEC (int, num_ssa_names);
   bitmap_obstack_initialize (&vrp_equiv_obstack);
+}
+
+/* Initialize local data structures for VRP.  If DOM_P is true,
+   we will be calling this from early_vrp where value range propagation
+   is done by visiting stmts in dominator tree.  ssa_propagate engine
+   is not used in this case and that part of the ininitialization will
+   be skipped.  */
+
+static void
+vrp_initialize ()
+{
+  basic_block bb;
 
   FOR_EACH_BB_FN (bb, cfun)
     {
@@ -8698,7 +8716,8 @@ vrp_meet (value_range *vr0, const value_range *vr1)
    value ranges, set a new range in VR_RESULT.  */
 
 static void
-extract_range_from_phi_node (gphi *phi, value_range *vr_result)
+extract_range_from_phi_node (gphi *phi, value_range *vr_result,
+			     bool early_vrp_p)
 {
   size_t i;
   tree lhs = PHI_RESULT (phi);
@@ -8821,6 +8840,7 @@ extract_range_from_phi_node (gphi *phi, value_range *vr_result)
      use the updated range and iterate one more time.  If we will not
      simulate this PHI again via the backedge allow us to iterate.  */
   if (edges > 0
+      && !early_vrp_p
       && gimple_phi_num_args (phi) > 1
       && edges == old_edges
       && lhs_vr->type != VR_UNDEFINED
@@ -8888,7 +8908,8 @@ scev_check:
      scev_check can be reached from two paths, one is a fall through from above
      "varying" label, the other is direct goto from code block which tries to
      avoid infinite simulation.  */
-  if ((l = loop_containing_stmt (phi))
+  if (!early_vrp_p
+      && (l = loop_containing_stmt (phi))
       && l->header == gimple_bb (phi))
     adjust_range_with_scev (vr_result, l, phi, lhs);
 
@@ -8918,7 +8939,7 @@ vrp_visit_phi_node (gphi *phi)
 {
   tree lhs = PHI_RESULT (phi);
   value_range vr_result = VR_INITIALIZER;
-  extract_range_from_phi_node (phi, &vr_result);
+  extract_range_from_phi_node (phi, &vr_result, false);
   if (update_value_range (lhs, &vr_result))
     {
       if (dump_file && (dump_flags & TDF_DETAILS))
@@ -10505,6 +10526,22 @@ finalize_jump_threads (void)
   delete equiv_stack;
 }
 
+/* Free VRP lattice.  */
+
+static void
+vrp_free_lattice ()
+{
+  /* Free allocated memory.  */
+  free (vr_value);
+  free (vr_phi_edge_counts);
+  bitmap_obstack_release (&vrp_equiv_obstack);
+  vrp_value_range_pool.release ();
+
+  /* So that we can distinguish between VRP data being available
+     and not available.  */
+  vr_value = NULL;
+  vr_phi_edge_counts = NULL;
+}
 
 /* Traverse all the blocks folding conditionals with known ranges.  */
 
@@ -10551,17 +10588,271 @@ vrp_finalize (bool warn_array_bounds_p)
   /* We must identify jump threading opportunities before we release
      the datastructures built by VRP.  */
   identify_jump_threads ();
+}
 
-  /* Free allocated memory.  */
-  free (vr_value);
-  free (vr_phi_edge_counts);
-  bitmap_obstack_release (&vrp_equiv_obstack);
-  vrp_value_range_pool.release ();
+/* Check to see if the PHI stmt has any back edges taht is not visited yet
+   (Circular dependancy).  In dominator based VRP, if we have back-edges,
+   we will have SSA_NAME operands with VR_UNDEFINED value range. */
 
-  /* So that we can distinguish between VRP data being available
-     and not available.  */
-  vr_value = NULL;
-  vr_phi_edge_counts = NULL;
+static bool
+stmt_visit_phi_node_in_dom_p (gphi *phi)
+{
+  ssa_op_iter iter;
+  use_operand_p oprnd;
+  tree op;
+  value_range *vr;
+  FOR_EACH_PHI_ARG (oprnd, phi, iter, SSA_OP_USE)
+    {
+      op = USE_FROM_PTR (oprnd);
+      if (TREE_CODE (op) == SSA_NAME)
+	{
+	  vr = get_value_range (op);
+	  if (vr->type == VR_UNDEFINED)
+	    return false;
+	}
+    }
+  return true;
+}
+
+/* evrp_dom_walker visits the basic blocks in the dominance order and set
+   the Value Ranges (VR) for SSA_NAMEs in the scope.  Use this VR to
+   discover more VRs.  */
+
+class evrp_dom_walker : public dom_walker
+{
+public:
+  evrp_dom_walker ()
+    : dom_walker (CDI_DOMINATORS), stack (10) {}
+  virtual edge before_dom_children (basic_block);
+  virtual void after_dom_children (basic_block);
+  void push_value_range (const_tree var, value_range *vr);
+  value_range *pop_value_range (const_tree var);
+
+  /* Cond_stack holds the old VR.  */
+  auto_vec<std::pair <const_tree, value_range*> > stack;
+};
+
+/* Return the singleton value-range for NAME or NAME.  */
+
+static inline tree
+evrp_valueize (tree name)
+{
+  if (TREE_CODE (name) == SSA_NAME)
+    {
+      value_range *vr = get_value_range (name);
+      if (vr->type == VR_RANGE
+	  && (range_int_cst_p (vr)
+	      || (TREE_CODE (vr->min) == SSA_NAME))
+	  && vrp_operand_equal_p (vr->min, vr->max))
+	return vr->min;
+    }
+  return name;
+}
+
+/* See if there is any new scope is entered with new VR and set that VR to
+   ssa_name before visiting the statements in the scope.  */
+
+edge
+evrp_dom_walker::before_dom_children (basic_block bb)
+{
+  value_range *new_vr = NULL;
+  tree op0 = NULL_TREE;
+  push_value_range (NULL_TREE, NULL);
+  if (single_pred_p (bb))
+    {
+      edge e = single_pred_edge (bb);
+      value_range vr = VR_INITIALIZER;
+      gimple *stmt = last_stmt (e->src);
+      if (stmt
+	  && gimple_code (stmt) == GIMPLE_COND
+	  && (op0 = gimple_cond_lhs (stmt))
+	  && TREE_CODE (op0) == SSA_NAME
+	  && INTEGRAL_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt))))
+	{
+	  /* Entering a new scope.  Try to see if we can find a VR
+	     here.  */
+	  tree op1 = gimple_cond_rhs (stmt);
+	  tree_code code = gimple_cond_code (stmt);
+	  value_range *old_vr = get_value_range (op0);
+
+	  if (TREE_OVERFLOW_P (op1))
+	    op1 = drop_tree_overflow (op1);
+
+	  /* If condition is false, invert the cond.  */
+	  if (e->flags & EDGE_FALSE_VALUE)
+	    code = invert_tree_comparison (gimple_cond_code (stmt),
+					   HONOR_NANS (op0));
+	  /* Discover VR when condition is true.  */
+	  extract_range_for_var_from_comparison_expr (op0, code, op0, op1, &vr);
+	  if (old_vr->type == VR_RANGE || old_vr->type == VR_ANTI_RANGE)
+	    vrp_intersect_ranges (&vr, old_vr);
+
+	  /* If we found any usable VR, set the VR to ssa_name and create a
+	     PUSH old value in the stack with the old VR.  */
+	  if (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE)
+	    {
+	      new_vr = vrp_value_range_pool.allocate ();
+	      *new_vr = vr;
+	      push_value_range (op0, new_vr);
+	    }
+	}
+    }
+
+  /* Visit PHI stmts and discover any new VRs possible.  */
+  gimple_stmt_iterator gsi;
+  for (gphi_iterator gpi = gsi_start_phis (bb);
+       !gsi_end_p (gpi); gsi_next (&gpi))
+    {
+      gphi *phi = gpi.phi ();
+      tree lhs = PHI_RESULT (phi);
+      value_range vr_result = VR_INITIALIZER;
+      if (stmt_interesting_for_vrp (phi)
+	  && stmt_visit_phi_node_in_dom_p (phi))
+	extract_range_from_phi_node (phi, &vr_result, true);
+      else
+	set_value_range_to_varying (&vr_result);
+      update_value_range (lhs, &vr_result);
+    }
+
+  /* Visit all other stmts and discover any new VRs possible.  */
+  for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+    {
+      gimple *stmt = gsi_stmt (gsi);
+      edge taken_edge;
+      tree output = NULL_TREE;
+      /* TODO, if found taken_edge, we should visit (return it) and travel
+	 again to improve VR as done in DOM/SCCVN optimizations.  It should
+	 be done carefully as stmts might prematurely leave a BB like
+	 in EH.  */
+      if (stmt_interesting_for_vrp (stmt))
+	{
+	  value_range vr = VR_INITIALIZER;
+	  extract_range_from_stmt (stmt, &taken_edge, &output, &vr);
+	  if (output)
+	    update_value_range (output, &vr);
+
+	  /* Try folding stmts with the VR discovered.  */
+	  bool did_replace = replace_uses_in (stmt, evrp_valueize);
+	  if (fold_stmt (&gsi, follow_single_use_edges)
+	      || did_replace)
+	    update_stmt (gsi_stmt (gsi));
+
+	  if (did_replace
+	      && gimple_assign_single_p (stmt))
+	    {
+	      tree rhs = gimple_assign_rhs1 (stmt);
+
+	      if (TREE_CODE (rhs) == ADDR_EXPR)
+		recompute_tree_invariant_for_addr_expr (rhs);
+	    }
+
+	  def_operand_p def_p = SINGLE_SSA_DEF_OPERAND (stmt, SSA_OP_DEF);
+	  /* Set the SSA with the value range.  */
+	  if (def_p
+	      && TREE_CODE (DEF_FROM_PTR (def_p)) == SSA_NAME
+	      && INTEGRAL_TYPE_P (TREE_TYPE (DEF_FROM_PTR (def_p))))
+	    {
+	      tree def = DEF_FROM_PTR (def_p);
+	      unsigned ver = SSA_NAME_VERSION (def);
+	      if ((vr_value[ver]->type == VR_RANGE
+		   || vr_value[ver]->type == VR_ANTI_RANGE)
+		  && (TREE_CODE (vr_value[ver]->min) == INTEGER_CST)
+		  && (TREE_CODE (vr_value[ver]->max) == INTEGER_CST))
+		set_range_info (def, vr_value[ver]->type, vr_value[ver]->min,
+				vr_value[ver]->max);
+	    }
+	}
+      else
+	{
+	  tree def;
+	  ssa_op_iter iter;
+	  FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_DEF)
+	    set_value_range_to_varying (get_value_range (def));
+	}
+    }
+  return NULL;
+}
+
+/* Restore/pop VRs valid only for BB when we leave BB.  */
+
+void
+evrp_dom_walker::after_dom_children (basic_block bb ATTRIBUTE_UNUSED)
+{
+  gcc_checking_assert (!stack.is_empty ());
+  while (stack.last ().first != NULL_TREE)
+    pop_value_range (stack.last ().first);
+  pop_value_range (stack.last ().first);
+}
+
+/* Push the Value Range of VAR to the stack and update it with new VR.  */
+
+void
+evrp_dom_walker::push_value_range (const_tree var, value_range *vr)
+{
+  if (vr != NULL)
+    {
+      unsigned ver = SSA_NAME_VERSION (var);
+      gcc_checking_assert (vr_value);
+      stack.safe_push (std::make_pair (var, vr_value[ver]));
+
+      if (ver < num_vr_values)
+	vr_value[ver] = vr;
+    }
+  else
+    stack.safe_push (std::make_pair (var, vr));
+}
+
+/* Pop the Value Range from the vrp_stack and update VAR with it.  */
+
+value_range *
+evrp_dom_walker::pop_value_range (const_tree var)
+{
+  value_range *vr = stack.last ().second;
+  if (vr != NULL)
+    {
+      unsigned ver = SSA_NAME_VERSION (var);
+      gcc_checking_assert (var == stack.last ().first);
+      gcc_checking_assert (vr_value);
+
+      if (ver < num_vr_values)
+	vr_value[ver] = vr;
+    }
+  stack.pop ();
+  return vr;
+}
+
+
+/* Main entry point for the early vrp pass which is a simplified non-iterative
+   version of VRP where basic blocks are visited in dominance order.  Value
+   ranges discovered in early vrp will also be used by ipa-vrp.  */
+
+static unsigned int
+execute_early_vrp ()
+{
+  edge e;
+  edge_iterator ei;
+  basic_block bb;
+
+  calculate_dominance_info (CDI_DOMINATORS);
+  FOR_EACH_BB_FN (bb, cfun)
+    {
+      FOR_EACH_EDGE (e, ei, bb->preds)
+	e->flags |= EDGE_EXECUTABLE;
+    }
+  vrp_initialize_lattice ();
+
+  /* Walk stmts in dominance order and propagate VRP.  */
+  evrp_dom_walker walker;
+  walker.walk (ENTRY_BLOCK_PTR_FOR_FN (cfun));
+
+  if (dump_file)
+    {
+      fprintf (dump_file, "\nValue ranges after Early VRP:\n\n");
+      dump_all_value_ranges (dump_file);
+      fprintf (dump_file, "\n");
+    }
+  vrp_free_lattice ();
+  return 0;
 }
 
 
@@ -10632,9 +10923,11 @@ execute_vrp (bool warn_array_bounds_p)
   /* For visiting PHI nodes we need EDGE_DFS_BACK computed.  */
   mark_dfs_back_edges ();
 
+  vrp_initialize_lattice ();
   vrp_initialize ();
   ssa_propagate (vrp_visit_stmt, vrp_visit_phi_node);
   vrp_finalize (warn_array_bounds_p);
+  vrp_free_lattice ();
 
   free_numbers_of_iterations_estimates (cfun);
 
@@ -10732,3 +11025,44 @@ make_pass_vrp (gcc::context *ctxt)
 {
   return new pass_vrp (ctxt);
 }
+
+namespace {
+
+const pass_data pass_data_early_vrp =
+{
+  GIMPLE_PASS, /* type */
+  "evrp", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_TREE_EARLY_VRP, /* tv_id */
+  PROP_ssa, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  ( TODO_cleanup_cfg | TODO_update_ssa | TODO_verify_all ),
+};
+
+class pass_early_vrp : public gimple_opt_pass
+{
+public:
+  pass_early_vrp (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_early_vrp, ctxt)
+    {}
+
+  /* opt_pass methods: */
+  opt_pass * clone () { return new pass_early_vrp (m_ctxt); }
+  virtual bool gate (function *)
+    {
+      return flag_tree_vrp != 0;
+    }
+  virtual unsigned int execute (function *)
+    { return execute_early_vrp (); }
+
+}; // class pass_vrp
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_early_vrp (gcc::context *ctxt)
+{
+  return new pass_early_vrp (ctxt);
+}
+

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Add support for IPA VRP in ipa-cp/ipa-prop
  2016-07-21 12:54           ` Jan Hubicka
@ 2016-08-30  5:21             ` Kugan Vivekanandarajah
  2016-08-30 18:12               ` Prathamesh Kulkarni
  2016-09-02 12:31               ` Jan Hubicka
  0 siblings, 2 replies; 67+ messages in thread
From: Kugan Vivekanandarajah @ 2016-08-30  5:21 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: gcc-patches, Richard Biener

[-- Attachment #1: Type: text/plain, Size: 4810 bytes --]

Hi Honza,

Here is a re-based version which also addresses the review comments.

On 21/07/16 22:54, Jan Hubicka wrote:
>> Maybe it is better to separate value range and alignment summary
>> writing/reading to different functions. Here is another updated
>> version which does this.
>
> Makes sense to me. Note that the alignment summary propagation can be either
> handled by doing bitwise constant propagation and/or extending our value ranges
> by stride (as described in
> http://www.lighterra.com/papers/valuerangeprop/Patterson1995-ValueRangeProp.pdf
> I would like it to go eventually away in favour of more generic solution.
>
>> -/* If DEST_PLATS already has aggregate items, check that aggs_by_ref matches
>> +/* 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);
>> +      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);
>
> Clearly we can propagate thorugh expressions here (PLUS_EXPR). I have run
> into similar issue in loop code that builds simple generic expresisons
> (like (int)ssa_name+10) and it would be nice to have easy way to deterine
> their value range based on the knowledge of SSA_NAME's valur range.
>
> Bit this is fine for initial implementaiotn for sure.

Indeed. I will do this as a follow up.

>>
>> +/* 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;
>
> I belive you need to also prevent propagation through functions copmiled with
> -fno-ipa-vrp, not only prevent any transformations.

Do you mean the following, I was following other implementations.

@@ -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 ();

>> +/* Update value range of formal parameters as described in
>> +   ipcp_transformation_summary.  */
>> +
>> +static void
>> +ipcp_update_vr (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->m_vr) == 0)
>> +    return;
>> +  const vec<ipa_vr, va_gc> &vr = *ts->m_vr;
>> +  unsigned count = vr.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);
>> +      tree ddef = ssa_default_def (DECL_STRUCT_FUNCTION (node->decl), parm);
>> +
>> +      if (!ddef || !is_gimple_reg (parm))
>> + continue;
>> +
>> +      if (cgraph_local_p (node)
> The test of cgraph_local_p seems redundant here. The analysis phase should not determine
> anything if function is reachable non-locally.

Removed it.

>> +/* 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 min;
>> +  tree max;
> What is the point of representing range as trees rather than wide ints. Can they
> be non-constant integer?

Changed to wide_int after adding that support.

LTO Bootstrapped and regression tested on x86_64-linux-gnu with no new
regressions, is this OK?

Thanks
Kugan

[-- Attachment #2: 0002-Add-ipa-vrp.patch --]
[-- Type: text/x-patch, Size: 28964 bytes --]

From c6687f60001695dd71316e894010a764cb15606a Mon Sep 17 00:00:00 2001
From: Kugan Vivekanandarajah <kugan.vivekanandarajah@linaro.org>
Date: Tue, 23 Aug 2016 19:47:58 +1000
Subject: [PATCH 2/3] Add ipa-vrp

---
 gcc/cgraph.c                            |   1 +
 gcc/cgraphunit.c                        |   1 +
 gcc/common.opt                          |   4 +
 gcc/ipa-cp.c                            | 243 ++++++++++++++++++++++++++++++++
 gcc/ipa-devirt.c                        |   1 +
 gcc/ipa-inline-transform.c              |   1 +
 gcc/ipa-inline.c                        |   1 +
 gcc/ipa-profile.c                       |   1 +
 gcc/ipa-prop.c                          | 180 ++++++++++++++++++++++-
 gcc/ipa-prop.h                          |  16 +++
 gcc/ipa-utils.c                         |   1 +
 gcc/ipa.c                               |   1 +
 gcc/lto/lto-partition.c                 |   1 +
 gcc/lto/lto.c                           |   1 +
 gcc/opts.c                              |   1 +
 gcc/testsuite/g++.dg/ipa/pure-const-3.C |   2 +-
 gcc/testsuite/gcc.dg/ipa/vrp1.c         |  32 +++++
 gcc/testsuite/gcc.dg/ipa/vrp2.c         |  35 +++++
 gcc/testsuite/gcc.dg/ipa/vrp3.c         |  30 ++++
 gcc/toplev.c                            |   1 +
 20 files changed, 547 insertions(+), 7 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/ipa/vrp1.c
 create mode 100644 gcc/testsuite/gcc.dg/ipa/vrp2.c
 create mode 100644 gcc/testsuite/gcc.dg/ipa/vrp3.c

diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index 9bc5b6b..0a43850 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -49,6 +49,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "value-prof.h"
 #include "ipa-utils.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "ipa-inline.h"
 #include "cfgloop.h"
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index 6a1d126..5588807 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -190,6 +190,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "toplev.h"
 #include "debug.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "gimple-pretty-print.h"
 #include "plugin.h"
diff --git a/gcc/common.opt b/gcc/common.opt
index fd1ac87..79ee799 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -1601,6 +1601,10 @@ fipa-struct-reorg
 Common Ignore
 Does nothing. Preserved for backward compatibility.
 
+fipa-vrp
+Common Report Var(flag_ipa_vrp) Optimization
+Perform IPA Value Range Propagation.
+
 fira-algorithm=
 Common Joined RejectNegative Enum(ira_algorithm) Var(flag_ira_algorithm) Init(IRA_ALGORITHM_CB) Optimization
 -fira-algorithm=[CB|priority] Set the used IRA algorithm.
diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
index 9514dd1..dacef4c 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);
diff --git a/gcc/ipa-devirt.c b/gcc/ipa-devirt.c
index 2cf018b..62a08f8 100644
--- a/gcc/ipa-devirt.c
+++ b/gcc/ipa-devirt.c
@@ -122,6 +122,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-utils.h"
 #include "gimple-fold.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "ipa-inline.h"
 #include "demangle.h"
diff --git a/gcc/ipa-inline-transform.c b/gcc/ipa-inline-transform.c
index 98c7f96..efe7421 100644
--- a/gcc/ipa-inline-transform.c
+++ b/gcc/ipa-inline-transform.c
@@ -39,6 +39,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "cgraph.h"
 #include "tree-cfg.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "ipa-inline.h"
 #include "tree-inline.h"
diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
index 5c9366a..82bb94f 100644
--- a/gcc/ipa-inline.c
+++ b/gcc/ipa-inline.c
@@ -108,6 +108,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "params.h"
 #include "profile.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "ipa-inline.h"
 #include "ipa-utils.h"
diff --git a/gcc/ipa-profile.c b/gcc/ipa-profile.c
index da17bcd..e87615a 100644
--- a/gcc/ipa-profile.c
+++ b/gcc/ipa-profile.c
@@ -62,6 +62,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "value-prof.h"
 #include "tree-inline.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "ipa-inline.h"
 
diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c
index 1629781..9d040f9 100644
--- a/gcc/ipa-prop.c
+++ b/gcc/ipa-prop.c
@@ -311,6 +311,19 @@ ipa_print_node_jump_functions_for_edge (FILE *f, struct cgraph_edge *cs)
 	}
       else
 	fprintf (f, "         Unknown bits\n");
+
+      if (jump_func->vr_known)
+	{
+	  fprintf (f, "         VR  ");
+	  fprintf (f, "%s[",
+		   (jump_func->m_vr.type == VR_ANTI_RANGE) ? "~" : "");
+	  print_decs (jump_func->m_vr.min, f);
+	  fprintf (f, ", ");
+	  print_decs (jump_func->m_vr.max, f);
+	  fprintf (f, "]\n");
+	}
+      else
+	fprintf (f, "         Unknown VR\n");
     }
 }
 
@@ -391,6 +404,7 @@ ipa_set_jf_unknown (struct ipa_jump_func *jfunc)
   jfunc->type = IPA_JF_UNKNOWN;
   jfunc->alignment.known = false;
   jfunc->bits.known = false;
+  jfunc->vr_known = false;
 }
 
 /* Set JFUNC to be a copy of another jmp (to be used by jump function
@@ -1680,9 +1694,28 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
 	    }
 	  else
 	    gcc_assert (!jfunc->alignment.known);
+	  gcc_assert (!jfunc->vr_known);
 	}
       else
-	gcc_assert (!jfunc->alignment.known);
+	{
+	  wide_int min, max;
+	  value_range_type type;
+	  if (TREE_CODE (arg) == SSA_NAME
+	      && param_type
+	      && (type = get_range_info (arg, &min, &max))
+	      && (type == VR_RANGE || type == VR_ANTI_RANGE)
+	      && (min.get_precision () <= TYPE_PRECISION (param_type)
+		  || TYPE_OVERFLOW_WRAPS (param_type)))
+	    {
+	      jfunc->vr_known = true;
+	      jfunc->m_vr.type = type;
+	      jfunc->m_vr.min = wide_int_to_tree (param_type, min);
+	      jfunc->m_vr.max = wide_int_to_tree (param_type, max);
+	    }
+	  else
+	    gcc_assert (!jfunc->vr_known);
+	  gcc_assert (!jfunc->alignment.known);
+	}
 
       if (INTEGRAL_TYPE_P (TREE_TYPE (arg))
 	  && (TREE_CODE (arg) == SSA_NAME || TREE_CODE (arg) == INTEGER_CST))
@@ -3709,16 +3742,28 @@ 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)
     {
       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->m_vr;
       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]);
+      vec<ipa_vr, va_gc> *&dst_vr
+	= ipcp_get_transformation_summary (dst)->m_vr;
+      if (vec_safe_length (src_trans->alignments) > 0)
+	{
+	  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]);
+	}
+      if (vec_safe_length (src_trans->m_vr) > 0)
+	{
+	  vec_safe_reserve_exact (dst_vr, src_vr->length ());
+	  for (unsigned i = 0; i < src_vr->length (); ++i)
+	    dst_vr->quick_push ((*src_vr)[i]);
+	}
     }
 
   if (src_trans && vec_safe_length (src_trans->bits) > 0)
@@ -4660,6 +4705,15 @@ ipa_write_jump_function (struct output_block *ob,
       streamer_write_widest_int (ob, jump_func->bits.value);
       streamer_write_widest_int (ob, jump_func->bits.mask);
     }   
+  bp_pack_value (&bp, jump_func->vr_known, 1);
+  streamer_write_bitpack (&bp);
+  if (jump_func->vr_known)
+    {
+      streamer_write_enum (ob->main_stream, value_rang_type,
+			   VR_LAST, jump_func->m_vr.type);
+      stream_write_tree (ob, jump_func->m_vr.min, true);
+      stream_write_tree (ob, jump_func->m_vr.max, true);
+    }
 }
 
 /* Read in jump function JUMP_FUNC from IB.  */
@@ -4747,6 +4801,20 @@ ipa_read_jump_function (struct lto_input_block *ib,
     }
   else
     jump_func->bits.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->m_vr.type = streamer_read_enum (ib,
+						 value_range_type,
+						 VR_LAST);
+      jump_func->m_vr.min = stream_read_tree (ib, data_in);
+      jump_func->m_vr.max = stream_read_tree (ib, data_in);
+    }
+  else
+    jump_func->vr_known = false;
 }
 
 /* Stream out parts of cgraph_indirect_call_info corresponding to CS that are
@@ -5113,7 +5181,29 @@ write_ipcp_transformation_info (output_block *ob, cgraph_node *node)
   else
     streamer_write_uhwi (ob, 0);
 
-  ts = ipcp_get_transformation_summary (node);
+  if (ts && vec_safe_length (ts->m_vr) > 0)
+    {
+      count = ts->m_vr->length ();
+      streamer_write_uhwi (ob, count);
+      for (unsigned i = 0; i < count; ++i)
+	{
+	  struct bitpack_d bp;
+	  ipa_vr *parm_vr = &(*ts->m_vr)[i];
+	  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);
+	      streamer_write_wide_int (ob, parm_vr->min);
+	      streamer_write_wide_int (ob, parm_vr->max);
+	    }
+	}
+    }
+  else
+    streamer_write_uhwi (ob, 0);
+
   if (ts && vec_safe_length (ts->bits) > 0)
     {
       count = ts->bits->length ();
@@ -5191,6 +5281,30 @@ read_ipcp_transformation_info (lto_input_block *ib, cgraph_node *node,
   if (count > 0)
     {
       ipcp_grow_transformations_if_necessary ();
+
+      ipcp_transformation_summary *ts = ipcp_get_transformation_summary (node);
+      vec_safe_grow_cleared (ts->m_vr, count);
+      for (i = 0; i < count; i++)
+	{
+	  ipa_vr *parm_vr;
+	  parm_vr = &(*ts->m_vr)[i];
+	  struct bitpack_d bp;
+	  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 = streamer_read_wide_int (ib);
+	      parm_vr->max = streamer_read_wide_int (ib);
+	    }
+	}
+    }
+  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->bits, count);
 
@@ -5558,6 +5672,59 @@ ipcp_update_bits (struct cgraph_node *node)
     }
 }
 
+/* Update value range of formal parameters as described in
+   ipcp_transformation_summary.  */
+
+static void
+ipcp_update_vr (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->m_vr) == 0)
+    return;
+  const vec<ipa_vr, va_gc> &vr = *ts->m_vr;
+  unsigned count = vr.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);
+      tree ddef = ssa_default_def (DECL_STRUCT_FUNCTION (node->decl), parm);
+
+      if (!ddef || !is_gimple_reg (parm))
+	continue;
+
+      if (vr[i].known
+	  && INTEGRAL_TYPE_P (TREE_TYPE (ddef))
+	  && !POINTER_TYPE_P (TREE_TYPE (ddef))
+	  && (vr[i].type == VR_RANGE || vr[i].type == VR_ANTI_RANGE))
+	{
+	  tree type = TREE_TYPE (ddef);
+	  unsigned prec = TYPE_PRECISION (type);
+	  if (dump_file)
+	    {
+	      fprintf (dump_file, "Setting value range of param %u ", i);
+	      fprintf (dump_file, "%s[",
+		       (vr[i].type == VR_ANTI_RANGE) ? "~" : "");
+	      print_decs (vr[i].min, dump_file);
+	      fprintf (dump_file, ", ");
+	      print_decs (vr[i].max, dump_file);
+	      fprintf (dump_file, "]\n");
+	    }
+	  set_range_info (ddef, vr[i].type,
+			  wide_int_storage::from (vr[i].min, prec,
+						  TYPE_SIGN (type)),
+			  wide_int_storage::from (vr[i].max, prec,
+						  TYPE_SIGN (type)));
+	}
+    }
+}
+
 /* IPCP transformation phase doing propagation of aggregate values.  */
 
 unsigned int
@@ -5578,6 +5745,7 @@ ipcp_transform_function (struct cgraph_node *node)
 
   ipcp_update_alignments (node);
   ipcp_update_bits (node);
+  ipcp_update_vr (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 e5a56da..a123978 100644
--- a/gcc/ipa-prop.h
+++ b/gcc/ipa-prop.h
@@ -167,6 +167,16 @@ struct GTY(()) ipa_bits
   bool known;
 };
 
+/* 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;
+  wide_int min;
+  wide_int 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.  */
@@ -182,6 +192,10 @@ struct GTY (()) ipa_jump_func
   /* Information about zero/non-zero bits.  */
   struct ipa_bits bits;
 
+  /* Information about value range.  */
+  bool vr_known;
+  value_range m_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
@@ -521,6 +535,8 @@ struct GTY(()) ipcp_transformation_summary
   vec<ipa_alignment, va_gc> *alignments;
   /* Known bits information.  */
   vec<ipa_bits, va_gc> *bits;
+  /* Value range information.  */
+  vec<ipa_vr, va_gc> *m_vr;
 };
 
 void ipa_set_node_agg_value_chain (struct cgraph_node *node,
diff --git a/gcc/ipa-utils.c b/gcc/ipa-utils.c
index 5eb7d5f..61d8dd1 100644
--- a/gcc/ipa-utils.c
+++ b/gcc/ipa-utils.c
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "splay-tree.h"
 #include "ipa-utils.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "ipa-inline.h"
 
diff --git a/gcc/ipa.c b/gcc/ipa.c
index 035fb64..b26dad5 100644
--- a/gcc/ipa.c
+++ b/gcc/ipa.c
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-iterator.h"
 #include "ipa-utils.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "ipa-inline.h"
 #include "dbgcnt.h"
diff --git a/gcc/lto/lto-partition.c b/gcc/lto/lto-partition.c
index 453343a..b52d175 100644
--- a/gcc/lto/lto-partition.c
+++ b/gcc/lto/lto-partition.c
@@ -31,6 +31,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "lto-streamer.h"
 #include "params.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "ipa-inline.h"
 #include "lto-partition.h"
diff --git a/gcc/lto/lto.c b/gcc/lto/lto.c
index 73d1e26..bbf02e8 100644
--- a/gcc/lto/lto.c
+++ b/gcc/lto/lto.c
@@ -36,6 +36,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "toplev.h"
 #include "stor-layout.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "common.h"
 #include "debug.h"
diff --git a/gcc/opts.c b/gcc/opts.c
index bc0570d..bb7879b 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -506,6 +506,7 @@ static const struct default_options default_options_table[] =
     { OPT_LEVELS_2_PLUS, OPT_fipa_cp, NULL, 1 },
     { OPT_LEVELS_2_PLUS, OPT_fipa_cp_alignment, NULL, 1 },
     { OPT_LEVELS_2_PLUS, OPT_fipa_bit_cp, NULL, 1 },
+    { OPT_LEVELS_2_PLUS, OPT_fipa_vrp, NULL, 1 },
     { OPT_LEVELS_2_PLUS, OPT_fdevirtualize, NULL, 1 },
     { OPT_LEVELS_2_PLUS, OPT_fdevirtualize_speculatively, NULL, 1 },
     { OPT_LEVELS_2_PLUS, OPT_fipa_sra, NULL, 1 },
diff --git a/gcc/testsuite/g++.dg/ipa/pure-const-3.C b/gcc/testsuite/g++.dg/ipa/pure-const-3.C
index 3779ecb..ff7fe53 100644
--- a/gcc/testsuite/g++.dg/ipa/pure-const-3.C
+++ b/gcc/testsuite/g++.dg/ipa/pure-const-3.C
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-optimized"  } */
+/* { dg-options "-O2 -fno-ipa-vrp -fdump-tree-optimized"  } */
 int *ptr;
 static int barvar;
 static int b(int a);
diff --git a/gcc/testsuite/gcc.dg/ipa/vrp1.c b/gcc/testsuite/gcc.dg/ipa/vrp1.c
new file mode 100644
index 0000000..72a3139
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/vrp1.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-ipa-cp-details" } */
+
+static __attribute__((noinline, noclone))
+int foo (int i)
+{
+  if (i < 5)
+    __builtin_abort ();
+  return 0;
+}
+
+static __attribute__((noinline, noclone))
+int bar (int j)
+{
+  if (j > 8)
+    return foo (j + 2);
+  else if (j > 2)
+    return foo (j + 3);
+
+  return 0;
+}
+
+int main ()
+{
+  for (unsigned int i =0; i < 1000; ++i)
+    bar (i);
+
+  return 0;
+}
+
+/* { dg-final { scan-ipa-dump "Setting value range of param 0 \\\[6," "cp" } } */
+/* { dg-final { scan-ipa-dump "Setting value range of param 0 \\\[0, 999\\\]" "cp" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/vrp2.c b/gcc/testsuite/gcc.dg/ipa/vrp2.c
new file mode 100644
index 0000000..c720e5c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/vrp2.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-ipa-cp-details" } */
+
+static __attribute__((noinline, noclone))
+int foo (int i)
+{
+  if (i < 4)
+    __builtin_abort ();
+  return 0;
+}
+
+static __attribute__((noinline, noclone))
+int bar (int j)
+{
+  if (j > 8)
+    return foo (j + 2);
+  else if (j > 2)
+    return foo (j + 3);
+
+  return 0;
+}
+
+int main ()
+{
+  foo (100);
+  for (unsigned int i = 0; i < 12; ++i)
+    {
+      bar (i);
+    }
+  foo (4);
+  return 0;
+}
+
+/* { dg-final { scan-ipa-dump "Setting value range of param 0 \\\[4," "cp" } } */
+/* { dg-final { scan-ipa-dump "Setting value range of param 0 \\\[0, 11\\\]" "cp" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/vrp3.c b/gcc/testsuite/gcc.dg/ipa/vrp3.c
new file mode 100644
index 0000000..fb5d54a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/vrp3.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-ipa-cp-details" } */
+
+volatile int cond;
+
+static __attribute__((noinline, noclone))
+int foo (int i)
+{
+  if (i < 5)
+    __builtin_abort ();
+  return 0;
+}
+
+static __attribute__((noinline, noclone))
+int bar (int j)
+{
+  if (cond)
+    foo (j);
+  return 0;
+}
+
+int main ()
+{
+  for (unsigned int i = 0; i < 10; ++i)
+    bar (i);
+
+  return 0;
+}
+
+/* { dg-final { scan-ipa-dump-times "Setting value range of param 0 \\\[0, 9\\\]" 2 "cp" } } */
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 2607904..668eccd 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -71,6 +71,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "dwarf2out.h"
 #include "ipa-reference.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
 #include "gcse.h"
 #include "tree-chkp.h"
-- 
2.7.4


^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Add support for IPA VRP in ipa-cp/ipa-prop
  2016-08-30  5:21             ` Kugan Vivekanandarajah
@ 2016-08-30 18:12               ` Prathamesh Kulkarni
  2016-08-30 21:10                 ` kugan
  2016-09-02 12:31               ` Jan Hubicka
  1 sibling, 1 reply; 67+ messages in thread
From: Prathamesh Kulkarni @ 2016-08-30 18:12 UTC (permalink / raw)
  To: Kugan Vivekanandarajah; +Cc: Jan Hubicka, gcc-patches, Richard Biener

On 30 August 2016 at 10:50, Kugan Vivekanandarajah
<kugan.vivekanandarajah@linaro.org> wrote:
> Hi Honza,
>
> Here is a re-based version which also addresses the review comments.
>
> On 21/07/16 22:54, Jan Hubicka wrote:
>>> Maybe it is better to separate value range and alignment summary
>>> writing/reading to different functions. Here is another updated
>>> version which does this.
>>
>> Makes sense to me. Note that the alignment summary propagation can be either
>> handled by doing bitwise constant propagation and/or extending our value ranges
>> by stride (as described in
>> http://www.lighterra.com/papers/valuerangeprop/Patterson1995-ValueRangeProp.pdf
>> I would like it to go eventually away in favour of more generic solution.
>>
>>> -/* If DEST_PLATS already has aggregate items, check that aggs_by_ref matches
>>> +/* 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);
>>> +      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);
>>
>> Clearly we can propagate thorugh expressions here (PLUS_EXPR). I have run
>> into similar issue in loop code that builds simple generic expresisons
>> (like (int)ssa_name+10) and it would be nice to have easy way to deterine
>> their value range based on the knowledge of SSA_NAME's valur range.
>>
>> Bit this is fine for initial implementaiotn for sure.
>
> Indeed. I will do this as a follow up.
>
>>>
>>> +/* 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;
>>
>> I belive you need to also prevent propagation through functions copmiled with
>> -fno-ipa-vrp, not only prevent any transformations.
>
> Do you mean the following, I was following other implementations.
>
> @@ -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 ();
>
>>> +/* Update value range of formal parameters as described in
>>> +   ipcp_transformation_summary.  */
>>> +
>>> +static void
>>> +ipcp_update_vr (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->m_vr) == 0)
>>> +    return;
>>> +  const vec<ipa_vr, va_gc> &vr = *ts->m_vr;
>>> +  unsigned count = vr.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);
>>> +      tree ddef = ssa_default_def (DECL_STRUCT_FUNCTION (node->decl), parm);
>>> +
>>> +      if (!ddef || !is_gimple_reg (parm))
>>> + continue;
>>> +
>>> +      if (cgraph_local_p (node)
>> The test of cgraph_local_p seems redundant here. The analysis phase should not determine
>> anything if function is reachable non-locally.
>
> Removed it.
>
>>> +/* 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 min;
>>> +  tree max;
>> What is the point of representing range as trees rather than wide ints. Can they
>> be non-constant integer?
>
> Changed to wide_int after adding that support.
>
> LTO Bootstrapped and regression tested on x86_64-linux-gnu with no new
> regressions, is this OK?
Hi Kugan,
Just noticed a small nit - why not reuse ipa_vr in ipa_jump_func
instead of adding vr_known and m_vr ?

Thanks,
Prathamesh
>
> Thanks
> Kugan

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Add support for IPA VRP in ipa-cp/ipa-prop
  2016-08-30 18:12               ` Prathamesh Kulkarni
@ 2016-08-30 21:10                 ` kugan
  0 siblings, 0 replies; 67+ messages in thread
From: kugan @ 2016-08-30 21:10 UTC (permalink / raw)
  To: Prathamesh Kulkarni; +Cc: Jan Hubicka, gcc-patches, Richard Biener

Hi,

> Just noticed a small nit - why not reuse ipa_vr in ipa_jump_func
> instead of adding vr_known and m_vr ?

This is because we want to reuse  vrp_intersect_ranges and vrp_meet 
which are not trivial. On the other hand, in ipa_jump_func, since we 
stream the data we have a simpler data structure with wide_int.

Thanks,
Kugan

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Early VRP Implementation
  2016-08-23  2:12                                 ` Kugan Vivekanandarajah
@ 2016-09-02  8:11                                   ` Kugan Vivekanandarajah
  2016-09-14 12:11                                   ` Richard Biener
  1 sibling, 0 replies; 67+ messages in thread
From: Kugan Vivekanandarajah @ 2016-09-02  8:11 UTC (permalink / raw)
  To: Richard Biener; +Cc: Andrew Pinski, gcc-patches, Jan Hubicka, Martin Jambor

Ping ?

Thanks,
Kugan

On 23 August 2016 at 12:11, Kugan Vivekanandarajah
<kugan.vivekanandarajah@linaro.org> wrote:
> Hi,
>
> On 19 August 2016 at 21:41, Richard Biener <richard.guenther@gmail.com> wrote:
>> On Tue, Aug 16, 2016 at 9:45 AM, kugan
>> <kugan.vivekanandarajah@linaro.org> wrote:
>>> Hi Richard,
>>>
>>> On 12/08/16 20:43, Richard Biener wrote:
>>>>
>>>> On Wed, Aug 3, 2016 at 3:17 AM, kugan <kugan.vivekanandarajah@linaro.org>
>>>> wrote:
>>>
>>>
>>> [SNIP]
>>>
>>>>
>>>> diff --git a/gcc/common.opt b/gcc/common.opt
>>>> index 8a292ed..7028cd4 100644
>>>> --- a/gcc/common.opt
>>>> +++ b/gcc/common.opt
>>>> @@ -2482,6 +2482,10 @@ ftree-vrp
>>>>  Common Report Var(flag_tree_vrp) Init(0) Optimization
>>>>  Perform Value Range Propagation on trees.
>>>>
>>>> +fdisable-tree-evrp
>>>> +Common Report Var(flag_disable_early_vrp) Init(0) Optimization
>>>> +Disable Early Value Range Propagation on trees.
>>>> +
>>>>
>>>> no please, this is automatically supported via -fdisable-
>>>
>>>
>>> I am now having -ftree-evrp which is enabled all the time. But This will
>>> only be used for disabling the early-vrp. That is, early-vrp will be run
>>> when ftree-vrp is enabled and ftree-evrp is not explicitly disabled. Is this
>>> OK?
>>
>> Why would one want to disable early-vrp?  I see you do this in the testsuite
>> for non-early VRP unit-tests but using -fdisable-tree-evrp1 there
>> would be ok as well.
>
> Removed it altogether. I though that you wanted a way to disable
> early-vrp for testing purposes.
>
>>>>
>>>> @@ -1728,11 +1736,12 @@ extract_range_from_assert (value_range *vr_p, tree
>>>> expr)
>>>>      always false.  */
>>>>
>>>>  static void
>>>> -extract_range_from_ssa_name (value_range *vr, tree var)
>>>> +extract_range_from_ssa_name (value_range *vr, bool dom_p, tree var)
>>>>  {
>>>>    value_range *var_vr = get_value_range (var);
>>>>
>>>> -  if (var_vr->type != VR_VARYING)
>>>> +  if (var_vr->type != VR_VARYING
>>>> +      && (!dom_p || var_vr->type != VR_UNDEFINED))
>>>>      copy_value_range (vr, var_vr);
>>>>    else
>>>>      set_value_range (vr, VR_RANGE, var, var, NULL);
>>>>
>>>> why do you need these changes?  I think I already told you you need to
>>>> initialize the lattice to sth else than VR_UNDEFINED and that you can't
>>>> fully re-use update_value_range.  If you don't want to do that then
>>>> instead
>>>> of doing changes all over the place do it in get_value_range and have a
>>>> global flag.
>>>
>>>
>>> I have now added a global early_vrp_p and use this to initialize
>>> VR_INITIALIZER and get_value_range default to VR_VARYING.
>>
>> ICK.  Ok, I see that this works, but it is quite ugly, so (see below)
>>
>>>>
>>>>
>>>> @@ -3594,7 +3643,8 @@ extract_range_from_cond_expr (value_range *vr,
>>>> gassign *stmt)
>>>>     on the range of its operand and the expression code.  */
>>>>
>>>>  static void
>>>> -extract_range_from_comparison (value_range *vr, enum tree_code code,
>>>> +extract_range_from_comparison (value_range *vr,
>>>> +                              enum tree_code code,
>>>>                                tree type, tree op0, tree op1)
>>>>  {
>>>>    bool sop = false;
>>>>
>>>> remove these kind of no-op changes.
>>>
>>>
>>> Done.
>>>
>>>
>>>>
>>>> +/* Initialize local data structures for VRP.  If DOM_P is true,
>>>> +   we will be calling this from early_vrp where value range propagation
>>>> +   is done by visiting stmts in dominator tree.  ssa_propagate engine
>>>> +   is not used in this case and that part of the ininitialization will
>>>> +   be skipped.  */
>>>>
>>>>  static void
>>>> -vrp_initialize (void)
>>>> +vrp_initialize (bool dom_p)
>>>>  {
>>>>    basic_block bb;
>>>>
>>>> @@ -6949,6 +7010,9 @@ vrp_initialize (void)
>>>>    vr_phi_edge_counts = XCNEWVEC (int, num_ssa_names);
>>>>    bitmap_obstack_initialize (&vrp_equiv_obstack);
>>>>
>>>> +  if (dom_p)
>>>> +    return;
>>>> +
>>>>
>>>> split the function instead.
>>>>
>>>> @@ -7926,7 +7992,8 @@ vrp_visit_switch_stmt (gswitch *stmt, edge
>>>> *taken_edge_p)
>>>>     If STMT produces a varying value, return SSA_PROP_VARYING.  */
>>>>
>>>>  static enum ssa_prop_result
>>>> -vrp_visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
>>>> +vrp_visit_stmt_worker (gimple *stmt, bool dom_p,  edge *taken_edge_p,
>>>> +                      tree *output_p)
>>>>  {
>>>>    tree def;
>>>>    ssa_op_iter iter;
>>>> @@ -7940,7 +8007,7 @@ vrp_visit_stmt (gimple *stmt, edge
>>>> *taken_edge_p, tree *output_p)
>>>>    if (!stmt_interesting_for_vrp (stmt))
>>>>      gcc_assert (stmt_ends_bb_p (stmt));
>>>>    else if (is_gimple_assign (stmt) || is_gimple_call (stmt))
>>>> -    return vrp_visit_assignment_or_call (stmt, output_p);
>>>> +    return vrp_visit_assignment_or_call (stmt, dom_p, output_p);
>>>>    else if (gimple_code (stmt) == GIMPLE_COND)
>>>>      return vrp_visit_cond_stmt (as_a <gcond *> (stmt), taken_edge_p);
>>>>    else if (gimple_code (stmt) == GIMPLE_SWITCH)
>>>> @@ -7954,6 +8021,12 @@ vrp_visit_stmt (gimple *stmt, edge
>>>> *taken_edge_p, tree *output_p)
>>>>    return SSA_PROP_VARYING;
>>>>  }
>>>>
>>>> +static enum ssa_prop_result
>>>> +vrp_visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
>>>> +{
>>>> +  return vrp_visit_stmt_worker (stmt, false, taken_edge_p, output_p);
>>>> +}
>>>>
>>>> as said the refactoring that would be appreciated is to split out the
>>>> update_value_range calls
>>>> from the worker functions so you can call the respective functions
>>>> from the DOM implementations.
>>>> That they are globbed in vrp_visit_stmt currently is due to the API of
>>>> the SSA propagator.
>>>
>>> Sent this as separate patch for easy reviewing and testing.
>>
>> Thanks.
>>
>>>>
>>>> @@ -8768,6 +8842,12 @@ vrp_visit_phi_node (gphi *phi)
>>>>               fprintf (dump_file, "\n");
>>>>             }
>>>>
>>>> +         if (dom_p && vr_arg.type == VR_UNDEFINED)
>>>> +           {
>>>> +             set_value_range_to_varying (&vr_result);
>>>> +             break;
>>>> +           }
>>>> +
>>>>
>>>> eh...  ok, so another way to attack this is, instead of initializing
>>>> the lattice to sth else
>>>> than VR_UNDEFINED, make sure to drop the lattice to varying for all PHI
>>>> args on
>>>> yet unvisited incoming edges (you're not doing optimistic VRP).  That's
>>>> the only
>>>> place you _have_ to do it.
>>>
>>>
>>> Even when it is initialize (as I am doing now), we can still end up with
>>> VR_UNDEFINED during the propagation.  I have just left the above so that we
>>> dont end up with the wrong VR.
>>
>> How would we end up with wrong VRs?  I see
>>
>> +         /* Discover VR when condition is true.  */
>> +         extract_range_for_var_from_comparison_expr (op0, code, op0, op1, &vr);
>> +         if (old_vr->type == VR_RANGE || old_vr->type == VR_ANTI_RANGE)
>> +           vrp_intersect_ranges (&vr, old_vr);
>>
>> where you already disregard UNDEFINED as old_vr.
>>
>> What you might be missing is to set all DEFs on !stmt_interesting_for_vrp to
>> VARYING.  Also
>>
>> +      if (stmt_interesting_for_vrp (stmt))
>> +       {
>> +         tree lhs = gimple_get_lhs (stmt);
>> +         value_range vr = VR_INITIALIZER;
>> +         vrp_visit_stmt_worker (stmt, &taken_edge, &output, &vr);
>> +         update_value_range (lhs, &vr);
>> +
>> +         /* Try folding stmts with the VR discovered.  */
>> +         if (fold_stmt (&gsi, follow_single_use_edges))
>> +           update_stmt (gsi_stmt (gsi));
>>
>> folding here can introduce additional stmts and thus unvisited SSA defs
>> which would end up with VR_UNINITIALIZED defs - I don't see exactly
>> where that would cause issues but I'm not sure it might not.  So better
>> use fold_stmt_inplace or alternatively if fold_stmt returned true then,
>> remembering the previous stmt gsi, iterate over all stmts emitted and
>> set their defs to varying (or re-visit them).  See for example how
>> tree-ssa-forwprop.c does this re-visiting (it revisits all changed stmts).
>
> I am now setting the results of stmts that are not interesting to vrp
> to VR_VARYING.
>
> Also, before visiting PHI, if any of the arguments are undefined,
> result of the PHI is also set varying.
>
> I have removed all the others. This now bootstraps and passes
> regressions (see attached patch).
>
>
>> Note that you want to have a custom valueize function instead of just
>> follow_single_use_edges as you want to valueize all SSA names according
>> to their lattice value (if it has a single value).  You can use vrp_valueize
>> for this though that gets you non-single-use edge following as well.
>> Eventually it's going to be cleaner to do what the SSA propagator does and
>> before folding do
>>
>>    did_replace = replace_uses_in (stmt, vrp_valueize);
>>    if (fold_stmt (&gsi, follow_single_use_edges)
>>        || did_replace)
>>      update_stmt (gsi_stmt (gsi));
>>
>> exporting replace_uses_in for this is ok.  I guess I prefer this for now.
>
> I also added the above.  I noticed that I need
> recompute_tree_invariant_for_addr_expr as in ssa_propagate. My initial
> implementation also had gimple_purge_all_dead_eh_edges and
> fixup_noreturn_call as in ssa_propagat but I thinj that is not needed
> as it would be done at the end of the pass.
>
> With this I noticed more stmts are folded before vrp1. This required
> me to adjust some testcases.
>
>>
>> Overall this now looks good apart from the folding and the VR_INITIALIZER thing.
>>
>> You can commit the already approved refactoring changes and combine this
>> patch with the struct value_range move, this way I can more easily look into
>> issues with the UNDEFINED thing if you can come up with a testcase that
>> doesn't work.
>>
>
> I have now committed all the dependent patches.
>
> Attached patch passes regression and bootstrap except pr33738.C. This
> is an unrelated issue as discussed in
> https://gcc.gnu.org/ml/gcc-patches/2016-08/msg01386.html
>
> Is this OK?
>
> Thanks,
> Kugan
>
>
>> Thanks,
>> Richard.
>>
>>> I also noticed that g++.dg/warn/pr33738.C testcase is now failing. This is
>>> because, with early-vrp setting value range ccp2 is optimizing without
>>> issuing a warning. I will look into it.
>>>
>>> bootstrap and regression testing is in progress.
>>>
>>> Thanks,
>>> Kugan

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Add support for IPA VRP in ipa-cp/ipa-prop
  2016-08-30  5:21             ` Kugan Vivekanandarajah
  2016-08-30 18:12               ` Prathamesh Kulkarni
@ 2016-09-02 12:31               ` Jan Hubicka
  1 sibling, 0 replies; 67+ messages in thread
From: Jan Hubicka @ 2016-09-02 12:31 UTC (permalink / raw)
  To: Kugan Vivekanandarajah; +Cc: Jan Hubicka, gcc-patches, Richard Biener

> Hi Honza,
> 
> Here is a re-based version which also addresses the review comments.
> 
> Do you mean the following, I was following other implementations.
> 
> @@ -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 ();

yes, that looks fine.

Path is OK, thanks!

Honza

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Early VRP Implementation
  2016-08-23  2:12                                 ` Kugan Vivekanandarajah
  2016-09-02  8:11                                   ` Kugan Vivekanandarajah
@ 2016-09-14 12:11                                   ` Richard Biener
  2016-09-14 21:47                                     ` Jan Hubicka
  2016-09-16  6:37                                     ` kugan
  1 sibling, 2 replies; 67+ messages in thread
From: Richard Biener @ 2016-09-14 12:11 UTC (permalink / raw)
  To: Kugan Vivekanandarajah
  Cc: Andrew Pinski, gcc-patches, Jan Hubicka, Martin Jambor

On Tue, Aug 23, 2016 at 4:11 AM, Kugan Vivekanandarajah
<kugan.vivekanandarajah@linaro.org> wrote:
> Hi,
>
> On 19 August 2016 at 21:41, Richard Biener <richard.guenther@gmail.com> wrote:
>> On Tue, Aug 16, 2016 at 9:45 AM, kugan
>> <kugan.vivekanandarajah@linaro.org> wrote:
>>> Hi Richard,
>>>
>>> On 12/08/16 20:43, Richard Biener wrote:
>>>>
>>>> On Wed, Aug 3, 2016 at 3:17 AM, kugan <kugan.vivekanandarajah@linaro.org>
>>>> wrote:
>>>
>>>
>>> [SNIP]
>>>
>>>>
>>>> diff --git a/gcc/common.opt b/gcc/common.opt
>>>> index 8a292ed..7028cd4 100644
>>>> --- a/gcc/common.opt
>>>> +++ b/gcc/common.opt
>>>> @@ -2482,6 +2482,10 @@ ftree-vrp
>>>>  Common Report Var(flag_tree_vrp) Init(0) Optimization
>>>>  Perform Value Range Propagation on trees.
>>>>
>>>> +fdisable-tree-evrp
>>>> +Common Report Var(flag_disable_early_vrp) Init(0) Optimization
>>>> +Disable Early Value Range Propagation on trees.
>>>> +
>>>>
>>>> no please, this is automatically supported via -fdisable-
>>>
>>>
>>> I am now having -ftree-evrp which is enabled all the time. But This will
>>> only be used for disabling the early-vrp. That is, early-vrp will be run
>>> when ftree-vrp is enabled and ftree-evrp is not explicitly disabled. Is this
>>> OK?
>>
>> Why would one want to disable early-vrp?  I see you do this in the testsuite
>> for non-early VRP unit-tests but using -fdisable-tree-evrp1 there
>> would be ok as well.
>
> Removed it altogether. I though that you wanted a way to disable
> early-vrp for testing purposes.

But there is via the generic -fdisable-tree-DUMPFILE way.

>>>>
>>>> @@ -1728,11 +1736,12 @@ extract_range_from_assert (value_range *vr_p, tree
>>>> expr)
>>>>      always false.  */
>>>>
>>>>  static void
>>>> -extract_range_from_ssa_name (value_range *vr, tree var)
>>>> +extract_range_from_ssa_name (value_range *vr, bool dom_p, tree var)
>>>>  {
>>>>    value_range *var_vr = get_value_range (var);
>>>>
>>>> -  if (var_vr->type != VR_VARYING)
>>>> +  if (var_vr->type != VR_VARYING
>>>> +      && (!dom_p || var_vr->type != VR_UNDEFINED))
>>>>      copy_value_range (vr, var_vr);
>>>>    else
>>>>      set_value_range (vr, VR_RANGE, var, var, NULL);
>>>>
>>>> why do you need these changes?  I think I already told you you need to
>>>> initialize the lattice to sth else than VR_UNDEFINED and that you can't
>>>> fully re-use update_value_range.  If you don't want to do that then
>>>> instead
>>>> of doing changes all over the place do it in get_value_range and have a
>>>> global flag.
>>>
>>>
>>> I have now added a global early_vrp_p and use this to initialize
>>> VR_INITIALIZER and get_value_range default to VR_VARYING.
>>
>> ICK.  Ok, I see that this works, but it is quite ugly, so (see below)
>>
>>>>
>>>>
>>>> @@ -3594,7 +3643,8 @@ extract_range_from_cond_expr (value_range *vr,
>>>> gassign *stmt)
>>>>     on the range of its operand and the expression code.  */
>>>>
>>>>  static void
>>>> -extract_range_from_comparison (value_range *vr, enum tree_code code,
>>>> +extract_range_from_comparison (value_range *vr,
>>>> +                              enum tree_code code,
>>>>                                tree type, tree op0, tree op1)
>>>>  {
>>>>    bool sop = false;
>>>>
>>>> remove these kind of no-op changes.
>>>
>>>
>>> Done.
>>>
>>>
>>>>
>>>> +/* Initialize local data structures for VRP.  If DOM_P is true,
>>>> +   we will be calling this from early_vrp where value range propagation
>>>> +   is done by visiting stmts in dominator tree.  ssa_propagate engine
>>>> +   is not used in this case and that part of the ininitialization will
>>>> +   be skipped.  */
>>>>
>>>>  static void
>>>> -vrp_initialize (void)
>>>> +vrp_initialize (bool dom_p)
>>>>  {
>>>>    basic_block bb;
>>>>
>>>> @@ -6949,6 +7010,9 @@ vrp_initialize (void)
>>>>    vr_phi_edge_counts = XCNEWVEC (int, num_ssa_names);
>>>>    bitmap_obstack_initialize (&vrp_equiv_obstack);
>>>>
>>>> +  if (dom_p)
>>>> +    return;
>>>> +
>>>>
>>>> split the function instead.
>>>>
>>>> @@ -7926,7 +7992,8 @@ vrp_visit_switch_stmt (gswitch *stmt, edge
>>>> *taken_edge_p)
>>>>     If STMT produces a varying value, return SSA_PROP_VARYING.  */
>>>>
>>>>  static enum ssa_prop_result
>>>> -vrp_visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
>>>> +vrp_visit_stmt_worker (gimple *stmt, bool dom_p,  edge *taken_edge_p,
>>>> +                      tree *output_p)
>>>>  {
>>>>    tree def;
>>>>    ssa_op_iter iter;
>>>> @@ -7940,7 +8007,7 @@ vrp_visit_stmt (gimple *stmt, edge
>>>> *taken_edge_p, tree *output_p)
>>>>    if (!stmt_interesting_for_vrp (stmt))
>>>>      gcc_assert (stmt_ends_bb_p (stmt));
>>>>    else if (is_gimple_assign (stmt) || is_gimple_call (stmt))
>>>> -    return vrp_visit_assignment_or_call (stmt, output_p);
>>>> +    return vrp_visit_assignment_or_call (stmt, dom_p, output_p);
>>>>    else if (gimple_code (stmt) == GIMPLE_COND)
>>>>      return vrp_visit_cond_stmt (as_a <gcond *> (stmt), taken_edge_p);
>>>>    else if (gimple_code (stmt) == GIMPLE_SWITCH)
>>>> @@ -7954,6 +8021,12 @@ vrp_visit_stmt (gimple *stmt, edge
>>>> *taken_edge_p, tree *output_p)
>>>>    return SSA_PROP_VARYING;
>>>>  }
>>>>
>>>> +static enum ssa_prop_result
>>>> +vrp_visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
>>>> +{
>>>> +  return vrp_visit_stmt_worker (stmt, false, taken_edge_p, output_p);
>>>> +}
>>>>
>>>> as said the refactoring that would be appreciated is to split out the
>>>> update_value_range calls
>>>> from the worker functions so you can call the respective functions
>>>> from the DOM implementations.
>>>> That they are globbed in vrp_visit_stmt currently is due to the API of
>>>> the SSA propagator.
>>>
>>> Sent this as separate patch for easy reviewing and testing.
>>
>> Thanks.
>>
>>>>
>>>> @@ -8768,6 +8842,12 @@ vrp_visit_phi_node (gphi *phi)
>>>>               fprintf (dump_file, "\n");
>>>>             }
>>>>
>>>> +         if (dom_p && vr_arg.type == VR_UNDEFINED)
>>>> +           {
>>>> +             set_value_range_to_varying (&vr_result);
>>>> +             break;
>>>> +           }
>>>> +
>>>>
>>>> eh...  ok, so another way to attack this is, instead of initializing
>>>> the lattice to sth else
>>>> than VR_UNDEFINED, make sure to drop the lattice to varying for all PHI
>>>> args on
>>>> yet unvisited incoming edges (you're not doing optimistic VRP).  That's
>>>> the only
>>>> place you _have_ to do it.
>>>
>>>
>>> Even when it is initialize (as I am doing now), we can still end up with
>>> VR_UNDEFINED during the propagation.  I have just left the above so that we
>>> dont end up with the wrong VR.
>>
>> How would we end up with wrong VRs?  I see
>>
>> +         /* Discover VR when condition is true.  */
>> +         extract_range_for_var_from_comparison_expr (op0, code, op0, op1, &vr);
>> +         if (old_vr->type == VR_RANGE || old_vr->type == VR_ANTI_RANGE)
>> +           vrp_intersect_ranges (&vr, old_vr);
>>
>> where you already disregard UNDEFINED as old_vr.
>>
>> What you might be missing is to set all DEFs on !stmt_interesting_for_vrp to
>> VARYING.  Also
>>
>> +      if (stmt_interesting_for_vrp (stmt))
>> +       {
>> +         tree lhs = gimple_get_lhs (stmt);
>> +         value_range vr = VR_INITIALIZER;
>> +         vrp_visit_stmt_worker (stmt, &taken_edge, &output, &vr);
>> +         update_value_range (lhs, &vr);
>> +
>> +         /* Try folding stmts with the VR discovered.  */
>> +         if (fold_stmt (&gsi, follow_single_use_edges))
>> +           update_stmt (gsi_stmt (gsi));
>>
>> folding here can introduce additional stmts and thus unvisited SSA defs
>> which would end up with VR_UNINITIALIZED defs - I don't see exactly
>> where that would cause issues but I'm not sure it might not.  So better
>> use fold_stmt_inplace or alternatively if fold_stmt returned true then,
>> remembering the previous stmt gsi, iterate over all stmts emitted and
>> set their defs to varying (or re-visit them).  See for example how
>> tree-ssa-forwprop.c does this re-visiting (it revisits all changed stmts).
>
> I am now setting the results of stmts that are not interesting to vrp
> to VR_VARYING.
>
> Also, before visiting PHI, if any of the arguments are undefined,
> result of the PHI is also set varying.
>
> I have removed all the others. This now bootstraps and passes
> regressions (see attached patch).
>
>
>> Note that you want to have a custom valueize function instead of just
>> follow_single_use_edges as you want to valueize all SSA names according
>> to their lattice value (if it has a single value).  You can use vrp_valueize
>> for this though that gets you non-single-use edge following as well.
>> Eventually it's going to be cleaner to do what the SSA propagator does and
>> before folding do
>>
>>    did_replace = replace_uses_in (stmt, vrp_valueize);
>>    if (fold_stmt (&gsi, follow_single_use_edges)
>>        || did_replace)
>>      update_stmt (gsi_stmt (gsi));
>>
>> exporting replace_uses_in for this is ok.  I guess I prefer this for now.
>
> I also added the above.  I noticed that I need
> recompute_tree_invariant_for_addr_expr as in ssa_propagate. My initial
> implementation also had gimple_purge_all_dead_eh_edges and
> fixup_noreturn_call as in ssa_propagat but I thinj that is not needed
> as it would be done at the end of the pass.

I don't see this being done at the end of the pass.  So please re-instantiate
that parts.

> With this I noticed more stmts are folded before vrp1. This required
> me to adjust some testcases.
>
>>
>> Overall this now looks good apart from the folding and the VR_INITIALIZER thing.
>>
>> You can commit the already approved refactoring changes and combine this
>> patch with the struct value_range move, this way I can more easily look into
>> issues with the UNDEFINED thing if you can come up with a testcase that
>> doesn't work.
>>
>
> I have now committed all the dependent patches.
>
> Attached patch passes regression and bootstrap except pr33738.C. This
> is an unrelated issue as discussed in
> https://gcc.gnu.org/ml/gcc-patches/2016-08/msg01386.html
>
> Is this OK?

+/* Initialize local data structures for VRP.  If DOM_P is true,
+   we will be calling this from early_vrp where value range propagation
+   is done by visiting stmts in dominator tree.  ssa_propagate engine
+   is not used in this case and that part of the ininitialization will
+   be skipped.  */
+
+static void
+vrp_initialize ()

comment needs updating now.


 static void
-extract_range_from_phi_node (gphi *phi, value_range *vr_result)
+extract_range_from_phi_node (gphi *phi, value_range *vr_result,
+                            bool early_vrp_p)
 {


I don't think you need this changes now that you have
stmt_visit_phi_node_in_dom_p
guarding its call.

+static bool
+stmt_visit_phi_node_in_dom_p (gphi *phi)
+{
+  ssa_op_iter iter;
+  use_operand_p oprnd;
+  tree op;
+  value_range *vr;
+  FOR_EACH_PHI_ARG (oprnd, phi, iter, SSA_OP_USE)
+    {
+      op = USE_FROM_PTR (oprnd);
+      if (TREE_CODE (op) == SSA_NAME)
+       {
+         vr = get_value_range (op);
+         if (vr->type == VR_UNDEFINED)
+           return false;
+       }
+    }

I think this is overly conservative in never allowing UNDEFINED on PHI
node args (even if the def was actually visited).  I think that the most
easy way to improve this bit would be to actually track visited blocks.
You already set the EDGE_EXECUTABLE flag on edges so you could
clear BB_VISITED on all blocks and set it in the before_dom_children
hook (at the end).  Then the above can be folded into the PHI visiting:

    bool has_unvisited_pred = false;
    FOR_EACH_EDGE (e, ei, bb->preds)
       if (!(e->src->flags & BB_VISITED))
         {
            has_unvisited_preds = true;
            break;
         }

+  /* Visit PHI stmts and discover any new VRs possible.  */
+  gimple_stmt_iterator gsi;
+  for (gphi_iterator gpi = gsi_start_phis (bb);
+       !gsi_end_p (gpi); gsi_next (&gpi))
+    {
+      gphi *phi = gpi.phi ();
+      tree lhs = PHI_RESULT (phi);
+      value_range vr_result = VR_INITIALIZER;
+      if (! has_unvisived_preds
           && stmt_interesting_for_vrp (phi)
+         && stmt_visit_phi_node_in_dom_p (phi))
+       extract_range_from_phi_node (phi, &vr_result, true);
+      else
+       set_value_range_to_varying (&vr_result);
+      update_value_range (lhs, &vr_result);
+    }

due to a bug in IRA you need to make sure to un-set BB_VISITED after
early-vrp is finished again.

+         /* Try folding stmts with the VR discovered.  */
+         bool did_replace = replace_uses_in (stmt, evrp_valueize);
+         if (fold_stmt (&gsi, follow_single_use_edges)
+             || did_replace)
+           update_stmt (gsi_stmt (gsi));

you should be able to re-use vrp_valueize here.

+         def_operand_p def_p = SINGLE_SSA_DEF_OPERAND (stmt, SSA_OP_DEF);
+         /* Set the SSA with the value range.  */
+         if (def_p
+             && TREE_CODE (DEF_FROM_PTR (def_p)) == SSA_NAME
+             && INTEGRAL_TYPE_P (TREE_TYPE (DEF_FROM_PTR (def_p))))
+           {
+             tree def = DEF_FROM_PTR (def_p);
+             unsigned ver = SSA_NAME_VERSION (def);
+             if ((vr_value[ver]->type == VR_RANGE

Use get_value_range () please, not direct access to vr_value.

+                  || vr_value[ver]->type == VR_ANTI_RANGE)
+                 && (TREE_CODE (vr_value[ver]->min) == INTEGER_CST)
+                 && (TREE_CODE (vr_value[ver]->max) == INTEGER_CST))
+               set_range_info (def, vr_value[ver]->type, vr_value[ver]->min,
+                               vr_value[ver]->max);
+           }

Otherwise the patch looks good now (with a lot of improvement
possibilities of course).

Thanks and sorry for the delay,
Richard.

> Thanks,
> Kugan
>
>
>> Thanks,
>> Richard.
>>
>>> I also noticed that g++.dg/warn/pr33738.C testcase is now failing. This is
>>> because, with early-vrp setting value range ccp2 is optimizing without
>>> issuing a warning. I will look into it.
>>>
>>> bootstrap and regression testing is in progress.
>>>
>>> Thanks,
>>> Kugan

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Early VRP Implementation
  2016-09-14 12:11                                   ` Richard Biener
@ 2016-09-14 21:47                                     ` Jan Hubicka
  2016-09-15  7:23                                       ` Richard Biener
  2016-09-16  6:37                                     ` kugan
  1 sibling, 1 reply; 67+ messages in thread
From: Jan Hubicka @ 2016-09-14 21:47 UTC (permalink / raw)
  To: Richard Biener
  Cc: Kugan Vivekanandarajah, Andrew Pinski, gcc-patches, Jan Hubicka,
	Martin Jambor

> +  /* Visit PHI stmts and discover any new VRs possible.  */
> +  gimple_stmt_iterator gsi;
> +  for (gphi_iterator gpi = gsi_start_phis (bb);
> +       !gsi_end_p (gpi); gsi_next (&gpi))
> +    {
> +      gphi *phi = gpi.phi ();
> +      tree lhs = PHI_RESULT (phi);
> +      value_range vr_result = VR_INITIALIZER;
> +      if (! has_unvisived_preds
>            && stmt_interesting_for_vrp (phi)
> +         && stmt_visit_phi_node_in_dom_p (phi))
> +       extract_range_from_phi_node (phi, &vr_result, true);
> +      else
> +       set_value_range_to_varying (&vr_result);
> +      update_value_range (lhs, &vr_result);
> +    }
> 
> due to a bug in IRA you need to make sure to un-set BB_VISITED after
> early-vrp is finished again.
How IRA bugs affects early passes?

Honza

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Early VRP Implementation
  2016-09-14 21:47                                     ` Jan Hubicka
@ 2016-09-15  7:23                                       ` Richard Biener
  2016-09-15 14:57                                         ` Jeff Law
  0 siblings, 1 reply; 67+ messages in thread
From: Richard Biener @ 2016-09-15  7:23 UTC (permalink / raw)
  To: Jan Hubicka
  Cc: Kugan Vivekanandarajah, Andrew Pinski, gcc-patches, Martin Jambor

On September 14, 2016 11:36:16 PM GMT+02:00, Jan Hubicka <hubicka@ucw.cz> wrote:
>> +  /* Visit PHI stmts and discover any new VRs possible.  */
>> +  gimple_stmt_iterator gsi;
>> +  for (gphi_iterator gpi = gsi_start_phis (bb);
>> +       !gsi_end_p (gpi); gsi_next (&gpi))
>> +    {
>> +      gphi *phi = gpi.phi ();
>> +      tree lhs = PHI_RESULT (phi);
>> +      value_range vr_result = VR_INITIALIZER;
>> +      if (! has_unvisived_preds
>>            && stmt_interesting_for_vrp (phi)
>> +         && stmt_visit_phi_node_in_dom_p (phi))
>> +       extract_range_from_phi_node (phi, &vr_result, true);
>> +      else
>> +       set_value_range_to_varying (&vr_result);
>> +      update_value_range (lhs, &vr_result);
>> +    }
>> 
>> due to a bug in IRA you need to make sure to un-set BB_VISITED after
>> early-vrp is finished again.
>How IRA bugs affects early passes?

IRA bogously relies on BB_VISITED being cleared at pass start.

Richard.

>Honza


^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Early VRP Implementation
  2016-09-15  7:23                                       ` Richard Biener
@ 2016-09-15 14:57                                         ` Jeff Law
  2016-09-16  8:59                                           ` Richard Biener
  0 siblings, 1 reply; 67+ messages in thread
From: Jeff Law @ 2016-09-15 14:57 UTC (permalink / raw)
  To: Richard Biener, Jan Hubicka
  Cc: Kugan Vivekanandarajah, Andrew Pinski, gcc-patches, Martin Jambor

On 09/14/2016 11:55 PM, Richard Biener wrote:
> On September 14, 2016 11:36:16 PM GMT+02:00, Jan Hubicka <hubicka@ucw.cz> wrote:
>>> +  /* Visit PHI stmts and discover any new VRs possible.  */
>>> +  gimple_stmt_iterator gsi;
>>> +  for (gphi_iterator gpi = gsi_start_phis (bb);
>>> +       !gsi_end_p (gpi); gsi_next (&gpi))
>>> +    {
>>> +      gphi *phi = gpi.phi ();
>>> +      tree lhs = PHI_RESULT (phi);
>>> +      value_range vr_result = VR_INITIALIZER;
>>> +      if (! has_unvisived_preds
>>>            && stmt_interesting_for_vrp (phi)
>>> +         && stmt_visit_phi_node_in_dom_p (phi))
>>> +       extract_range_from_phi_node (phi, &vr_result, true);
>>> +      else
>>> +       set_value_range_to_varying (&vr_result);
>>> +      update_value_range (lhs, &vr_result);
>>> +    }
>>>
>>> due to a bug in IRA you need to make sure to un-set BB_VISITED after
>>> early-vrp is finished again.
>> How IRA bugs affects early passes?
>
> IRA bogously relies on BB_VISITED being cleared at pass start.
Seems like IRA ought to be fixed to clear BB_VISITED on every block as 
part of its initialization.

Jeff

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Early VRP Implementation
  2016-09-14 12:11                                   ` Richard Biener
  2016-09-14 21:47                                     ` Jan Hubicka
@ 2016-09-16  6:37                                     ` kugan
  2016-09-16 10:26                                       ` Richard Biener
  1 sibling, 1 reply; 67+ messages in thread
From: kugan @ 2016-09-16  6:37 UTC (permalink / raw)
  To: Richard Biener; +Cc: Andrew Pinski, gcc-patches, Jan Hubicka, Martin Jambor

[-- Attachment #1: Type: text/plain, Size: 7503 bytes --]

Hi Richard,

Thanks for the review.

On 14/09/16 22:04, Richard Biener wrote:
> On Tue, Aug 23, 2016 at 4:11 AM, Kugan Vivekanandarajah
> <kugan.vivekanandarajah@linaro.org> wrote:
>> Hi,
>>
>> On 19 August 2016 at 21:41, Richard Biener <richard.guenther@gmail.com> wrote:
>>> On Tue, Aug 16, 2016 at 9:45 AM, kugan
>>> <kugan.vivekanandarajah@linaro.org> wrote:
>>>> Hi Richard,

>>>> I am now having -ftree-evrp which is enabled all the time. But This will
>>>> only be used for disabling the early-vrp. That is, early-vrp will be run
>>>> when ftree-vrp is enabled and ftree-evrp is not explicitly disabled. Is this
>>>> OK?
>>>
>>> Why would one want to disable early-vrp?  I see you do this in the testsuite
>>> for non-early VRP unit-tests but using -fdisable-tree-evrp1 there
>>> would be ok as well.
>>
>> Removed it altogether. I though that you wanted a way to disable
>> early-vrp for testing purposes.
>
> But there is via the generic -fdisable-tree-DUMPFILE way.

OK. I didnt know about that.


>>> Note that you want to have a custom valueize function instead of just
>>> follow_single_use_edges as you want to valueize all SSA names according
>>> to their lattice value (if it has a single value).  You can use vrp_valueize
>>> for this though that gets you non-single-use edge following as well.
>>> Eventually it's going to be cleaner to do what the SSA propagator does and
>>> before folding do
>>>
>>>    did_replace = replace_uses_in (stmt, vrp_valueize);
>>>    if (fold_stmt (&gsi, follow_single_use_edges)
>>>        || did_replace)
>>>      update_stmt (gsi_stmt (gsi));
>>>
>>> exporting replace_uses_in for this is ok.  I guess I prefer this for now.
>>
>> I also added the above.  I noticed that I need
>> recompute_tree_invariant_for_addr_expr as in ssa_propagate. My initial
>> implementation also had gimple_purge_all_dead_eh_edges and
>> fixup_noreturn_call as in ssa_propagat but I thinj that is not needed
>> as it would be done at the end of the pass.
>
> I don't see this being done at the end of the pass.  So please re-instantiate
> that parts.

I have copied these part as well.

>> With this I noticed more stmts are folded before vrp1. This required
>> me to adjust some testcases.
>>
>>>
>>> Overall this now looks good apart from the folding and the VR_INITIALIZER thing.
>>>
>>> You can commit the already approved refactoring changes and combine this
>>> patch with the struct value_range move, this way I can more easily look into
>>> issues with the UNDEFINED thing if you can come up with a testcase that
>>> doesn't work.
>>>
>>
>> I have now committed all the dependent patches.
>>
>> Attached patch passes regression and bootstrap except pr33738.C. This
>> is an unrelated issue as discussed in
>> https://gcc.gnu.org/ml/gcc-patches/2016-08/msg01386.html
>>
>> Is this OK?
>
> +/* Initialize local data structures for VRP.  If DOM_P is true,
> +   we will be calling this from early_vrp where value range propagation
> +   is done by visiting stmts in dominator tree.  ssa_propagate engine
> +   is not used in this case and that part of the ininitialization will
> +   be skipped.  */
> +
> +static void
> +vrp_initialize ()
>
> comment needs updating now.
>
Done.

>
>  static void
> -extract_range_from_phi_node (gphi *phi, value_range *vr_result)
> +extract_range_from_phi_node (gphi *phi, value_range *vr_result,
> +                            bool early_vrp_p)
>  {
>
>
> I don't think you need this changes now that you have
> stmt_visit_phi_node_in_dom_p
> guarding its call.

OK removed it. That also mean I had to put scev_* in the early_vrp.


> +static bool
> +stmt_visit_phi_node_in_dom_p (gphi *phi)
> +{
> +  ssa_op_iter iter;
> +  use_operand_p oprnd;
> +  tree op;
> +  value_range *vr;
> +  FOR_EACH_PHI_ARG (oprnd, phi, iter, SSA_OP_USE)
> +    {
> +      op = USE_FROM_PTR (oprnd);
> +      if (TREE_CODE (op) == SSA_NAME)
> +       {
> +         vr = get_value_range (op);
> +         if (vr->type == VR_UNDEFINED)
> +           return false;
> +       }
> +    }
>
> I think this is overly conservative in never allowing UNDEFINED on PHI
> node args (even if the def was actually visited).  I think that the most
> easy way to improve this bit would be to actually track visited blocks.
> You already set the EDGE_EXECUTABLE flag on edges so you could
> clear BB_VISITED on all blocks and set it in the before_dom_children
> hook (at the end).  Then the above can be folded into the PHI visiting:
>
>     bool has_unvisited_pred = false;
>     FOR_EACH_EDGE (e, ei, bb->preds)
>        if (!(e->src->flags & BB_VISITED))
>          {
>             has_unvisited_preds = true;
>             break;
>          }
>
OK done.

I also had to check for uninitialized variables that will have 
VR_UNDEFINED as range. We do not visit GIMPLE_NOP.


> +  /* Visit PHI stmts and discover any new VRs possible.  */
> +  gimple_stmt_iterator gsi;
> +  for (gphi_iterator gpi = gsi_start_phis (bb);
> +       !gsi_end_p (gpi); gsi_next (&gpi))
> +    {
> +      gphi *phi = gpi.phi ();
> +      tree lhs = PHI_RESULT (phi);
> +      value_range vr_result = VR_INITIALIZER;
> +      if (! has_unvisived_preds
>            && stmt_interesting_for_vrp (phi)
> +         && stmt_visit_phi_node_in_dom_p (phi))
> +       extract_range_from_phi_node (phi, &vr_result, true);
> +      else
> +       set_value_range_to_varying (&vr_result);
> +      update_value_range (lhs, &vr_result);
> +    }
>
> due to a bug in IRA you need to make sure to un-set BB_VISITED after
> early-vrp is finished again.
OK. Done.

>
> +         /* Try folding stmts with the VR discovered.  */
> +         bool did_replace = replace_uses_in (stmt, evrp_valueize);
> +         if (fold_stmt (&gsi, follow_single_use_edges)
> +             || did_replace)
> +           update_stmt (gsi_stmt (gsi));
>
> you should be able to re-use vrp_valueize here.
This issue is vrp_valueize accepts ranges such as [VAR + CST, VAR + CST] 
which we can not set.

>
> +         def_operand_p def_p = SINGLE_SSA_DEF_OPERAND (stmt, SSA_OP_DEF);
> +         /* Set the SSA with the value range.  */
> +         if (def_p
> +             && TREE_CODE (DEF_FROM_PTR (def_p)) == SSA_NAME
> +             && INTEGRAL_TYPE_P (TREE_TYPE (DEF_FROM_PTR (def_p))))
> +           {
> +             tree def = DEF_FROM_PTR (def_p);
> +             unsigned ver = SSA_NAME_VERSION (def);
> +             if ((vr_value[ver]->type == VR_RANGE
>
> Use get_value_range () please, not direct access to vr_value.
>
Done.

> +                  || vr_value[ver]->type == VR_ANTI_RANGE)
> +                 && (TREE_CODE (vr_value[ver]->min) == INTEGER_CST)
> +                 && (TREE_CODE (vr_value[ver]->max) == INTEGER_CST))
> +               set_range_info (def, vr_value[ver]->type, vr_value[ver]->min,
> +                               vr_value[ver]->max);
> +           }
>
> Otherwise the patch looks good now (with a lot of improvement
> possibilities of course).
I will work on the improvement after this goes in.

Bootstrapped and regression tested on x86_64-linux-gnu. Does this looks OK?

Thanks,
Kugan


>
> Thanks and sorry for the delay,
> Richard.
>
>> Thanks,
>> Kugan
>>
>>
>>> Thanks,
>>> Richard.
>>>
>>>> I also noticed that g++.dg/warn/pr33738.C testcase is now failing. This is
>>>> because, with early-vrp setting value range ccp2 is optimizing without
>>>> issuing a warning. I will look into it.
>>>>
>>>> bootstrap and regression testing is in progress.
>>>>
>>>> Thanks,
>>>> Kugan

[-- Attachment #2: 0001-Add-early-vrp.patch --]
[-- Type: text/x-patch, Size: 31632 bytes --]

From 928718fd1e99384774a762a9ee8617d40b9e6a56 Mon Sep 17 00:00:00 2001
From: Kugan Vivekanandarajah <kugan.vivekanandarajah@linaro.org>
Date: Tue, 23 Aug 2016 16:18:30 +1000
Subject: [PATCH 1/3] Add early-vrp

---
 gcc/doc/invoke.texi                       |   5 +
 gcc/passes.def                            |   1 +
 gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C |   2 +-
 gcc/testsuite/gcc.dg/tree-ssa/evrp1.c     |  13 +
 gcc/testsuite/gcc.dg/tree-ssa/evrp2.c     |  18 ++
 gcc/testsuite/gcc.dg/tree-ssa/evrp3.c     |  15 +
 gcc/testsuite/gcc.dg/tree-ssa/pr20657.c   |   4 +-
 gcc/testsuite/gcc.dg/tree-ssa/pr22117.c   |   4 +-
 gcc/testsuite/gcc.dg/tree-ssa/pr25382.c   |   2 +-
 gcc/testsuite/gcc.dg/tree-ssa/pr37508.c   |   2 +-
 gcc/testsuite/gcc.dg/tree-ssa/pr61839_2.c |   8 +-
 gcc/testsuite/gcc.dg/tree-ssa/pr64130.c   |   6 +-
 gcc/testsuite/gcc.dg/tree-ssa/vrp04.c     |   2 +-
 gcc/testsuite/gcc.dg/tree-ssa/vrp06.c     |   4 +-
 gcc/testsuite/gcc.dg/tree-ssa/vrp16.c     |   4 +-
 gcc/testsuite/gcc.dg/tree-ssa/vrp25.c     |   4 +-
 gcc/testsuite/gcc.dg/tree-ssa/vrp46.c     |   3 +-
 gcc/testsuite/gcc.dg/tree-ssa/vrp67.c     |   2 +-
 gcc/timevar.def                           |   1 +
 gcc/tree-pass.h                           |   1 +
 gcc/tree-ssa-propagate.c                  |   2 +-
 gcc/tree-ssa-propagate.h                  |   1 +
 gcc/tree-vrp.c                            | 496 ++++++++++++++++++++++++++----
 23 files changed, 522 insertions(+), 78 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/evrp1.c
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/evrp2.c
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/evrp3.c

diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 87da1f1..9ed9c24 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -12454,6 +12454,11 @@ is made by appending @file{.slp} to the source file name.
 Dump each function after Value Range Propagation (VRP).  The file name
 is made by appending @file{.vrp} to the source file name.
 
+@item early vrp
+@opindex fdump-tree-evrp
+Dump each function after Early Value Range Propagation (EVRP).  The file name
+is made by appending @file{.evrp} to the source file name.
+
 @item oaccdevlow
 @opindex fdump-tree-oaccdevlow
 Dump each function after applying device-specific OpenACC transformations.
diff --git a/gcc/passes.def b/gcc/passes.def
index 533157d..9759fed 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -89,6 +89,7 @@ along with GCC; see the file COPYING3.  If not see
 	     execute TODO_rebuild_alias at this point.  */
 	  NEXT_PASS (pass_build_ealias);
 	  NEXT_PASS (pass_fre);
+	  NEXT_PASS (pass_early_vrp);
 	  NEXT_PASS (pass_merge_phi);
           NEXT_PASS (pass_dse);
 	  NEXT_PASS (pass_cd_dce);
diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C b/gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C
index 5e09583..cf4ed33 100644
--- a/gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C
+++ b/gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O -fdump-tree-forwprop1" } */
+/* { dg-options "-O -fno-tree-vrp -fdump-tree-forwprop1" } */
 
 #include <new>
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/evrp1.c b/gcc/testsuite/gcc.dg/tree-ssa/evrp1.c
new file mode 100644
index 0000000..8c6e4e6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/evrp1.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+int foo (int i);
+int bar (int j)
+{
+  if (j > 2)
+    return foo (j + 2);
+  else
+    return j;
+}
+
+/* { dg-final { scan-tree-dump "\\\[5, \\+INF" "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/evrp2.c b/gcc/testsuite/gcc.dg/tree-ssa/evrp2.c
new file mode 100644
index 0000000..e6d4235
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/evrp2.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+int foo (int i);
+int bar2 (int j)
+{
+  if (j > 2)
+    {
+      if (j < 7)
+	return foo (j + 1);
+      else
+	return foo (j + 2);
+    }
+  return j;
+}
+
+
+/* { dg-final { scan-tree-dump "\\\[4, 7\\\]" "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/evrp3.c b/gcc/testsuite/gcc.dg/tree-ssa/evrp3.c
new file mode 100644
index 0000000..1a3bbd5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/evrp3.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+int foo (int i);
+void bar (int j)
+{
+  unsigned int i;
+  for (i = 0; i < 10; ++i)
+    {
+      bar (i + 1);
+    }
+}
+
+/* { dg-final { scan-tree-dump "\\\[1, 10\\\]" "evrp" } } */
+
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr20657.c b/gcc/testsuite/gcc.dg/tree-ssa/pr20657.c
index 727ca4c..e678231 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr20657.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr20657.c
@@ -3,7 +3,7 @@
    statement, which was needed to eliminate the second "if" statement.  */
 
 /* { dg-do compile } */
-/* { dg-options "-O2 -fno-tree-dominator-opts -fno-tree-fre -fdump-tree-vrp1-details" } */
+/* { dg-options "-O2 -fno-tree-dominator-opts -fno-tree-fre -fdump-tree-evrp" } */
 
 int
 foo (int a)
@@ -14,4 +14,4 @@ foo (int a)
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "Folding predicate" 1 "vrp1"} } */
+/* { dg-final { scan-tree-dump-times "if" 1 "evrp"} } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c b/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c
index 7efdd63..3a433d6 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c
@@ -3,7 +3,7 @@
    known to be zero after entering the first two "if" statements.  */
 
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1" } */
+/* { dg-options "-O2  -fdump-tree-vrp1" } */
 
 void link_error (void);
 
@@ -21,4 +21,4 @@ foo (int *p, int q)
     }
 }
 
-/* { dg-final { scan-tree-dump-times "Folding predicate r_.* != 0B to 0" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "link_error" 0 "vrp1" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c b/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c
index dcf9148..c4fda8b 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c
@@ -3,7 +3,7 @@
    Check that VRP now gets ranges from BIT_AND_EXPRs.  */
 
 /* { dg-do compile } */
-/* { dg-options "-O2 -fno-tree-ccp -fdump-tree-vrp1" } */
+/* { dg-options "-O2 -fno-tree-ccp -fdump-tree-vrp" } */
 
 int
 foo (int a)
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr37508.c b/gcc/testsuite/gcc.dg/tree-ssa/pr37508.c
index 0963cd9..2ba09af 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr37508.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr37508.c
@@ -46,4 +46,4 @@ int test4 (struct foo2 *x)
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "Folding" 2 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "if" 2 "vrp1" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr61839_2.c b/gcc/testsuite/gcc.dg/tree-ssa/pr61839_2.c
index ffa00a7..e44dc57 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr61839_2.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr61839_2.c
@@ -1,6 +1,6 @@
 /* PR tree-optimization/61839.  */
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1" } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
 /* { dg-require-effective-target int32plus } */
 
 __attribute__ ((noinline))
@@ -47,8 +47,8 @@ int bar2 ()
 
 
 /* Dont optimize 972195717 / 0 in function foo.  */
-/* { dg-final { scan-tree-dump-times "972195717 / _" 1  "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "972195717 / _" 1  "evrp" } } */
 /* Dont optimize 972195717 % 0 in function bar.  */
-/* { dg-final { scan-tree-dump-times "972195717 % _" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "972195717 % _" 1 "evrp" } } */
 /* Optimize in function bar2.  */
-/* { dg-final { scan-tree-dump-times "972195715 % _" 0 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "972195715 % _" 0 "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr64130.c b/gcc/testsuite/gcc.dg/tree-ssa/pr64130.c
index 0b25466..f39bd17 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr64130.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr64130.c
@@ -1,6 +1,6 @@
 
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1" } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
 
 int funsigned (unsigned a)
 {
@@ -13,6 +13,6 @@ int funsigned2 (unsigned a)
   return (-1 * 0x1ffffffffL) / a == 0;
 }
 
-/* { dg-final { scan-tree-dump ": \\\[2, 8589934591\\\]" "vrp1" } } */
-/* { dg-final { scan-tree-dump ": \\\[-8589934591, -2\\\]" "vrp1" } } */
+/* { dg-final { scan-tree-dump ": \\\[2, 8589934591\\\]" "evrp" } } */
+/* { dg-final { scan-tree-dump ": \\\[-8589934591, -2\\\]" "evrp" } } */
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp04.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp04.c
index 61b7a47..67f8f01 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp04.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp04.c
@@ -10,4 +10,4 @@ foo (int a, int b)
       return a + b;
 }
 
-/* { dg-final { scan-tree-dump-times "Folding predicate a_.*to 1" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "if" 1 "vrp1" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp06.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp06.c
index cdad534..c4ce170 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp06.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp06.c
@@ -28,6 +28,6 @@ foo (int i, int j, int a)
   return i + a + j;
 }
 
-/* { dg-final { scan-tree-dump-times "Folding predicate i_\[0-9\]+.*0 to 0" 1 "vrp1" } } */
-/* { dg-final { scan-tree-dump-times "Folding predicate j_\[0-9\]+.*0 to 1" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "Folding predicate \[i|j\]_\[0-9\]+.*0 to 0" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "Folding predicate \[i|j\]_\[0-9\]+.*0 to 1" 1 "vrp1" } } */
 /* { dg-final { scan-tree-dump-times "Folding predicate i_\[0-9]+.*j_\[0-9\]+.* to 0" 1 "vrp1" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp16.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp16.c
index 8f5d5c8..d09f3ae 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp16.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp16.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fno-tree-fre -fdump-tree-vrp1-details" } */
+/* { dg-options "-O2 -fno-tree-fre -fdump-tree-evrp" } */
 
 
 extern void abort (void) __attribute__ ((__noreturn__));
@@ -19,5 +19,5 @@ nonlocal_mentioned_p (rtx x)
 	abort ();
 }
 
-/* { dg-final { scan-tree-dump-times "Folding predicate .*to 0" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "if" 0 "evrp" } } */
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp25.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp25.c
index cbc4ec3..a49f079 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp25.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp25.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fno-tree-fre -fdump-tree-vrp1-details" } */
+/* { dg-options "-O2 -fno-tree-fre -fdump-tree-vrp1" } */
 
 extern void abort ();
 extern void arf ();
@@ -49,5 +49,5 @@ L9:
 /* The second test of (code1 != 53) and the test (D18670 <= 2) are
    both totally subsumed by earlier tests and thus should be folded
    away using VRP.  */
-/* { dg-final { scan-tree-dump-times "Folding predicate" 2 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "if" 3 "vrp1" } } */
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp46.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp46.c
index d3c9ed1..5b279a1 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp46.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp46.c
@@ -27,6 +27,5 @@ func_18 ( int t )
     }
 }
 
-/* There should be a single if left.  */
 
-/* { dg-final { scan-tree-dump-times "if" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "if" 0 "vrp1" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp67.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp67.c
index ef5e8f9..5155f7b 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp67.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp67.c
@@ -36,4 +36,4 @@ unsigned baz (unsigned i)
   return i;
 }
 
-/* { dg-final { scan-tree-dump-times "Folding predicate" 3 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "if" 3 "vrp1" } } */
diff --git a/gcc/timevar.def b/gcc/timevar.def
index 5f12118..8837832 100644
--- a/gcc/timevar.def
+++ b/gcc/timevar.def
@@ -149,6 +149,7 @@ DEFTIMEVAR (TV_TREE_CFG		     , "tree CFG construction")
 DEFTIMEVAR (TV_TREE_CLEANUP_CFG	     , "tree CFG cleanup")
 DEFTIMEVAR (TV_TREE_TAIL_MERGE       , "tree tail merge")
 DEFTIMEVAR (TV_TREE_VRP              , "tree VRP")
+DEFTIMEVAR (TV_TREE_EARLY_VRP        , "tree Early VRP")
 DEFTIMEVAR (TV_TREE_COPY_PROP        , "tree copy propagation")
 DEFTIMEVAR (TV_FIND_REFERENCED_VARS  , "tree find ref. vars")
 DEFTIMEVAR (TV_TREE_PTA		     , "tree PTA")
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index c0059de..86d797e 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -440,6 +440,7 @@ extern gimple_opt_pass *make_pass_fre (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_check_data_deps (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_copy_prop (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_isolate_erroneous_paths (gcc::context *ctxt);
+extern gimple_opt_pass *make_pass_early_vrp (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_vrp (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_uncprop (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_return_slot (gcc::context *ctxt);
diff --git a/gcc/tree-ssa-propagate.c b/gcc/tree-ssa-propagate.c
index c8cf078..97cfde5 100644
--- a/gcc/tree-ssa-propagate.c
+++ b/gcc/tree-ssa-propagate.c
@@ -863,7 +863,7 @@ static struct prop_stats_d prop_stats;
 /* Replace USE references in statement STMT with the values stored in
    PROP_VALUE. Return true if at least one reference was replaced.  */
 
-static bool
+bool
 replace_uses_in (gimple *stmt, ssa_prop_get_value_fn get_value)
 {
   bool replaced = false;
diff --git a/gcc/tree-ssa-propagate.h b/gcc/tree-ssa-propagate.h
index 30d66a9..1a96976 100644
--- a/gcc/tree-ssa-propagate.h
+++ b/gcc/tree-ssa-propagate.h
@@ -84,5 +84,6 @@ extern void propagate_value (use_operand_p, tree);
 extern void replace_exp (use_operand_p, tree);
 extern void propagate_tree_value (tree *, tree);
 extern void propagate_tree_value_into_stmt (gimple_stmt_iterator *, tree);
+extern bool replace_uses_in (gimple *stmt, ssa_prop_get_value_fn get_value);
 
 #endif /* _TREE_SSA_PROPAGATE_H  */
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index 45882c4..ada66ed 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -60,6 +60,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "case-cfn-macros.h"
 #include "params.h"
 #include "alloc-pool.h"
+#include "domwalk.h"
+#include "tree-cfgcleanup.h"
 
 #define VR_INITIALIZER { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL }
 
@@ -1455,44 +1457,17 @@ op_with_boolean_value_range_p (tree op)
 	  && integer_onep (vr->max));
 }
 
-/* Extract value range information from an ASSERT_EXPR EXPR and store
-   it in *VR_P.  */
+/* Extract value range information for VAR when (OP COND_CODE LIMIT) is
+   true and store it in *VR_P.  */
 
 static void
-extract_range_from_assert (value_range *vr_p, tree expr)
+extract_range_for_var_from_comparison_expr (tree var, enum tree_code cond_code,
+					    tree op, tree limit,
+					    value_range *vr_p)
 {
-  tree var, cond, limit, min, max, type;
+  tree  min, max, type;
   value_range *limit_vr;
-  enum tree_code cond_code;
-
-  var = ASSERT_EXPR_VAR (expr);
-  cond = ASSERT_EXPR_COND (expr);
-
-  gcc_assert (COMPARISON_CLASS_P (cond));
-
-  /* Find VAR in the ASSERT_EXPR conditional.  */
-  if (var == TREE_OPERAND (cond, 0)
-      || TREE_CODE (TREE_OPERAND (cond, 0)) == PLUS_EXPR
-      || TREE_CODE (TREE_OPERAND (cond, 0)) == NOP_EXPR)
-    {
-      /* If the predicate is of the form VAR COMP LIMIT, then we just
-	 take LIMIT from the RHS and use the same comparison code.  */
-      cond_code = TREE_CODE (cond);
-      limit = TREE_OPERAND (cond, 1);
-      cond = TREE_OPERAND (cond, 0);
-    }
-  else
-    {
-      /* If the predicate is of the form LIMIT COMP VAR, then we need
-	 to flip around the comparison code to create the proper range
-	 for VAR.  */
-      cond_code = swap_tree_comparison (TREE_CODE (cond));
-      limit = TREE_OPERAND (cond, 0);
-      cond = TREE_OPERAND (cond, 1);
-    }
-
   limit = avoid_overflow_infinity (limit);
-
   type = TREE_TYPE (var);
   gcc_assert (limit != var);
 
@@ -1538,15 +1513,15 @@ extract_range_from_assert (value_range *vr_p, tree expr)
      as well build the range [b_4, +INF] for it.
      One special case we handle is extracting a range from a
      range test encoded as (unsigned)var + CST <= limit.  */
-  if (TREE_CODE (cond) == NOP_EXPR
-      || TREE_CODE (cond) == PLUS_EXPR)
+  if (TREE_CODE (op) == NOP_EXPR
+      || TREE_CODE (op) == PLUS_EXPR)
     {
-      if (TREE_CODE (cond) == PLUS_EXPR)
+      if (TREE_CODE (op) == PLUS_EXPR)
         {
-          min = fold_build1 (NEGATE_EXPR, TREE_TYPE (TREE_OPERAND (cond, 1)),
-			     TREE_OPERAND (cond, 1));
+	  min = fold_build1 (NEGATE_EXPR, TREE_TYPE (TREE_OPERAND (op, 1)),
+			     TREE_OPERAND (op, 1));
           max = int_const_binop (PLUS_EXPR, limit, min);
-	  cond = TREE_OPERAND (cond, 0);
+	  op = TREE_OPERAND (op, 0);
 	}
       else
 	{
@@ -1730,6 +1705,41 @@ extract_range_from_assert (value_range *vr_p, tree expr)
   vrp_intersect_ranges (vr_p, get_value_range (var));
 }
 
+/* Extract value range information from an ASSERT_EXPR EXPR and store
+   it in *VR_P.  */
+
+static void
+extract_range_from_assert (value_range *vr_p, tree expr)
+{
+  tree var = ASSERT_EXPR_VAR (expr);
+  tree cond = ASSERT_EXPR_COND (expr);
+  tree limit, op;
+  enum tree_code cond_code;
+  gcc_assert (COMPARISON_CLASS_P (cond));
+
+  /* Find VAR in the ASSERT_EXPR conditional.  */
+  if (var == TREE_OPERAND (cond, 0)
+      || TREE_CODE (TREE_OPERAND (cond, 0)) == PLUS_EXPR
+      || TREE_CODE (TREE_OPERAND (cond, 0)) == NOP_EXPR)
+    {
+      /* If the predicate is of the form VAR COMP LIMIT, then we just
+	 take LIMIT from the RHS and use the same comparison code.  */
+      cond_code = TREE_CODE (cond);
+      limit = TREE_OPERAND (cond, 1);
+      op = TREE_OPERAND (cond, 0);
+    }
+  else
+    {
+      /* If the predicate is of the form LIMIT COMP VAR, then we need
+	 to flip around the comparison code to create the proper range
+	 for VAR.  */
+      cond_code = swap_tree_comparison (TREE_CODE (cond));
+      limit = TREE_OPERAND (cond, 0);
+      op = TREE_OPERAND (cond, 1);
+    }
+  extract_range_for_var_from_comparison_expr (var, cond_code, op,
+					      limit, vr_p);
+}
 
 /* Extract range information from SSA name VAR and store it in VR.  If
    VAR has an interesting range, use it.  Otherwise, create the
@@ -6947,19 +6957,24 @@ stmt_interesting_for_vrp (gimple *stmt)
   return false;
 }
 
-
-/* Initialize local data structures for VRP.  */
+/* Initialize VRP lattice.  */
 
 static void
-vrp_initialize (void)
+vrp_initialize_lattice ()
 {
-  basic_block bb;
-
   values_propagated = false;
   num_vr_values = num_ssa_names;
   vr_value = XCNEWVEC (value_range *, num_vr_values);
   vr_phi_edge_counts = XCNEWVEC (int, num_ssa_names);
   bitmap_obstack_initialize (&vrp_equiv_obstack);
+}
+
+/* Initialization required by ssa_propagate engine.  */
+
+static void
+vrp_initialize ()
+{
+  basic_block bb;
 
   FOR_EACH_BB_FN (bb, cfun)
     {
@@ -10500,6 +10515,22 @@ finalize_jump_threads (void)
   delete equiv_stack;
 }
 
+/* Free VRP lattice.  */
+
+static void
+vrp_free_lattice ()
+{
+  /* Free allocated memory.  */
+  free (vr_value);
+  free (vr_phi_edge_counts);
+  bitmap_obstack_release (&vrp_equiv_obstack);
+  vrp_value_range_pool.release ();
+
+  /* So that we can distinguish between VRP data being available
+     and not available.  */
+  vr_value = NULL;
+  vr_phi_edge_counts = NULL;
+}
 
 /* Traverse all the blocks folding conditionals with known ranges.  */
 
@@ -10546,17 +10577,333 @@ vrp_finalize (bool warn_array_bounds_p)
   /* We must identify jump threading opportunities before we release
      the datastructures built by VRP.  */
   identify_jump_threads ();
+}
 
-  /* Free allocated memory.  */
-  free (vr_value);
-  free (vr_phi_edge_counts);
-  bitmap_obstack_release (&vrp_equiv_obstack);
-  vrp_value_range_pool.release ();
+/* Check to see if the PHI stmt has any edges that has operand
+   which is not visited yet.  */
 
-  /* So that we can distinguish between VRP data being available
-     and not available.  */
-  vr_value = NULL;
-  vr_phi_edge_counts = NULL;
+static bool
+stmt_visit_phi_node_in_dom_p (gphi *phi)
+{
+  basic_block bb = gimple_bb (phi);
+  edge e;
+  edge_iterator ei;
+
+  FOR_EACH_EDGE (e, ei, bb->preds)
+    if (!(e->src->flags & BB_VISITED))
+      return false;
+    else
+      {
+	tree op = gimple_phi_arg_def (phi, e->dest_idx);
+	value_range *vr;
+
+	/* If uninitialized variable which is VR_UNDEFINED.  */
+	if (TREE_CODE (op) == SSA_NAME
+	    && (gimple_code (SSA_NAME_DEF_STMT (op)) == GIMPLE_NOP)
+	    && (vr = get_value_range (op))
+	    && (vr->type == VR_UNDEFINED))
+	  return false;
+      }
+  return true;
+}
+
+/* evrp_dom_walker visits the basic blocks in the dominance order and set
+   the Value Ranges (VR) for SSA_NAMEs in the scope.  Use this VR to
+   discover more VRs.  */
+
+class evrp_dom_walker : public dom_walker
+{
+public:
+  evrp_dom_walker ()
+    : dom_walker (CDI_DOMINATORS), stack (10)
+    {
+      stmts_to_fixup.create (0);
+      need_eh_cleanup = BITMAP_ALLOC (NULL);
+    }
+  ~evrp_dom_walker ()
+    {
+      stmts_to_fixup.release ();
+      BITMAP_FREE (need_eh_cleanup);
+    }
+  virtual edge before_dom_children (basic_block);
+  virtual void after_dom_children (basic_block);
+  void push_value_range (const_tree var, value_range *vr);
+  value_range *pop_value_range (const_tree var);
+
+  /* Cond_stack holds the old VR.  */
+  auto_vec<std::pair <const_tree, value_range*> > stack;
+  bitmap need_eh_cleanup;
+  vec<gimple *> stmts_to_fixup;
+};
+
+/* Return the singleton value-range for NAME or NAME.  */
+
+static inline tree
+evrp_valueize (tree name)
+{
+  if (TREE_CODE (name) == SSA_NAME)
+    {
+      value_range *vr = get_value_range (name);
+      if (vr->type == VR_RANGE
+	  && (range_int_cst_p (vr)
+	      || (TREE_CODE (vr->min) == SSA_NAME))
+	  && vrp_operand_equal_p (vr->min, vr->max))
+	return vr->min;
+    }
+  return name;
+}
+
+/* See if there is any new scope is entered with new VR and set that VR to
+   ssa_name before visiting the statements in the scope.  */
+
+edge
+evrp_dom_walker::before_dom_children (basic_block bb)
+{
+  value_range *new_vr = NULL;
+  tree op0 = NULL_TREE;
+
+  push_value_range (NULL_TREE, NULL);
+  if (single_pred_p (bb))
+    {
+      edge e = single_pred_edge (bb);
+      value_range vr = VR_INITIALIZER;
+      gimple *stmt = last_stmt (e->src);
+      if (stmt
+	  && gimple_code (stmt) == GIMPLE_COND
+	  && (op0 = gimple_cond_lhs (stmt))
+	  && TREE_CODE (op0) == SSA_NAME
+	  && INTEGRAL_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt))))
+	{
+	  /* Entering a new scope.  Try to see if we can find a VR
+	     here.  */
+	  tree op1 = gimple_cond_rhs (stmt);
+	  tree_code code = gimple_cond_code (stmt);
+	  value_range *old_vr = get_value_range (op0);
+
+	  if (TREE_OVERFLOW_P (op1))
+	    op1 = drop_tree_overflow (op1);
+
+	  /* If condition is false, invert the cond.  */
+	  if (e->flags & EDGE_FALSE_VALUE)
+	    code = invert_tree_comparison (gimple_cond_code (stmt),
+					   HONOR_NANS (op0));
+	  /* Discover VR when condition is true.  */
+	  extract_range_for_var_from_comparison_expr (op0, code, op0, op1, &vr);
+	  if (old_vr->type == VR_RANGE || old_vr->type == VR_ANTI_RANGE)
+	    vrp_intersect_ranges (&vr, old_vr);
+
+	  /* If we found any usable VR, set the VR to ssa_name and create a
+	     PUSH old value in the stack with the old VR.  */
+	  if (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE)
+	    {
+	      new_vr = vrp_value_range_pool.allocate ();
+	      *new_vr = vr;
+	      push_value_range (op0, new_vr);
+	    }
+	}
+    }
+
+  /* Visit PHI stmts and discover any new VRs possible.  */
+  gimple_stmt_iterator gsi;
+  for (gphi_iterator gpi = gsi_start_phis (bb);
+       !gsi_end_p (gpi); gsi_next (&gpi))
+    {
+      gphi *phi = gpi.phi ();
+      tree lhs = PHI_RESULT (phi);
+      value_range vr_result = VR_INITIALIZER;
+      if (stmt_interesting_for_vrp (phi)
+	  && stmt_visit_phi_node_in_dom_p (phi))
+	extract_range_from_phi_node (phi, &vr_result);
+      else
+	set_value_range_to_varying (&vr_result);
+      update_value_range (lhs, &vr_result);
+    }
+
+  /* Visit all other stmts and discover any new VRs possible.  */
+  for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+    {
+      gimple *stmt = gsi_stmt (gsi);
+      edge taken_edge;
+      tree output = NULL_TREE;
+      gimple *old_stmt = stmt;
+      bool was_noreturn = (is_gimple_call (stmt)
+			   && gimple_call_noreturn_p (stmt));
+
+      /* TODO, if found taken_edge, we should visit (return it) and travel
+	 again to improve VR as done in DOM/SCCVN optimizations.  It should
+	 be done carefully as stmts might prematurely leave a BB like
+	 in EH.  */
+      if (stmt_interesting_for_vrp (stmt))
+	{
+	  value_range vr = VR_INITIALIZER;
+	  extract_range_from_stmt (stmt, &taken_edge, &output, &vr);
+	  if (output
+	      && (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE))
+	    update_value_range (output, &vr);
+	  else
+	    {
+	      tree def;
+	      ssa_op_iter iter;
+	      FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_DEF)
+		set_value_range_to_varying (get_value_range (def));
+	    }
+
+	  /* Try folding stmts with the VR discovered.  */
+	  bool did_replace = replace_uses_in (stmt, evrp_valueize);
+	  if (fold_stmt (&gsi, follow_single_use_edges)
+	      || did_replace)
+	    update_stmt (gsi_stmt (gsi));
+
+	  if (did_replace)
+	    {
+	      /* If we cleaned up EH information from the statement,
+		 remove EH edges.  */
+	      if (maybe_clean_or_replace_eh_stmt (old_stmt, stmt))
+		bitmap_set_bit (need_eh_cleanup, bb->index);
+
+	      /* If we turned a not noreturn call into a noreturn one
+		 schedule it for fixup.  */
+	      if (!was_noreturn
+		  && is_gimple_call (stmt)
+		  && gimple_call_noreturn_p (stmt))
+		stmts_to_fixup.safe_push (stmt);
+
+	      if (gimple_assign_single_p (stmt))
+		{
+		  tree rhs = gimple_assign_rhs1 (stmt);
+		  if (TREE_CODE (rhs) == ADDR_EXPR)
+		    recompute_tree_invariant_for_addr_expr (rhs);
+		}
+	    }
+
+	  def_operand_p def_p = SINGLE_SSA_DEF_OPERAND (stmt, SSA_OP_DEF);
+	  /* Set the SSA with the value range.  */
+	  if (def_p
+	      && TREE_CODE (DEF_FROM_PTR (def_p)) == SSA_NAME
+	      && INTEGRAL_TYPE_P (TREE_TYPE (DEF_FROM_PTR (def_p))))
+	    {
+	      tree def = DEF_FROM_PTR (def_p);
+	      value_range *vr = get_value_range (def);
+
+	      if ((vr->type == VR_RANGE
+		   || vr->type == VR_ANTI_RANGE)
+		  && (TREE_CODE (vr->min) == INTEGER_CST)
+		  && (TREE_CODE (vr->max) == INTEGER_CST))
+		set_range_info (def, vr->type, vr->min, vr->max);
+	    }
+	}
+      else
+	{
+	  tree def;
+	  ssa_op_iter iter;
+	  FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_DEF)
+	    set_value_range_to_varying (get_value_range (def));
+	}
+    }
+  return NULL;
+}
+
+/* Restore/pop VRs valid only for BB when we leave BB.  */
+
+void
+evrp_dom_walker::after_dom_children (basic_block bb)
+{
+  bb->flags |= BB_VISITED;
+  gcc_checking_assert (!stack.is_empty ());
+  while (stack.last ().first != NULL_TREE)
+    pop_value_range (stack.last ().first);
+  pop_value_range (stack.last ().first);
+}
+
+/* Push the Value Range of VAR to the stack and update it with new VR.  */
+
+void
+evrp_dom_walker::push_value_range (const_tree var, value_range *vr)
+{
+  if (vr != NULL)
+    {
+      unsigned ver = SSA_NAME_VERSION (var);
+      gcc_checking_assert (vr_value);
+      stack.safe_push (std::make_pair (var, vr_value[ver]));
+
+      if (ver < num_vr_values)
+	vr_value[ver] = vr;
+    }
+  else
+    stack.safe_push (std::make_pair (var, vr));
+}
+
+/* Pop the Value Range from the vrp_stack and update VAR with it.  */
+
+value_range *
+evrp_dom_walker::pop_value_range (const_tree var)
+{
+  value_range *vr = stack.last ().second;
+  if (vr != NULL)
+    {
+      unsigned ver = SSA_NAME_VERSION (var);
+      gcc_checking_assert (var == stack.last ().first);
+      gcc_checking_assert (vr_value);
+
+      if (ver < num_vr_values)
+	vr_value[ver] = vr;
+    }
+  stack.pop ();
+  return vr;
+}
+
+
+/* Main entry point for the early vrp pass which is a simplified non-iterative
+   version of vrp where basic blocks are visited in dominance order.  Value
+   ranges discovered in early vrp will also be used by ipa-vrp.  */
+
+static unsigned int
+execute_early_vrp ()
+{
+  edge e;
+  edge_iterator ei;
+  basic_block bb;
+
+  loop_optimizer_init (LOOPS_NORMAL | LOOPS_HAVE_RECORDED_EXITS);
+  rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa);
+  scev_initialize ();
+  calculate_dominance_info (CDI_DOMINATORS);
+  FOR_EACH_BB_FN (bb, cfun)
+    {
+      FOR_EACH_EDGE (e, ei, bb->preds)
+	e->flags |= EDGE_EXECUTABLE;
+    }
+  vrp_initialize_lattice ();
+
+  /* Walk stmts in dominance order and propagate VRP.  */
+  evrp_dom_walker walker;
+  walker.walk (ENTRY_BLOCK_PTR_FOR_FN (cfun));
+
+  if (!bitmap_empty_p (walker.need_eh_cleanup))
+    gimple_purge_all_dead_eh_edges (walker.need_eh_cleanup);
+
+  /* Fixup stmts that became noreturn calls.  This may require splitting
+     blocks and thus isn't possible during the dominator walk.  Do this
+     in reverse order so we don't inadvertedly remove a stmt we want to
+     fixup by visiting a dominating now noreturn call first.  */
+  while (!walker.stmts_to_fixup.is_empty ())
+    {
+      gimple *stmt = walker.stmts_to_fixup.pop ();
+      fixup_noreturn_call (stmt);
+    }
+
+  if (dump_file)
+    {
+      fprintf (dump_file, "\nValue ranges after Early VRP:\n\n");
+      dump_all_value_ranges (dump_file);
+      fprintf (dump_file, "\n");
+    }
+  vrp_free_lattice ();
+  scev_finalize ();
+  loop_optimizer_finalize ();
+  FOR_EACH_BB_FN (bb, cfun)
+    bb->flags &= ~BB_VISITED;
+  return 0;
 }
 
 
@@ -10627,9 +10974,11 @@ execute_vrp (bool warn_array_bounds_p)
   /* For visiting PHI nodes we need EDGE_DFS_BACK computed.  */
   mark_dfs_back_edges ();
 
+  vrp_initialize_lattice ();
   vrp_initialize ();
   ssa_propagate (vrp_visit_stmt, vrp_visit_phi_node);
   vrp_finalize (warn_array_bounds_p);
+  vrp_free_lattice ();
 
   free_numbers_of_iterations_estimates (cfun);
 
@@ -10727,3 +11076,44 @@ make_pass_vrp (gcc::context *ctxt)
 {
   return new pass_vrp (ctxt);
 }
+
+namespace {
+
+const pass_data pass_data_early_vrp =
+{
+  GIMPLE_PASS, /* type */
+  "evrp", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_TREE_EARLY_VRP, /* tv_id */
+  PROP_ssa, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  ( TODO_cleanup_cfg | TODO_update_ssa | TODO_verify_all ),
+};
+
+class pass_early_vrp : public gimple_opt_pass
+{
+public:
+  pass_early_vrp (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_early_vrp, ctxt)
+    {}
+
+  /* opt_pass methods: */
+  opt_pass * clone () { return new pass_early_vrp (m_ctxt); }
+  virtual bool gate (function *)
+    {
+      return flag_tree_vrp != 0;
+    }
+  virtual unsigned int execute (function *)
+    { return execute_early_vrp (); }
+
+}; // class pass_vrp
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_early_vrp (gcc::context *ctxt)
+{
+  return new pass_early_vrp (ctxt);
+}
+
-- 
2.7.4


^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Early VRP Implementation
  2016-09-15 14:57                                         ` Jeff Law
@ 2016-09-16  8:59                                           ` Richard Biener
  0 siblings, 0 replies; 67+ messages in thread
From: Richard Biener @ 2016-09-16  8:59 UTC (permalink / raw)
  To: Jeff Law
  Cc: Jan Hubicka, Kugan Vivekanandarajah, Andrew Pinski, gcc-patches,
	Martin Jambor

On Thu, Sep 15, 2016 at 4:45 PM, Jeff Law <law@redhat.com> wrote:
> On 09/14/2016 11:55 PM, Richard Biener wrote:
>>
>> On September 14, 2016 11:36:16 PM GMT+02:00, Jan Hubicka <hubicka@ucw.cz>
>> wrote:
>>>>
>>>> +  /* Visit PHI stmts and discover any new VRs possible.  */
>>>> +  gimple_stmt_iterator gsi;
>>>> +  for (gphi_iterator gpi = gsi_start_phis (bb);
>>>> +       !gsi_end_p (gpi); gsi_next (&gpi))
>>>> +    {
>>>> +      gphi *phi = gpi.phi ();
>>>> +      tree lhs = PHI_RESULT (phi);
>>>> +      value_range vr_result = VR_INITIALIZER;
>>>> +      if (! has_unvisived_preds
>>>>            && stmt_interesting_for_vrp (phi)
>>>> +         && stmt_visit_phi_node_in_dom_p (phi))
>>>> +       extract_range_from_phi_node (phi, &vr_result, true);
>>>> +      else
>>>> +       set_value_range_to_varying (&vr_result);
>>>> +      update_value_range (lhs, &vr_result);
>>>> +    }
>>>>
>>>> due to a bug in IRA you need to make sure to un-set BB_VISITED after
>>>> early-vrp is finished again.
>>>
>>> How IRA bugs affects early passes?
>>
>>
>> IRA bogously relies on BB_VISITED being cleared at pass start.
>
> Seems like IRA ought to be fixed to clear BB_VISITED on every block as part
> of its initialization.

Agreed but I didn't find the time to track down an appropriate place to do that.

Richard.

> Jeff
>

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Early VRP Implementation
  2016-09-16  6:37                                     ` kugan
@ 2016-09-16 10:26                                       ` Richard Biener
  2016-09-18 23:40                                         ` kugan
  0 siblings, 1 reply; 67+ messages in thread
From: Richard Biener @ 2016-09-16 10:26 UTC (permalink / raw)
  To: kugan; +Cc: Andrew Pinski, gcc-patches, Jan Hubicka, Martin Jambor

On Fri, Sep 16, 2016 at 7:59 AM, kugan
<kugan.vivekanandarajah@linaro.org> wrote:
> Hi Richard,
>
> Thanks for the review.
>
> On 14/09/16 22:04, Richard Biener wrote:
>>
>> On Tue, Aug 23, 2016 at 4:11 AM, Kugan Vivekanandarajah
>> <kugan.vivekanandarajah@linaro.org> wrote:
>>>
>>> Hi,
>>>
>>> On 19 August 2016 at 21:41, Richard Biener <richard.guenther@gmail.com>
>>> wrote:
>>>>
>>>> On Tue, Aug 16, 2016 at 9:45 AM, kugan
>>>> <kugan.vivekanandarajah@linaro.org> wrote:
>>>>>
>>>>> Hi Richard,
>
>
>>>>> I am now having -ftree-evrp which is enabled all the time. But This
>>>>> will
>>>>> only be used for disabling the early-vrp. That is, early-vrp will be
>>>>> run
>>>>> when ftree-vrp is enabled and ftree-evrp is not explicitly disabled. Is
>>>>> this
>>>>> OK?
>>>>
>>>>
>>>> Why would one want to disable early-vrp?  I see you do this in the
>>>> testsuite
>>>> for non-early VRP unit-tests but using -fdisable-tree-evrp1 there
>>>> would be ok as well.
>>>
>>>
>>> Removed it altogether. I though that you wanted a way to disable
>>> early-vrp for testing purposes.
>>
>>
>> But there is via the generic -fdisable-tree-DUMPFILE way.
>
>
> OK. I didnt know about that.
>
>
>>>> Note that you want to have a custom valueize function instead of just
>>>> follow_single_use_edges as you want to valueize all SSA names according
>>>> to their lattice value (if it has a single value).  You can use
>>>> vrp_valueize
>>>> for this though that gets you non-single-use edge following as well.
>>>> Eventually it's going to be cleaner to do what the SSA propagator does
>>>> and
>>>> before folding do
>>>>
>>>>    did_replace = replace_uses_in (stmt, vrp_valueize);
>>>>    if (fold_stmt (&gsi, follow_single_use_edges)
>>>>        || did_replace)
>>>>      update_stmt (gsi_stmt (gsi));
>>>>
>>>> exporting replace_uses_in for this is ok.  I guess I prefer this for
>>>> now.
>>>
>>>
>>> I also added the above.  I noticed that I need
>>> recompute_tree_invariant_for_addr_expr as in ssa_propagate. My initial
>>> implementation also had gimple_purge_all_dead_eh_edges and
>>> fixup_noreturn_call as in ssa_propagat but I thinj that is not needed
>>> as it would be done at the end of the pass.
>>
>>
>> I don't see this being done at the end of the pass.  So please
>> re-instantiate
>> that parts.
>
>
> I have copied these part as well.
>
>>> With this I noticed more stmts are folded before vrp1. This required
>>> me to adjust some testcases.
>>>
>>>>
>>>> Overall this now looks good apart from the folding and the
>>>> VR_INITIALIZER thing.
>>>>
>>>> You can commit the already approved refactoring changes and combine this
>>>> patch with the struct value_range move, this way I can more easily look
>>>> into
>>>> issues with the UNDEFINED thing if you can come up with a testcase that
>>>> doesn't work.
>>>>
>>>
>>> I have now committed all the dependent patches.
>>>
>>> Attached patch passes regression and bootstrap except pr33738.C. This
>>> is an unrelated issue as discussed in
>>> https://gcc.gnu.org/ml/gcc-patches/2016-08/msg01386.html
>>>
>>> Is this OK?
>>
>>
>> +/* Initialize local data structures for VRP.  If DOM_P is true,
>> +   we will be calling this from early_vrp where value range propagation
>> +   is done by visiting stmts in dominator tree.  ssa_propagate engine
>> +   is not used in this case and that part of the ininitialization will
>> +   be skipped.  */
>> +
>> +static void
>> +vrp_initialize ()
>>
>> comment needs updating now.
>>
> Done.
>
>>
>>  static void
>> -extract_range_from_phi_node (gphi *phi, value_range *vr_result)
>> +extract_range_from_phi_node (gphi *phi, value_range *vr_result,
>> +                            bool early_vrp_p)
>>  {
>>
>>
>> I don't think you need this changes now that you have
>> stmt_visit_phi_node_in_dom_p
>> guarding its call.
>
>
> OK removed it. That also mean I had to put scev_* in the early_vrp.
>
>
>
>> +static bool
>> +stmt_visit_phi_node_in_dom_p (gphi *phi)
>> +{
>> +  ssa_op_iter iter;
>> +  use_operand_p oprnd;
>> +  tree op;
>> +  value_range *vr;
>> +  FOR_EACH_PHI_ARG (oprnd, phi, iter, SSA_OP_USE)
>> +    {
>> +      op = USE_FROM_PTR (oprnd);
>> +      if (TREE_CODE (op) == SSA_NAME)
>> +       {
>> +         vr = get_value_range (op);
>> +         if (vr->type == VR_UNDEFINED)
>> +           return false;
>> +       }
>> +    }
>>
>> I think this is overly conservative in never allowing UNDEFINED on PHI
>> node args (even if the def was actually visited).  I think that the most
>> easy way to improve this bit would be to actually track visited blocks.
>> You already set the EDGE_EXECUTABLE flag on edges so you could
>> clear BB_VISITED on all blocks and set it in the before_dom_children
>> hook (at the end).  Then the above can be folded into the PHI visiting:
>>
>>     bool has_unvisited_pred = false;
>>     FOR_EACH_EDGE (e, ei, bb->preds)
>>        if (!(e->src->flags & BB_VISITED))
>>          {
>>             has_unvisited_preds = true;
>>             break;
>>          }
>>
> OK done.
>
> I also had to check for uninitialized variables that will have VR_UNDEFINED
> as range. We do not visit GIMPLE_NOP.

But VR_UNDEFINED of uninitialized variables is fine to use.

>
>> +  /* Visit PHI stmts and discover any new VRs possible.  */
>> +  gimple_stmt_iterator gsi;
>> +  for (gphi_iterator gpi = gsi_start_phis (bb);
>> +       !gsi_end_p (gpi); gsi_next (&gpi))
>> +    {
>> +      gphi *phi = gpi.phi ();
>> +      tree lhs = PHI_RESULT (phi);
>> +      value_range vr_result = VR_INITIALIZER;
>> +      if (! has_unvisived_preds
>>            && stmt_interesting_for_vrp (phi)
>> +         && stmt_visit_phi_node_in_dom_p (phi))

failed to remove this call to stmt_visit_phi_node_in_dom_p -- whether we need to
drop to varying is a property that is the same for all PHI nodes in a block.

>> +       extract_range_from_phi_node (phi, &vr_result, true);
>> +      else
>> +       set_value_range_to_varying (&vr_result);
>> +      update_value_range (lhs, &vr_result);
>> +    }
>>
>> due to a bug in IRA you need to make sure to un-set BB_VISITED after
>> early-vrp is finished again.
>
> OK. Done.

You set BB_VISITED in after_dom_children -- that is too late, please
set it at the end
of before_dom_children.  Otherwise it pessimizes handling of the PHIs
in the merge
block of a diamond in case the PHI args are defined in the immediate dominator.

As said you need to clear BB_VISITED at the start of evrp as well
(clearing at the end
is just a workaround for a IRA bug).

>>
>> +         /* Try folding stmts with the VR discovered.  */
>> +         bool did_replace = replace_uses_in (stmt, evrp_valueize);
>> +         if (fold_stmt (&gsi, follow_single_use_edges)
>> +             || did_replace)
>> +           update_stmt (gsi_stmt (gsi));
>>
>> you should be able to re-use vrp_valueize here.
>
> This issue is vrp_valueize accepts ranges such as [VAR + CST, VAR + CST]
> which we can not set.

Oh - that looks like sth we need to fix anyway then.  May I suggest to change
vrp_valueize to do

         && (TREE_CODE (vr->min) == SSA_NAME
                || is_gimple_min_invariant (TREE_CODE (vr->min)))

which also allows [&a, &a] like constants.

>>
>> +         def_operand_p def_p = SINGLE_SSA_DEF_OPERAND (stmt, SSA_OP_DEF);
>> +         /* Set the SSA with the value range.  */
>> +         if (def_p
>> +             && TREE_CODE (DEF_FROM_PTR (def_p)) == SSA_NAME
>> +             && INTEGRAL_TYPE_P (TREE_TYPE (DEF_FROM_PTR (def_p))))
>> +           {
>> +             tree def = DEF_FROM_PTR (def_p);
>> +             unsigned ver = SSA_NAME_VERSION (def);
>> +             if ((vr_value[ver]->type == VR_RANGE
>>
>> Use get_value_range () please, not direct access to vr_value.
>>
> Done.
>
>> +                  || vr_value[ver]->type == VR_ANTI_RANGE)
>> +                 && (TREE_CODE (vr_value[ver]->min) == INTEGER_CST)
>> +                 && (TREE_CODE (vr_value[ver]->max) == INTEGER_CST))
>> +               set_range_info (def, vr_value[ver]->type,
>> vr_value[ver]->min,
>> +                               vr_value[ver]->max);
>> +           }
>>
>> Otherwise the patch looks good now (with a lot of improvement
>> possibilities of course).
>
> I will work on the improvement after this goes in.
>
> Bootstrapped and regression tested on x86_64-linux-gnu. Does this looks OK?

Please remove no-op changes like

diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c
b/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c
index 7efdd63..3a433d6 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c
@@ -3,7 +3,7 @@
    known to be zero after entering the first two "if" statements.  */

 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1" } */
+/* { dg-options "-O2  -fdump-tree-vrp1" } */

 void link_error (void);

@@ -21,4 +21,4 @@ foo (int *p, int q)
     }
 }

-/* { dg-final { scan-tree-dump-times "Folding predicate r_.* != 0B to
0" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "link_error" 0 "vrp1" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c
b/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c
index dcf9148..c4fda8b 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c
@@ -3,7 +3,7 @@
    Check that VRP now gets ranges from BIT_AND_EXPRs.  */

 /* { dg-do compile } */
-/* { dg-options "-O2 -fno-tree-ccp -fdump-tree-vrp1" } */
+/* { dg-options "-O2 -fno-tree-ccp -fdump-tree-vrp" } */

 int
 foo (int a)


diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp46.c
b/gcc/testsuite/gcc.dg/tree-ssa/vrp46.c
index d3c9ed1..5b279a1 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp46.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp46.c
@@ -27,6 +27,5 @@ func_18 ( int t )
     }
 }

-/* There should be a single if left.  */

-/* { dg-final { scan-tree-dump-times "if" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "if" 0 "vrp1" } } */

I'm curious -- this is not a dg-run testcase but did you investigate this
isn't generating wrong code now?  At least I can't see how
the if (1 & (t % rhs)) test could vanish.

I hope we'll get GIMPLE unit testing finished for GCC 7 so we can add separate
unit-tests for VRP and EVRP.

Thanks,
Richard.


> Thanks,
> Kugan
>
>
>
>>
>> Thanks and sorry for the delay,
>> Richard.
>>
>>> Thanks,
>>> Kugan
>>>
>>>
>>>> Thanks,
>>>> Richard.
>>>>
>>>>> I also noticed that g++.dg/warn/pr33738.C testcase is now failing. This
>>>>> is
>>>>> because, with early-vrp setting value range ccp2 is optimizing without
>>>>> issuing a warning. I will look into it.
>>>>>
>>>>> bootstrap and regression testing is in progress.
>>>>>
>>>>> Thanks,
>>>>> Kugan

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Early VRP Implementation
  2016-09-16 10:26                                       ` Richard Biener
@ 2016-09-18 23:40                                         ` kugan
  2016-09-19 13:30                                           ` Richard Biener
  0 siblings, 1 reply; 67+ messages in thread
From: kugan @ 2016-09-18 23:40 UTC (permalink / raw)
  To: Richard Biener; +Cc: Andrew Pinski, gcc-patches, Jan Hubicka, Martin Jambor

[-- Attachment #1: Type: text/plain, Size: 12220 bytes --]

Hi Richard,


On 16/09/16 20:21, Richard Biener wrote:
> On Fri, Sep 16, 2016 at 7:59 AM, kugan
> <kugan.vivekanandarajah@linaro.org> wrote:
>> Hi Richard,
>>
>> Thanks for the review.
>>
>> On 14/09/16 22:04, Richard Biener wrote:
>>>
>>> On Tue, Aug 23, 2016 at 4:11 AM, Kugan Vivekanandarajah
>>> <kugan.vivekanandarajah@linaro.org> wrote:
>>>>
>>>> Hi,
>>>>
>>>> On 19 August 2016 at 21:41, Richard Biener <richard.guenther@gmail.com>
>>>> wrote:
>>>>>
>>>>> On Tue, Aug 16, 2016 at 9:45 AM, kugan
>>>>> <kugan.vivekanandarajah@linaro.org> wrote:
>>>>>>
>>>>>> Hi Richard,
>>
>>
>>>>>> I am now having -ftree-evrp which is enabled all the time. But This
>>>>>> will
>>>>>> only be used for disabling the early-vrp. That is, early-vrp will be
>>>>>> run
>>>>>> when ftree-vrp is enabled and ftree-evrp is not explicitly disabled. Is
>>>>>> this
>>>>>> OK?
>>>>>
>>>>>
>>>>> Why would one want to disable early-vrp?  I see you do this in the
>>>>> testsuite
>>>>> for non-early VRP unit-tests but using -fdisable-tree-evrp1 there
>>>>> would be ok as well.
>>>>
>>>>
>>>> Removed it altogether. I though that you wanted a way to disable
>>>> early-vrp for testing purposes.
>>>
>>>
>>> But there is via the generic -fdisable-tree-DUMPFILE way.
>>
>>
>> OK. I didnt know about that.
>>
>>
>>>>> Note that you want to have a custom valueize function instead of just
>>>>> follow_single_use_edges as you want to valueize all SSA names according
>>>>> to their lattice value (if it has a single value).  You can use
>>>>> vrp_valueize
>>>>> for this though that gets you non-single-use edge following as well.
>>>>> Eventually it's going to be cleaner to do what the SSA propagator does
>>>>> and
>>>>> before folding do
>>>>>
>>>>>    did_replace = replace_uses_in (stmt, vrp_valueize);
>>>>>    if (fold_stmt (&gsi, follow_single_use_edges)
>>>>>        || did_replace)
>>>>>      update_stmt (gsi_stmt (gsi));
>>>>>
>>>>> exporting replace_uses_in for this is ok.  I guess I prefer this for
>>>>> now.
>>>>
>>>>
>>>> I also added the above.  I noticed that I need
>>>> recompute_tree_invariant_for_addr_expr as in ssa_propagate. My initial
>>>> implementation also had gimple_purge_all_dead_eh_edges and
>>>> fixup_noreturn_call as in ssa_propagat but I thinj that is not needed
>>>> as it would be done at the end of the pass.
>>>
>>>
>>> I don't see this being done at the end of the pass.  So please
>>> re-instantiate
>>> that parts.
>>
>>
>> I have copied these part as well.
>>
>>>> With this I noticed more stmts are folded before vrp1. This required
>>>> me to adjust some testcases.
>>>>
>>>>>
>>>>> Overall this now looks good apart from the folding and the
>>>>> VR_INITIALIZER thing.
>>>>>
>>>>> You can commit the already approved refactoring changes and combine this
>>>>> patch with the struct value_range move, this way I can more easily look
>>>>> into
>>>>> issues with the UNDEFINED thing if you can come up with a testcase that
>>>>> doesn't work.
>>>>>
>>>>
>>>> I have now committed all the dependent patches.
>>>>
>>>> Attached patch passes regression and bootstrap except pr33738.C. This
>>>> is an unrelated issue as discussed in
>>>> https://gcc.gnu.org/ml/gcc-patches/2016-08/msg01386.html
>>>>
>>>> Is this OK?
>>>
>>>
>>> +/* Initialize local data structures for VRP.  If DOM_P is true,
>>> +   we will be calling this from early_vrp where value range propagation
>>> +   is done by visiting stmts in dominator tree.  ssa_propagate engine
>>> +   is not used in this case and that part of the ininitialization will
>>> +   be skipped.  */
>>> +
>>> +static void
>>> +vrp_initialize ()
>>>
>>> comment needs updating now.
>>>
>> Done.
>>
>>>
>>>  static void
>>> -extract_range_from_phi_node (gphi *phi, value_range *vr_result)
>>> +extract_range_from_phi_node (gphi *phi, value_range *vr_result,
>>> +                            bool early_vrp_p)
>>>  {
>>>
>>>
>>> I don't think you need this changes now that you have
>>> stmt_visit_phi_node_in_dom_p
>>> guarding its call.
>>
>>
>> OK removed it. That also mean I had to put scev_* in the early_vrp.
>>
>>
>>
>>> +static bool
>>> +stmt_visit_phi_node_in_dom_p (gphi *phi)
>>> +{
>>> +  ssa_op_iter iter;
>>> +  use_operand_p oprnd;
>>> +  tree op;
>>> +  value_range *vr;
>>> +  FOR_EACH_PHI_ARG (oprnd, phi, iter, SSA_OP_USE)
>>> +    {
>>> +      op = USE_FROM_PTR (oprnd);
>>> +      if (TREE_CODE (op) == SSA_NAME)
>>> +       {
>>> +         vr = get_value_range (op);
>>> +         if (vr->type == VR_UNDEFINED)
>>> +           return false;
>>> +       }
>>> +    }
>>>
>>> I think this is overly conservative in never allowing UNDEFINED on PHI
>>> node args (even if the def was actually visited).  I think that the most
>>> easy way to improve this bit would be to actually track visited blocks.
>>> You already set the EDGE_EXECUTABLE flag on edges so you could
>>> clear BB_VISITED on all blocks and set it in the before_dom_children
>>> hook (at the end).  Then the above can be folded into the PHI visiting:
>>>
>>>     bool has_unvisited_pred = false;
>>>     FOR_EACH_EDGE (e, ei, bb->preds)
>>>        if (!(e->src->flags & BB_VISITED))
>>>          {
>>>             has_unvisited_preds = true;
>>>             break;
>>>          }
>>>
>> OK done.
>>
>> I also had to check for uninitialized variables that will have VR_UNDEFINED
>> as range. We do not visit GIMPLE_NOP.
>
> But VR_UNDEFINED of uninitialized variables is fine to use.

Indeed. I was really trying to fix another problem with this.

The real problem I am facing is:

When we have a PHI stmt with one argument as symbolic VR_RANGE and 
another as VR_UNDEFINED, we will copy VR_RANGE to the PHI result.

When we fold the uses of the PHI result with vrp_valueize, we will 
assign the symbol from VR_RANGE if that is of the form [a, a].

However, in replace_uses_in, we dont see if the SSA definition dominates 
the gimple that uses it. This some times results in ICE.

For now, in the vrp_valueize, I have commented out the SSA_NAME part (as 
shown in the attached patch). With that I can bootstrap and regression 
test the patch.

The fix is to either:

1. Remove SSA_NAME from vrp_valueize. Currently we use vrp_valueize with 
gimple_fold_stmt_to_constant_1 and accepts only is_gimple_min_invariant. 
Therefore maybe SSA_NAME is not needed?

2. Or, in replace_uses_in, see if the stmt dominates operand definition 
before replacing.

>>
>>> +  /* Visit PHI stmts and discover any new VRs possible.  */
>>> +  gimple_stmt_iterator gsi;
>>> +  for (gphi_iterator gpi = gsi_start_phis (bb);
>>> +       !gsi_end_p (gpi); gsi_next (&gpi))
>>> +    {
>>> +      gphi *phi = gpi.phi ();
>>> +      tree lhs = PHI_RESULT (phi);
>>> +      value_range vr_result = VR_INITIALIZER;
>>> +      if (! has_unvisived_preds
>>>            && stmt_interesting_for_vrp (phi)
>>> +         && stmt_visit_phi_node_in_dom_p (phi))
>
> failed to remove this call to stmt_visit_phi_node_in_dom_p -- whether we need to
> drop to varying is a property that is the same for all PHI nodes in a block.
>
Done.

>>> +       extract_range_from_phi_node (phi, &vr_result, true);
>>> +      else
>>> +       set_value_range_to_varying (&vr_result);
>>> +      update_value_range (lhs, &vr_result);
>>> +    }
>>>
>>> due to a bug in IRA you need to make sure to un-set BB_VISITED after
>>> early-vrp is finished again.
>>
>> OK. Done.
>
> You set BB_VISITED in after_dom_children -- that is too late, please
> set it at the end
> of before_dom_children.  Otherwise it pessimizes handling of the PHIs
> in the merge
> block of a diamond in case the PHI args are defined in the immediate dominator.
>
> As said you need to clear BB_VISITED at the start of evrp as well
> (clearing at the end
> is just a workaround for a IRA bug).
Done.

>>>
>>> +         /* Try folding stmts with the VR discovered.  */
>>> +         bool did_replace = replace_uses_in (stmt, evrp_valueize);
>>> +         if (fold_stmt (&gsi, follow_single_use_edges)
>>> +             || did_replace)
>>> +           update_stmt (gsi_stmt (gsi));
>>>
>>> you should be able to re-use vrp_valueize here.
>>
>> This issue is vrp_valueize accepts ranges such as [VAR + CST, VAR + CST]
>> which we can not set.
>
> Oh - that looks like sth we need to fix anyway then.  May I suggest to change
> vrp_valueize to do
>
>          && (TREE_CODE (vr->min) == SSA_NAME
>                 || is_gimple_min_invariant (TREE_CODE (vr->min)))
>
> which also allows [&a, &a] like constants.

Please see the error above.


>>>
>>> +         def_operand_p def_p = SINGLE_SSA_DEF_OPERAND (stmt, SSA_OP_DEF);
>>> +         /* Set the SSA with the value range.  */
>>> +         if (def_p
>>> +             && TREE_CODE (DEF_FROM_PTR (def_p)) == SSA_NAME
>>> +             && INTEGRAL_TYPE_P (TREE_TYPE (DEF_FROM_PTR (def_p))))
>>> +           {
>>> +             tree def = DEF_FROM_PTR (def_p);
>>> +             unsigned ver = SSA_NAME_VERSION (def);
>>> +             if ((vr_value[ver]->type == VR_RANGE
>>>
>>> Use get_value_range () please, not direct access to vr_value.
>>>
>> Done.
>>
>>> +                  || vr_value[ver]->type == VR_ANTI_RANGE)
>>> +                 && (TREE_CODE (vr_value[ver]->min) == INTEGER_CST)
>>> +                 && (TREE_CODE (vr_value[ver]->max) == INTEGER_CST))
>>> +               set_range_info (def, vr_value[ver]->type,
>>> vr_value[ver]->min,
>>> +                               vr_value[ver]->max);
>>> +           }
>>>
>>> Otherwise the patch looks good now (with a lot of improvement
>>> possibilities of course).
>>
>> I will work on the improvement after this goes in.
>>
>> Bootstrapped and regression tested on x86_64-linux-gnu. Does this looks OK?
>
> Please remove no-op changes like
Done.

> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c
> b/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c
> index 7efdd63..3a433d6 100644
> --- a/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c
> @@ -3,7 +3,7 @@
>     known to be zero after entering the first two "if" statements.  */
>
>  /* { dg-do compile } */
> -/* { dg-options "-O2 -fdump-tree-vrp1" } */
> +/* { dg-options "-O2  -fdump-tree-vrp1" } */
>
>  void link_error (void);
>
> @@ -21,4 +21,4 @@ foo (int *p, int q)
>      }
>  }
>
> -/* { dg-final { scan-tree-dump-times "Folding predicate r_.* != 0B to
> 0" 1 "vrp1" } } */
> +/* { dg-final { scan-tree-dump-times "link_error" 0 "vrp1" } } */
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c
> b/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c
> index dcf9148..c4fda8b 100644
> --- a/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c
> @@ -3,7 +3,7 @@
>     Check that VRP now gets ranges from BIT_AND_EXPRs.  */
>
>  /* { dg-do compile } */
> -/* { dg-options "-O2 -fno-tree-ccp -fdump-tree-vrp1" } */
> +/* { dg-options "-O2 -fno-tree-ccp -fdump-tree-vrp" } */
>
>  int
>  foo (int a)
>
>
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp46.c
> b/gcc/testsuite/gcc.dg/tree-ssa/vrp46.c
> index d3c9ed1..5b279a1 100644
> --- a/gcc/testsuite/gcc.dg/tree-ssa/vrp46.c
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp46.c
> @@ -27,6 +27,5 @@ func_18 ( int t )
>      }
>  }
>
> -/* There should be a single if left.  */
>
> -/* { dg-final { scan-tree-dump-times "if" 1 "vrp1" } } */
> +/* { dg-final { scan-tree-dump-times "if" 0 "vrp1" } } */
>
> I'm curious -- this is not a dg-run testcase but did you investigate this
> isn't generating wrong code now?  At least I can't see how
> the if (1 & (t % rhs)) test could vanish.
Indeed.This was a mistake and fixed it.


> I hope we'll get GIMPLE unit testing finished for GCC 7 so we can add separate
> unit-tests for VRP and EVRP.

I will have a look at it.

Thanks,
Kugan

> Thanks,
> Richard.
>
>
>> Thanks,
>> Kugan
>>
>>
>>
>>>
>>> Thanks and sorry for the delay,
>>> Richard.
>>>
>>>> Thanks,
>>>> Kugan
>>>>
>>>>
>>>>> Thanks,
>>>>> Richard.
>>>>>
>>>>>> I also noticed that g++.dg/warn/pr33738.C testcase is now failing. This
>>>>>> is
>>>>>> because, with early-vrp setting value range ccp2 is optimizing without
>>>>>> issuing a warning. I will look into it.
>>>>>>
>>>>>> bootstrap and regression testing is in progress.
>>>>>>
>>>>>> Thanks,
>>>>>> Kugan

[-- Attachment #2: 0001-Add-early-vrp.patch --]
[-- Type: text/x-patch, Size: 29861 bytes --]

From aac85c76a6445a240f277d02a4d37652cdeda7d7 Mon Sep 17 00:00:00 2001
From: Kugan Vivekanandarajah <kugan.vivekanandarajah@linaro.org>
Date: Tue, 23 Aug 2016 16:18:30 +1000
Subject: [PATCH 1/3] Add early-vrp

---
 gcc/doc/invoke.texi                       |   5 +
 gcc/passes.def                            |   1 +
 gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C |   2 +-
 gcc/testsuite/gcc.dg/tree-ssa/evrp1.c     |  13 +
 gcc/testsuite/gcc.dg/tree-ssa/evrp2.c     |  18 ++
 gcc/testsuite/gcc.dg/tree-ssa/evrp3.c     |  15 +
 gcc/testsuite/gcc.dg/tree-ssa/pr20657.c   |   4 +-
 gcc/testsuite/gcc.dg/tree-ssa/pr22117.c   |   2 +-
 gcc/testsuite/gcc.dg/tree-ssa/pr37508.c   |   2 +-
 gcc/testsuite/gcc.dg/tree-ssa/pr61839_2.c |   8 +-
 gcc/testsuite/gcc.dg/tree-ssa/pr64130.c   |   6 +-
 gcc/testsuite/gcc.dg/tree-ssa/vrp04.c     |   2 +-
 gcc/testsuite/gcc.dg/tree-ssa/vrp06.c     |   4 +-
 gcc/testsuite/gcc.dg/tree-ssa/vrp16.c     |   4 +-
 gcc/testsuite/gcc.dg/tree-ssa/vrp25.c     |   4 +-
 gcc/testsuite/gcc.dg/tree-ssa/vrp67.c     |   2 +-
 gcc/timevar.def                           |   1 +
 gcc/tree-pass.h                           |   1 +
 gcc/tree-ssa-propagate.c                  |   2 +-
 gcc/tree-ssa-propagate.h                  |   1 +
 gcc/tree-vrp.c                            | 465 ++++++++++++++++++++++++++----
 21 files changed, 488 insertions(+), 74 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/evrp1.c
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/evrp2.c
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/evrp3.c

diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 87da1f1..9ed9c24 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -12454,6 +12454,11 @@ is made by appending @file{.slp} to the source file name.
 Dump each function after Value Range Propagation (VRP).  The file name
 is made by appending @file{.vrp} to the source file name.
 
+@item early vrp
+@opindex fdump-tree-evrp
+Dump each function after Early Value Range Propagation (EVRP).  The file name
+is made by appending @file{.evrp} to the source file name.
+
 @item oaccdevlow
 @opindex fdump-tree-oaccdevlow
 Dump each function after applying device-specific OpenACC transformations.
diff --git a/gcc/passes.def b/gcc/passes.def
index 533157d..9759fed 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -89,6 +89,7 @@ along with GCC; see the file COPYING3.  If not see
 	     execute TODO_rebuild_alias at this point.  */
 	  NEXT_PASS (pass_build_ealias);
 	  NEXT_PASS (pass_fre);
+	  NEXT_PASS (pass_early_vrp);
 	  NEXT_PASS (pass_merge_phi);
           NEXT_PASS (pass_dse);
 	  NEXT_PASS (pass_cd_dce);
diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C b/gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C
index 5e09583..cf4ed33 100644
--- a/gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C
+++ b/gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O -fdump-tree-forwprop1" } */
+/* { dg-options "-O -fno-tree-vrp -fdump-tree-forwprop1" } */
 
 #include <new>
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/evrp1.c b/gcc/testsuite/gcc.dg/tree-ssa/evrp1.c
new file mode 100644
index 0000000..8c6e4e6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/evrp1.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+int foo (int i);
+int bar (int j)
+{
+  if (j > 2)
+    return foo (j + 2);
+  else
+    return j;
+}
+
+/* { dg-final { scan-tree-dump "\\\[5, \\+INF" "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/evrp2.c b/gcc/testsuite/gcc.dg/tree-ssa/evrp2.c
new file mode 100644
index 0000000..e6d4235
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/evrp2.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+int foo (int i);
+int bar2 (int j)
+{
+  if (j > 2)
+    {
+      if (j < 7)
+	return foo (j + 1);
+      else
+	return foo (j + 2);
+    }
+  return j;
+}
+
+
+/* { dg-final { scan-tree-dump "\\\[4, 7\\\]" "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/evrp3.c b/gcc/testsuite/gcc.dg/tree-ssa/evrp3.c
new file mode 100644
index 0000000..1a3bbd5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/evrp3.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+int foo (int i);
+void bar (int j)
+{
+  unsigned int i;
+  for (i = 0; i < 10; ++i)
+    {
+      bar (i + 1);
+    }
+}
+
+/* { dg-final { scan-tree-dump "\\\[1, 10\\\]" "evrp" } } */
+
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr20657.c b/gcc/testsuite/gcc.dg/tree-ssa/pr20657.c
index 727ca4c..e678231 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr20657.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr20657.c
@@ -3,7 +3,7 @@
    statement, which was needed to eliminate the second "if" statement.  */
 
 /* { dg-do compile } */
-/* { dg-options "-O2 -fno-tree-dominator-opts -fno-tree-fre -fdump-tree-vrp1-details" } */
+/* { dg-options "-O2 -fno-tree-dominator-opts -fno-tree-fre -fdump-tree-evrp" } */
 
 int
 foo (int a)
@@ -14,4 +14,4 @@ foo (int a)
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "Folding predicate" 1 "vrp1"} } */
+/* { dg-final { scan-tree-dump-times "if" 1 "evrp"} } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c b/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c
index 7efdd63..01cd33e 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c
@@ -21,4 +21,4 @@ foo (int *p, int q)
     }
 }
 
-/* { dg-final { scan-tree-dump-times "Folding predicate r_.* != 0B to 0" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "link_error" 0 "vrp1" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr37508.c b/gcc/testsuite/gcc.dg/tree-ssa/pr37508.c
index 0963cd9..2ba09af 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr37508.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr37508.c
@@ -46,4 +46,4 @@ int test4 (struct foo2 *x)
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "Folding" 2 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "if" 2 "vrp1" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr61839_2.c b/gcc/testsuite/gcc.dg/tree-ssa/pr61839_2.c
index ffa00a7..e44dc57 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr61839_2.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr61839_2.c
@@ -1,6 +1,6 @@
 /* PR tree-optimization/61839.  */
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1" } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
 /* { dg-require-effective-target int32plus } */
 
 __attribute__ ((noinline))
@@ -47,8 +47,8 @@ int bar2 ()
 
 
 /* Dont optimize 972195717 / 0 in function foo.  */
-/* { dg-final { scan-tree-dump-times "972195717 / _" 1  "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "972195717 / _" 1  "evrp" } } */
 /* Dont optimize 972195717 % 0 in function bar.  */
-/* { dg-final { scan-tree-dump-times "972195717 % _" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "972195717 % _" 1 "evrp" } } */
 /* Optimize in function bar2.  */
-/* { dg-final { scan-tree-dump-times "972195715 % _" 0 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "972195715 % _" 0 "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr64130.c b/gcc/testsuite/gcc.dg/tree-ssa/pr64130.c
index 0b25466..f39bd17 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr64130.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr64130.c
@@ -1,6 +1,6 @@
 
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1" } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
 
 int funsigned (unsigned a)
 {
@@ -13,6 +13,6 @@ int funsigned2 (unsigned a)
   return (-1 * 0x1ffffffffL) / a == 0;
 }
 
-/* { dg-final { scan-tree-dump ": \\\[2, 8589934591\\\]" "vrp1" } } */
-/* { dg-final { scan-tree-dump ": \\\[-8589934591, -2\\\]" "vrp1" } } */
+/* { dg-final { scan-tree-dump ": \\\[2, 8589934591\\\]" "evrp" } } */
+/* { dg-final { scan-tree-dump ": \\\[-8589934591, -2\\\]" "evrp" } } */
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp04.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp04.c
index 61b7a47..67f8f01 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp04.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp04.c
@@ -10,4 +10,4 @@ foo (int a, int b)
       return a + b;
 }
 
-/* { dg-final { scan-tree-dump-times "Folding predicate a_.*to 1" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "if" 1 "vrp1" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp06.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp06.c
index cdad534..c4ce170 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp06.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp06.c
@@ -28,6 +28,6 @@ foo (int i, int j, int a)
   return i + a + j;
 }
 
-/* { dg-final { scan-tree-dump-times "Folding predicate i_\[0-9\]+.*0 to 0" 1 "vrp1" } } */
-/* { dg-final { scan-tree-dump-times "Folding predicate j_\[0-9\]+.*0 to 1" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "Folding predicate \[i|j\]_\[0-9\]+.*0 to 0" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "Folding predicate \[i|j\]_\[0-9\]+.*0 to 1" 1 "vrp1" } } */
 /* { dg-final { scan-tree-dump-times "Folding predicate i_\[0-9]+.*j_\[0-9\]+.* to 0" 1 "vrp1" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp16.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp16.c
index 8f5d5c8..d09f3ae 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp16.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp16.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fno-tree-fre -fdump-tree-vrp1-details" } */
+/* { dg-options "-O2 -fno-tree-fre -fdump-tree-evrp" } */
 
 
 extern void abort (void) __attribute__ ((__noreturn__));
@@ -19,5 +19,5 @@ nonlocal_mentioned_p (rtx x)
 	abort ();
 }
 
-/* { dg-final { scan-tree-dump-times "Folding predicate .*to 0" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "if" 0 "evrp" } } */
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp25.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp25.c
index cbc4ec3..a49f079 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp25.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp25.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fno-tree-fre -fdump-tree-vrp1-details" } */
+/* { dg-options "-O2 -fno-tree-fre -fdump-tree-vrp1" } */
 
 extern void abort ();
 extern void arf ();
@@ -49,5 +49,5 @@ L9:
 /* The second test of (code1 != 53) and the test (D18670 <= 2) are
    both totally subsumed by earlier tests and thus should be folded
    away using VRP.  */
-/* { dg-final { scan-tree-dump-times "Folding predicate" 2 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "if" 3 "vrp1" } } */
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp67.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp67.c
index ef5e8f9..5155f7b 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp67.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp67.c
@@ -36,4 +36,4 @@ unsigned baz (unsigned i)
   return i;
 }
 
-/* { dg-final { scan-tree-dump-times "Folding predicate" 3 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "if" 3 "vrp1" } } */
diff --git a/gcc/timevar.def b/gcc/timevar.def
index 5f12118..8837832 100644
--- a/gcc/timevar.def
+++ b/gcc/timevar.def
@@ -149,6 +149,7 @@ DEFTIMEVAR (TV_TREE_CFG		     , "tree CFG construction")
 DEFTIMEVAR (TV_TREE_CLEANUP_CFG	     , "tree CFG cleanup")
 DEFTIMEVAR (TV_TREE_TAIL_MERGE       , "tree tail merge")
 DEFTIMEVAR (TV_TREE_VRP              , "tree VRP")
+DEFTIMEVAR (TV_TREE_EARLY_VRP        , "tree Early VRP")
 DEFTIMEVAR (TV_TREE_COPY_PROP        , "tree copy propagation")
 DEFTIMEVAR (TV_FIND_REFERENCED_VARS  , "tree find ref. vars")
 DEFTIMEVAR (TV_TREE_PTA		     , "tree PTA")
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index c0059de..86d797e 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -440,6 +440,7 @@ extern gimple_opt_pass *make_pass_fre (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_check_data_deps (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_copy_prop (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_isolate_erroneous_paths (gcc::context *ctxt);
+extern gimple_opt_pass *make_pass_early_vrp (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_vrp (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_uncprop (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_return_slot (gcc::context *ctxt);
diff --git a/gcc/tree-ssa-propagate.c b/gcc/tree-ssa-propagate.c
index c8cf078..97cfde5 100644
--- a/gcc/tree-ssa-propagate.c
+++ b/gcc/tree-ssa-propagate.c
@@ -863,7 +863,7 @@ static struct prop_stats_d prop_stats;
 /* Replace USE references in statement STMT with the values stored in
    PROP_VALUE. Return true if at least one reference was replaced.  */
 
-static bool
+bool
 replace_uses_in (gimple *stmt, ssa_prop_get_value_fn get_value)
 {
   bool replaced = false;
diff --git a/gcc/tree-ssa-propagate.h b/gcc/tree-ssa-propagate.h
index 30d66a9..1a96976 100644
--- a/gcc/tree-ssa-propagate.h
+++ b/gcc/tree-ssa-propagate.h
@@ -84,5 +84,6 @@ extern void propagate_value (use_operand_p, tree);
 extern void replace_exp (use_operand_p, tree);
 extern void propagate_tree_value (tree *, tree);
 extern void propagate_tree_value_into_stmt (gimple_stmt_iterator *, tree);
+extern bool replace_uses_in (gimple *stmt, ssa_prop_get_value_fn get_value);
 
 #endif /* _TREE_SSA_PROPAGATE_H  */
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index 45882c4..0002040 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -60,6 +60,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "case-cfn-macros.h"
 #include "params.h"
 #include "alloc-pool.h"
+#include "domwalk.h"
+#include "tree-cfgcleanup.h"
 
 #define VR_INITIALIZER { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL }
 
@@ -1455,44 +1457,17 @@ op_with_boolean_value_range_p (tree op)
 	  && integer_onep (vr->max));
 }
 
-/* Extract value range information from an ASSERT_EXPR EXPR and store
-   it in *VR_P.  */
+/* Extract value range information for VAR when (OP COND_CODE LIMIT) is
+   true and store it in *VR_P.  */
 
 static void
-extract_range_from_assert (value_range *vr_p, tree expr)
+extract_range_for_var_from_comparison_expr (tree var, enum tree_code cond_code,
+					    tree op, tree limit,
+					    value_range *vr_p)
 {
-  tree var, cond, limit, min, max, type;
+  tree  min, max, type;
   value_range *limit_vr;
-  enum tree_code cond_code;
-
-  var = ASSERT_EXPR_VAR (expr);
-  cond = ASSERT_EXPR_COND (expr);
-
-  gcc_assert (COMPARISON_CLASS_P (cond));
-
-  /* Find VAR in the ASSERT_EXPR conditional.  */
-  if (var == TREE_OPERAND (cond, 0)
-      || TREE_CODE (TREE_OPERAND (cond, 0)) == PLUS_EXPR
-      || TREE_CODE (TREE_OPERAND (cond, 0)) == NOP_EXPR)
-    {
-      /* If the predicate is of the form VAR COMP LIMIT, then we just
-	 take LIMIT from the RHS and use the same comparison code.  */
-      cond_code = TREE_CODE (cond);
-      limit = TREE_OPERAND (cond, 1);
-      cond = TREE_OPERAND (cond, 0);
-    }
-  else
-    {
-      /* If the predicate is of the form LIMIT COMP VAR, then we need
-	 to flip around the comparison code to create the proper range
-	 for VAR.  */
-      cond_code = swap_tree_comparison (TREE_CODE (cond));
-      limit = TREE_OPERAND (cond, 0);
-      cond = TREE_OPERAND (cond, 1);
-    }
-
   limit = avoid_overflow_infinity (limit);
-
   type = TREE_TYPE (var);
   gcc_assert (limit != var);
 
@@ -1538,15 +1513,15 @@ extract_range_from_assert (value_range *vr_p, tree expr)
      as well build the range [b_4, +INF] for it.
      One special case we handle is extracting a range from a
      range test encoded as (unsigned)var + CST <= limit.  */
-  if (TREE_CODE (cond) == NOP_EXPR
-      || TREE_CODE (cond) == PLUS_EXPR)
+  if (TREE_CODE (op) == NOP_EXPR
+      || TREE_CODE (op) == PLUS_EXPR)
     {
-      if (TREE_CODE (cond) == PLUS_EXPR)
+      if (TREE_CODE (op) == PLUS_EXPR)
         {
-          min = fold_build1 (NEGATE_EXPR, TREE_TYPE (TREE_OPERAND (cond, 1)),
-			     TREE_OPERAND (cond, 1));
+	  min = fold_build1 (NEGATE_EXPR, TREE_TYPE (TREE_OPERAND (op, 1)),
+			     TREE_OPERAND (op, 1));
           max = int_const_binop (PLUS_EXPR, limit, min);
-	  cond = TREE_OPERAND (cond, 0);
+	  op = TREE_OPERAND (op, 0);
 	}
       else
 	{
@@ -1730,6 +1705,41 @@ extract_range_from_assert (value_range *vr_p, tree expr)
   vrp_intersect_ranges (vr_p, get_value_range (var));
 }
 
+/* Extract value range information from an ASSERT_EXPR EXPR and store
+   it in *VR_P.  */
+
+static void
+extract_range_from_assert (value_range *vr_p, tree expr)
+{
+  tree var = ASSERT_EXPR_VAR (expr);
+  tree cond = ASSERT_EXPR_COND (expr);
+  tree limit, op;
+  enum tree_code cond_code;
+  gcc_assert (COMPARISON_CLASS_P (cond));
+
+  /* Find VAR in the ASSERT_EXPR conditional.  */
+  if (var == TREE_OPERAND (cond, 0)
+      || TREE_CODE (TREE_OPERAND (cond, 0)) == PLUS_EXPR
+      || TREE_CODE (TREE_OPERAND (cond, 0)) == NOP_EXPR)
+    {
+      /* If the predicate is of the form VAR COMP LIMIT, then we just
+	 take LIMIT from the RHS and use the same comparison code.  */
+      cond_code = TREE_CODE (cond);
+      limit = TREE_OPERAND (cond, 1);
+      op = TREE_OPERAND (cond, 0);
+    }
+  else
+    {
+      /* If the predicate is of the form LIMIT COMP VAR, then we need
+	 to flip around the comparison code to create the proper range
+	 for VAR.  */
+      cond_code = swap_tree_comparison (TREE_CODE (cond));
+      limit = TREE_OPERAND (cond, 0);
+      op = TREE_OPERAND (cond, 1);
+    }
+  extract_range_for_var_from_comparison_expr (var, cond_code, op,
+					      limit, vr_p);
+}
 
 /* Extract range information from SSA name VAR and store it in VR.  If
    VAR has an interesting range, use it.  Otherwise, create the
@@ -6947,19 +6957,24 @@ stmt_interesting_for_vrp (gimple *stmt)
   return false;
 }
 
-
-/* Initialize local data structures for VRP.  */
+/* Initialize VRP lattice.  */
 
 static void
-vrp_initialize (void)
+vrp_initialize_lattice ()
 {
-  basic_block bb;
-
   values_propagated = false;
   num_vr_values = num_ssa_names;
   vr_value = XCNEWVEC (value_range *, num_vr_values);
   vr_phi_edge_counts = XCNEWVEC (int, num_ssa_names);
   bitmap_obstack_initialize (&vrp_equiv_obstack);
+}
+
+/* Initialization required by ssa_propagate engine.  */
+
+static void
+vrp_initialize ()
+{
+  basic_block bb;
 
   FOR_EACH_BB_FN (bb, cfun)
     {
@@ -7010,6 +7025,8 @@ vrp_valueize (tree name)
     {
       value_range *vr = get_value_range (name);
       if (vr->type == VR_RANGE
+	  && (/*TREE_CODE (vr->min) == SSA_NAME
+	      ||*/ is_gimple_min_invariant (vr->min))
 	  && vrp_operand_equal_p (vr->min, vr->max))
 	return vr->min;
     }
@@ -10500,6 +10517,22 @@ finalize_jump_threads (void)
   delete equiv_stack;
 }
 
+/* Free VRP lattice.  */
+
+static void
+vrp_free_lattice ()
+{
+  /* Free allocated memory.  */
+  free (vr_value);
+  free (vr_phi_edge_counts);
+  bitmap_obstack_release (&vrp_equiv_obstack);
+  vrp_value_range_pool.release ();
+
+  /* So that we can distinguish between VRP data being available
+     and not available.  */
+  vr_value = NULL;
+  vr_phi_edge_counts = NULL;
+}
 
 /* Traverse all the blocks folding conditionals with known ranges.  */
 
@@ -10546,17 +10579,300 @@ vrp_finalize (bool warn_array_bounds_p)
   /* We must identify jump threading opportunities before we release
      the datastructures built by VRP.  */
   identify_jump_threads ();
+}
 
-  /* Free allocated memory.  */
-  free (vr_value);
-  free (vr_phi_edge_counts);
-  bitmap_obstack_release (&vrp_equiv_obstack);
-  vrp_value_range_pool.release ();
+/* evrp_dom_walker visits the basic blocks in the dominance order and set
+   the Value Ranges (VR) for SSA_NAMEs in the scope.  Use this VR to
+   discover more VRs.  */
 
-  /* So that we can distinguish between VRP data being available
-     and not available.  */
-  vr_value = NULL;
-  vr_phi_edge_counts = NULL;
+class evrp_dom_walker : public dom_walker
+{
+public:
+  evrp_dom_walker ()
+    : dom_walker (CDI_DOMINATORS), stack (10)
+    {
+      stmts_to_fixup.create (0);
+      need_eh_cleanup = BITMAP_ALLOC (NULL);
+    }
+  ~evrp_dom_walker ()
+    {
+      stmts_to_fixup.release ();
+      BITMAP_FREE (need_eh_cleanup);
+    }
+  virtual edge before_dom_children (basic_block);
+  virtual void after_dom_children (basic_block);
+  void push_value_range (const_tree var, value_range *vr);
+  value_range *pop_value_range (const_tree var);
+
+  /* Cond_stack holds the old VR.  */
+  auto_vec<std::pair <const_tree, value_range*> > stack;
+  bitmap need_eh_cleanup;
+  vec<gimple *> stmts_to_fixup;
+};
+
+/* See if there is any new scope is entered with new VR and set that VR to
+   ssa_name before visiting the statements in the scope.  */
+
+edge
+evrp_dom_walker::before_dom_children (basic_block bb)
+{
+  value_range *new_vr = NULL;
+  tree op0 = NULL_TREE;
+
+  push_value_range (NULL_TREE, NULL);
+  if (single_pred_p (bb))
+    {
+      edge e = single_pred_edge (bb);
+      value_range vr = VR_INITIALIZER;
+      gimple *stmt = last_stmt (e->src);
+      if (stmt
+	  && gimple_code (stmt) == GIMPLE_COND
+	  && (op0 = gimple_cond_lhs (stmt))
+	  && TREE_CODE (op0) == SSA_NAME
+	  && INTEGRAL_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt))))
+	{
+	  /* Entering a new scope.  Try to see if we can find a VR
+	     here.  */
+	  tree op1 = gimple_cond_rhs (stmt);
+	  tree_code code = gimple_cond_code (stmt);
+	  value_range *old_vr = get_value_range (op0);
+
+	  if (TREE_OVERFLOW_P (op1))
+	    op1 = drop_tree_overflow (op1);
+
+	  /* If condition is false, invert the cond.  */
+	  if (e->flags & EDGE_FALSE_VALUE)
+	    code = invert_tree_comparison (gimple_cond_code (stmt),
+					   HONOR_NANS (op0));
+	  /* Discover VR when condition is true.  */
+	  extract_range_for_var_from_comparison_expr (op0, code, op0, op1, &vr);
+	  if (old_vr->type == VR_RANGE || old_vr->type == VR_ANTI_RANGE)
+	    vrp_intersect_ranges (&vr, old_vr);
+
+	  /* If we found any usable VR, set the VR to ssa_name and create a
+	     PUSH old value in the stack with the old VR.  */
+	  if (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE)
+	    {
+	      new_vr = vrp_value_range_pool.allocate ();
+	      *new_vr = vr;
+	      push_value_range (op0, new_vr);
+	    }
+	}
+    }
+
+  /* Visit PHI stmts and discover any new VRs possible.  */
+  gimple_stmt_iterator gsi;
+  edge e;
+  edge_iterator ei;
+  bool has_unvisived_preds = false;
+
+  FOR_EACH_EDGE (e, ei, bb->preds)
+    if (!(e->src->flags & BB_VISITED))
+      {
+	has_unvisived_preds = true;
+	break;
+      }
+
+  for (gphi_iterator gpi = gsi_start_phis (bb);
+       !gsi_end_p (gpi); gsi_next (&gpi))
+    {
+      gphi *phi = gpi.phi ();
+      tree lhs = PHI_RESULT (phi);
+      value_range vr_result = VR_INITIALIZER;
+      if (!has_unvisived_preds
+	  && stmt_interesting_for_vrp (phi))
+	extract_range_from_phi_node (phi, &vr_result);
+      else
+	set_value_range_to_varying (&vr_result);
+      update_value_range (lhs, &vr_result);
+    }
+
+  /* Visit all other stmts and discover any new VRs possible.  */
+  for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+    {
+      gimple *stmt = gsi_stmt (gsi);
+      edge taken_edge;
+      tree output = NULL_TREE;
+      gimple *old_stmt = stmt;
+      bool was_noreturn = (is_gimple_call (stmt)
+			   && gimple_call_noreturn_p (stmt));
+
+      /* TODO, if found taken_edge, we should visit (return it) and travel
+	 again to improve VR as done in DOM/SCCVN optimizations.  It should
+	 be done carefully as stmts might prematurely leave a BB like
+	 in EH.  */
+      if (stmt_interesting_for_vrp (stmt))
+	{
+	  value_range vr = VR_INITIALIZER;
+	  extract_range_from_stmt (stmt, &taken_edge, &output, &vr);
+	  if (output
+	      && (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE))
+	    update_value_range (output, &vr);
+	  else
+	    {
+	      tree def;
+	      ssa_op_iter iter;
+	      FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_DEF)
+		set_value_range_to_varying (get_value_range (def));
+	    }
+
+	  /* Try folding stmts with the VR discovered.  */
+	  bool did_replace = replace_uses_in (stmt, vrp_valueize);
+	  if (fold_stmt (&gsi, follow_single_use_edges)
+	      || did_replace)
+	    update_stmt (gsi_stmt (gsi));
+
+	  if (did_replace)
+	    {
+	      /* If we cleaned up EH information from the statement,
+		 remove EH edges.  */
+	      if (maybe_clean_or_replace_eh_stmt (old_stmt, stmt))
+		bitmap_set_bit (need_eh_cleanup, bb->index);
+
+	      /* If we turned a not noreturn call into a noreturn one
+		 schedule it for fixup.  */
+	      if (!was_noreturn
+		  && is_gimple_call (stmt)
+		  && gimple_call_noreturn_p (stmt))
+		stmts_to_fixup.safe_push (stmt);
+
+	      if (gimple_assign_single_p (stmt))
+		{
+		  tree rhs = gimple_assign_rhs1 (stmt);
+		  if (TREE_CODE (rhs) == ADDR_EXPR)
+		    recompute_tree_invariant_for_addr_expr (rhs);
+		}
+	    }
+
+	  def_operand_p def_p = SINGLE_SSA_DEF_OPERAND (stmt, SSA_OP_DEF);
+	  /* Set the SSA with the value range.  */
+	  if (def_p
+	      && TREE_CODE (DEF_FROM_PTR (def_p)) == SSA_NAME
+	      && INTEGRAL_TYPE_P (TREE_TYPE (DEF_FROM_PTR (def_p))))
+	    {
+	      tree def = DEF_FROM_PTR (def_p);
+	      value_range *vr = get_value_range (def);
+
+	      if ((vr->type == VR_RANGE
+		   || vr->type == VR_ANTI_RANGE)
+		  && (TREE_CODE (vr->min) == INTEGER_CST)
+		  && (TREE_CODE (vr->max) == INTEGER_CST))
+		set_range_info (def, vr->type, vr->min, vr->max);
+	    }
+	}
+      else
+	{
+	  tree def;
+	  ssa_op_iter iter;
+	  FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_DEF)
+	    set_value_range_to_varying (get_value_range (def));
+	}
+    }
+  bb->flags |= BB_VISITED;
+  return NULL;
+}
+
+/* Restore/pop VRs valid only for BB when we leave BB.  */
+
+void
+evrp_dom_walker::after_dom_children (basic_block bb ATTRIBUTE_UNUSED)
+{
+  gcc_checking_assert (!stack.is_empty ());
+  while (stack.last ().first != NULL_TREE)
+    pop_value_range (stack.last ().first);
+  pop_value_range (stack.last ().first);
+}
+
+/* Push the Value Range of VAR to the stack and update it with new VR.  */
+
+void
+evrp_dom_walker::push_value_range (const_tree var, value_range *vr)
+{
+  if (vr != NULL)
+    {
+      unsigned ver = SSA_NAME_VERSION (var);
+      gcc_checking_assert (vr_value);
+      stack.safe_push (std::make_pair (var, vr_value[ver]));
+
+      if (ver < num_vr_values)
+	vr_value[ver] = vr;
+    }
+  else
+    stack.safe_push (std::make_pair (var, vr));
+}
+
+/* Pop the Value Range from the vrp_stack and update VAR with it.  */
+
+value_range *
+evrp_dom_walker::pop_value_range (const_tree var)
+{
+  value_range *vr = stack.last ().second;
+  if (vr != NULL)
+    {
+      unsigned ver = SSA_NAME_VERSION (var);
+      gcc_checking_assert (var == stack.last ().first);
+      gcc_checking_assert (vr_value);
+
+      if (ver < num_vr_values)
+	vr_value[ver] = vr;
+    }
+  stack.pop ();
+  return vr;
+}
+
+
+/* Main entry point for the early vrp pass which is a simplified non-iterative
+   version of vrp where basic blocks are visited in dominance order.  Value
+   ranges discovered in early vrp will also be used by ipa-vrp.  */
+
+static unsigned int
+execute_early_vrp ()
+{
+  edge e;
+  edge_iterator ei;
+  basic_block bb;
+
+  loop_optimizer_init (LOOPS_NORMAL | LOOPS_HAVE_RECORDED_EXITS);
+  rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa);
+  scev_initialize ();
+  calculate_dominance_info (CDI_DOMINATORS);
+  FOR_EACH_BB_FN (bb, cfun)
+    {
+      bb->flags &= ~BB_VISITED;
+      FOR_EACH_EDGE (e, ei, bb->preds)
+	e->flags |= EDGE_EXECUTABLE;
+    }
+  vrp_initialize_lattice ();
+
+  /* Walk stmts in dominance order and propagate VRP.  */
+  evrp_dom_walker walker;
+  walker.walk (ENTRY_BLOCK_PTR_FOR_FN (cfun));
+
+  if (!bitmap_empty_p (walker.need_eh_cleanup))
+    gimple_purge_all_dead_eh_edges (walker.need_eh_cleanup);
+
+  /* Fixup stmts that became noreturn calls.  This may require splitting
+     blocks and thus isn't possible during the dominator walk.  Do this
+     in reverse order so we don't inadvertedly remove a stmt we want to
+     fixup by visiting a dominating now noreturn call first.  */
+  while (!walker.stmts_to_fixup.is_empty ())
+    {
+      gimple *stmt = walker.stmts_to_fixup.pop ();
+      fixup_noreturn_call (stmt);
+    }
+
+  if (dump_file)
+    {
+      fprintf (dump_file, "\nValue ranges after Early VRP:\n\n");
+      dump_all_value_ranges (dump_file);
+      fprintf (dump_file, "\n");
+    }
+  vrp_free_lattice ();
+  scev_finalize ();
+  loop_optimizer_finalize ();
+  FOR_EACH_BB_FN (bb, cfun)
+    bb->flags &= ~BB_VISITED;
+  return 0;
 }
 
 
@@ -10627,9 +10943,11 @@ execute_vrp (bool warn_array_bounds_p)
   /* For visiting PHI nodes we need EDGE_DFS_BACK computed.  */
   mark_dfs_back_edges ();
 
+  vrp_initialize_lattice ();
   vrp_initialize ();
   ssa_propagate (vrp_visit_stmt, vrp_visit_phi_node);
   vrp_finalize (warn_array_bounds_p);
+  vrp_free_lattice ();
 
   free_numbers_of_iterations_estimates (cfun);
 
@@ -10727,3 +11045,44 @@ make_pass_vrp (gcc::context *ctxt)
 {
   return new pass_vrp (ctxt);
 }
+
+namespace {
+
+const pass_data pass_data_early_vrp =
+{
+  GIMPLE_PASS, /* type */
+  "evrp", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_TREE_EARLY_VRP, /* tv_id */
+  PROP_ssa, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  ( TODO_cleanup_cfg | TODO_update_ssa | TODO_verify_all ),
+};
+
+class pass_early_vrp : public gimple_opt_pass
+{
+public:
+  pass_early_vrp (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_early_vrp, ctxt)
+    {}
+
+  /* opt_pass methods: */
+  opt_pass * clone () { return new pass_early_vrp (m_ctxt); }
+  virtual bool gate (function *)
+    {
+      return flag_tree_vrp != 0;
+    }
+  virtual unsigned int execute (function *)
+    { return execute_early_vrp (); }
+
+}; // class pass_vrp
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_early_vrp (gcc::context *ctxt)
+{
+  return new pass_early_vrp (ctxt);
+}
+
-- 
2.7.4


^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Early VRP Implementation
  2016-09-18 23:40                                         ` kugan
@ 2016-09-19 13:30                                           ` Richard Biener
  2016-09-20  5:48                                             ` kugan
  0 siblings, 1 reply; 67+ messages in thread
From: Richard Biener @ 2016-09-19 13:30 UTC (permalink / raw)
  To: kugan; +Cc: Andrew Pinski, gcc-patches, Jan Hubicka, Martin Jambor

On Sun, Sep 18, 2016 at 10:50 PM, kugan
<kugan.vivekanandarajah@linaro.org> wrote:
> Hi Richard,
>
>
>
> On 16/09/16 20:21, Richard Biener wrote:
>>
>> On Fri, Sep 16, 2016 at 7:59 AM, kugan
>> <kugan.vivekanandarajah@linaro.org> wrote:
>>>
>>> Hi Richard,
>>>
>>> Thanks for the review.
>>>
>>> On 14/09/16 22:04, Richard Biener wrote:
>>>>
>>>>
>>>> On Tue, Aug 23, 2016 at 4:11 AM, Kugan Vivekanandarajah
>>>> <kugan.vivekanandarajah@linaro.org> wrote:
>>>>>
>>>>>
>>>>> Hi,
>>>>>
>>>>> On 19 August 2016 at 21:41, Richard Biener <richard.guenther@gmail.com>
>>>>> wrote:
>>>>>>
>>>>>>
>>>>>> On Tue, Aug 16, 2016 at 9:45 AM, kugan
>>>>>> <kugan.vivekanandarajah@linaro.org> wrote:
>>>>>>>
>>>>>>>
>>>>>>> Hi Richard,
>>>
>>>
>>>
>>>>>>> I am now having -ftree-evrp which is enabled all the time. But This
>>>>>>> will
>>>>>>> only be used for disabling the early-vrp. That is, early-vrp will be
>>>>>>> run
>>>>>>> when ftree-vrp is enabled and ftree-evrp is not explicitly disabled.
>>>>>>> Is
>>>>>>> this
>>>>>>> OK?
>>>>>>
>>>>>>
>>>>>>
>>>>>> Why would one want to disable early-vrp?  I see you do this in the
>>>>>> testsuite
>>>>>> for non-early VRP unit-tests but using -fdisable-tree-evrp1 there
>>>>>> would be ok as well.
>>>>>
>>>>>
>>>>>
>>>>> Removed it altogether. I though that you wanted a way to disable
>>>>> early-vrp for testing purposes.
>>>>
>>>>
>>>>
>>>> But there is via the generic -fdisable-tree-DUMPFILE way.
>>>
>>>
>>>
>>> OK. I didnt know about that.
>>>
>>>
>>>>>> Note that you want to have a custom valueize function instead of just
>>>>>> follow_single_use_edges as you want to valueize all SSA names
>>>>>> according
>>>>>> to their lattice value (if it has a single value).  You can use
>>>>>> vrp_valueize
>>>>>> for this though that gets you non-single-use edge following as well.
>>>>>> Eventually it's going to be cleaner to do what the SSA propagator does
>>>>>> and
>>>>>> before folding do
>>>>>>
>>>>>>    did_replace = replace_uses_in (stmt, vrp_valueize);
>>>>>>    if (fold_stmt (&gsi, follow_single_use_edges)
>>>>>>        || did_replace)
>>>>>>      update_stmt (gsi_stmt (gsi));
>>>>>>
>>>>>> exporting replace_uses_in for this is ok.  I guess I prefer this for
>>>>>> now.
>>>>>
>>>>>
>>>>>
>>>>> I also added the above.  I noticed that I need
>>>>> recompute_tree_invariant_for_addr_expr as in ssa_propagate. My initial
>>>>> implementation also had gimple_purge_all_dead_eh_edges and
>>>>> fixup_noreturn_call as in ssa_propagat but I thinj that is not needed
>>>>> as it would be done at the end of the pass.
>>>>
>>>>
>>>>
>>>> I don't see this being done at the end of the pass.  So please
>>>> re-instantiate
>>>> that parts.
>>>
>>>
>>>
>>> I have copied these part as well.
>>>
>>>>> With this I noticed more stmts are folded before vrp1. This required
>>>>> me to adjust some testcases.
>>>>>
>>>>>>
>>>>>> Overall this now looks good apart from the folding and the
>>>>>> VR_INITIALIZER thing.
>>>>>>
>>>>>> You can commit the already approved refactoring changes and combine
>>>>>> this
>>>>>> patch with the struct value_range move, this way I can more easily
>>>>>> look
>>>>>> into
>>>>>> issues with the UNDEFINED thing if you can come up with a testcase
>>>>>> that
>>>>>> doesn't work.
>>>>>>
>>>>>
>>>>> I have now committed all the dependent patches.
>>>>>
>>>>> Attached patch passes regression and bootstrap except pr33738.C. This
>>>>> is an unrelated issue as discussed in
>>>>> https://gcc.gnu.org/ml/gcc-patches/2016-08/msg01386.html
>>>>>
>>>>> Is this OK?
>>>>
>>>>
>>>>
>>>> +/* Initialize local data structures for VRP.  If DOM_P is true,
>>>> +   we will be calling this from early_vrp where value range propagation
>>>> +   is done by visiting stmts in dominator tree.  ssa_propagate engine
>>>> +   is not used in this case and that part of the ininitialization will
>>>> +   be skipped.  */
>>>> +
>>>> +static void
>>>> +vrp_initialize ()
>>>>
>>>> comment needs updating now.
>>>>
>>> Done.
>>>
>>>>
>>>>  static void
>>>> -extract_range_from_phi_node (gphi *phi, value_range *vr_result)
>>>> +extract_range_from_phi_node (gphi *phi, value_range *vr_result,
>>>> +                            bool early_vrp_p)
>>>>  {
>>>>
>>>>
>>>> I don't think you need this changes now that you have
>>>> stmt_visit_phi_node_in_dom_p
>>>> guarding its call.
>>>
>>>
>>>
>>> OK removed it. That also mean I had to put scev_* in the early_vrp.
>>>
>>>
>>>
>>>> +static bool
>>>> +stmt_visit_phi_node_in_dom_p (gphi *phi)
>>>> +{
>>>> +  ssa_op_iter iter;
>>>> +  use_operand_p oprnd;
>>>> +  tree op;
>>>> +  value_range *vr;
>>>> +  FOR_EACH_PHI_ARG (oprnd, phi, iter, SSA_OP_USE)
>>>> +    {
>>>> +      op = USE_FROM_PTR (oprnd);
>>>> +      if (TREE_CODE (op) == SSA_NAME)
>>>> +       {
>>>> +         vr = get_value_range (op);
>>>> +         if (vr->type == VR_UNDEFINED)
>>>> +           return false;
>>>> +       }
>>>> +    }
>>>>
>>>> I think this is overly conservative in never allowing UNDEFINED on PHI
>>>> node args (even if the def was actually visited).  I think that the most
>>>> easy way to improve this bit would be to actually track visited blocks.
>>>> You already set the EDGE_EXECUTABLE flag on edges so you could
>>>> clear BB_VISITED on all blocks and set it in the before_dom_children
>>>> hook (at the end).  Then the above can be folded into the PHI visiting:
>>>>
>>>>     bool has_unvisited_pred = false;
>>>>     FOR_EACH_EDGE (e, ei, bb->preds)
>>>>        if (!(e->src->flags & BB_VISITED))
>>>>          {
>>>>             has_unvisited_preds = true;
>>>>             break;
>>>>          }
>>>>
>>> OK done.
>>>
>>> I also had to check for uninitialized variables that will have
>>> VR_UNDEFINED
>>> as range. We do not visit GIMPLE_NOP.
>>
>>
>> But VR_UNDEFINED of uninitialized variables is fine to use.
>
>
> Indeed. I was really trying to fix another problem with this.
>
> The real problem I am facing is:
>
> When we have a PHI stmt with one argument as symbolic VR_RANGE and another
> as VR_UNDEFINED, we will copy VR_RANGE to the PHI result.
>
> When we fold the uses of the PHI result with vrp_valueize, we will assign
> the symbol from VR_RANGE if that is of the form [a, a].
>
> However, in replace_uses_in, we dont see if the SSA definition dominates the
> gimple that uses it. This some times results in ICE.

Indeed -- ccp_lattice_meet avoids this by not merging UNDEF and SSA to SSA.

VRP uses op_with_constant_singleton_value_range for the valueization at
substitute_and_fold time which only substitutes constants.

> For now, in the vrp_valueize, I have commented out the SSA_NAME part (as
> shown in the attached patch). With that I can bootstrap and regression test
> the patch.
>
> The fix is to either:
>
> 1. Remove SSA_NAME from vrp_valueize. Currently we use vrp_valueize with
> gimple_fold_stmt_to_constant_1 and accepts only is_gimple_min_invariant.
> Therefore maybe SSA_NAME is not needed?

Yeah, technically it is not needed.

> 2. Or, in replace_uses_in, see if the stmt dominates operand definition
> before replacing.

We need to treat the valueization as a "value number" and separately
keep track of available DEFs we can substitute.  See for example how
FRE/PRE handle this in eliminate_dom_walker.  The substitute-and-fold
DOM walker would need to be adjusted similarly (and your copy of it
in DOM VRP).

Short-cutting this at vrp_valueize will remove some valid foldings to
constants but I think you can simply use op_with_constant_singleton_value_range
for the replace_uses_in call.

The patch is ok with that change.

Thanks,
Richard.

>>>
>>>> +  /* Visit PHI stmts and discover any new VRs possible.  */
>>>> +  gimple_stmt_iterator gsi;
>>>> +  for (gphi_iterator gpi = gsi_start_phis (bb);
>>>> +       !gsi_end_p (gpi); gsi_next (&gpi))
>>>> +    {
>>>> +      gphi *phi = gpi.phi ();
>>>> +      tree lhs = PHI_RESULT (phi);
>>>> +      value_range vr_result = VR_INITIALIZER;
>>>> +      if (! has_unvisived_preds
>>>>            && stmt_interesting_for_vrp (phi)
>>>> +         && stmt_visit_phi_node_in_dom_p (phi))
>>
>>
>> failed to remove this call to stmt_visit_phi_node_in_dom_p -- whether we
>> need to
>> drop to varying is a property that is the same for all PHI nodes in a
>> block.
>>
> Done.
>
>>>> +       extract_range_from_phi_node (phi, &vr_result, true);
>>>> +      else
>>>> +       set_value_range_to_varying (&vr_result);
>>>> +      update_value_range (lhs, &vr_result);
>>>> +    }
>>>>
>>>> due to a bug in IRA you need to make sure to un-set BB_VISITED after
>>>> early-vrp is finished again.
>>>
>>>
>>> OK. Done.
>>
>>
>> You set BB_VISITED in after_dom_children -- that is too late, please
>> set it at the end
>> of before_dom_children.  Otherwise it pessimizes handling of the PHIs
>> in the merge
>> block of a diamond in case the PHI args are defined in the immediate
>> dominator.
>>
>> As said you need to clear BB_VISITED at the start of evrp as well
>> (clearing at the end
>> is just a workaround for a IRA bug).
>
> Done.
>
>>>>
>>>> +         /* Try folding stmts with the VR discovered.  */
>>>> +         bool did_replace = replace_uses_in (stmt, evrp_valueize);
>>>> +         if (fold_stmt (&gsi, follow_single_use_edges)
>>>> +             || did_replace)
>>>> +           update_stmt (gsi_stmt (gsi));
>>>>
>>>> you should be able to re-use vrp_valueize here.
>>>
>>>
>>> This issue is vrp_valueize accepts ranges such as [VAR + CST, VAR + CST]
>>> which we can not set.
>>
>>
>> Oh - that looks like sth we need to fix anyway then.  May I suggest to
>> change
>> vrp_valueize to do
>>
>>          && (TREE_CODE (vr->min) == SSA_NAME
>>                 || is_gimple_min_invariant (TREE_CODE (vr->min)))
>>
>> which also allows [&a, &a] like constants.
>
>
> Please see the error above.
>
>
>>>>
>>>> +         def_operand_p def_p = SINGLE_SSA_DEF_OPERAND (stmt,
>>>> SSA_OP_DEF);
>>>> +         /* Set the SSA with the value range.  */
>>>> +         if (def_p
>>>> +             && TREE_CODE (DEF_FROM_PTR (def_p)) == SSA_NAME
>>>> +             && INTEGRAL_TYPE_P (TREE_TYPE (DEF_FROM_PTR (def_p))))
>>>> +           {
>>>> +             tree def = DEF_FROM_PTR (def_p);
>>>> +             unsigned ver = SSA_NAME_VERSION (def);
>>>> +             if ((vr_value[ver]->type == VR_RANGE
>>>>
>>>> Use get_value_range () please, not direct access to vr_value.
>>>>
>>> Done.
>>>
>>>> +                  || vr_value[ver]->type == VR_ANTI_RANGE)
>>>> +                 && (TREE_CODE (vr_value[ver]->min) == INTEGER_CST)
>>>> +                 && (TREE_CODE (vr_value[ver]->max) == INTEGER_CST))
>>>> +               set_range_info (def, vr_value[ver]->type,
>>>> vr_value[ver]->min,
>>>> +                               vr_value[ver]->max);
>>>> +           }
>>>>
>>>> Otherwise the patch looks good now (with a lot of improvement
>>>> possibilities of course).
>>>
>>>
>>> I will work on the improvement after this goes in.
>>>
>>> Bootstrapped and regression tested on x86_64-linux-gnu. Does this looks
>>> OK?
>>
>>
>> Please remove no-op changes like
>
> Done.
>
>
>> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c
>> b/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c
>> index 7efdd63..3a433d6 100644
>> --- a/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c
>> +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c
>> @@ -3,7 +3,7 @@
>>     known to be zero after entering the first two "if" statements.  */
>>
>>  /* { dg-do compile } */
>> -/* { dg-options "-O2 -fdump-tree-vrp1" } */
>> +/* { dg-options "-O2  -fdump-tree-vrp1" } */
>>
>>  void link_error (void);
>>
>> @@ -21,4 +21,4 @@ foo (int *p, int q)
>>      }
>>  }
>>
>> -/* { dg-final { scan-tree-dump-times "Folding predicate r_.* != 0B to
>> 0" 1 "vrp1" } } */
>> +/* { dg-final { scan-tree-dump-times "link_error" 0 "vrp1" } } */
>> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c
>> b/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c
>> index dcf9148..c4fda8b 100644
>> --- a/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c
>> +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c
>> @@ -3,7 +3,7 @@
>>     Check that VRP now gets ranges from BIT_AND_EXPRs.  */
>>
>>  /* { dg-do compile } */
>> -/* { dg-options "-O2 -fno-tree-ccp -fdump-tree-vrp1" } */
>> +/* { dg-options "-O2 -fno-tree-ccp -fdump-tree-vrp" } */
>>
>>  int
>>  foo (int a)
>>
>>
>> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp46.c
>> b/gcc/testsuite/gcc.dg/tree-ssa/vrp46.c
>> index d3c9ed1..5b279a1 100644
>> --- a/gcc/testsuite/gcc.dg/tree-ssa/vrp46.c
>> +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp46.c
>> @@ -27,6 +27,5 @@ func_18 ( int t )
>>      }
>>  }
>>
>> -/* There should be a single if left.  */
>>
>> -/* { dg-final { scan-tree-dump-times "if" 1 "vrp1" } } */
>> +/* { dg-final { scan-tree-dump-times "if" 0 "vrp1" } } */
>>
>> I'm curious -- this is not a dg-run testcase but did you investigate this
>> isn't generating wrong code now?  At least I can't see how
>> the if (1 & (t % rhs)) test could vanish.
>
> Indeed.This was a mistake and fixed it.
>
>
>> I hope we'll get GIMPLE unit testing finished for GCC 7 so we can add
>> separate
>> unit-tests for VRP and EVRP.
>
>
> I will have a look at it.
>
> Thanks,
> Kugan
>
>
>> Thanks,
>> Richard.
>>
>>
>>> Thanks,
>>> Kugan
>>>
>>>
>>>
>>>>
>>>> Thanks and sorry for the delay,
>>>> Richard.
>>>>
>>>>> Thanks,
>>>>> Kugan
>>>>>
>>>>>
>>>>>> Thanks,
>>>>>> Richard.
>>>>>>
>>>>>>> I also noticed that g++.dg/warn/pr33738.C testcase is now failing.
>>>>>>> This
>>>>>>> is
>>>>>>> because, with early-vrp setting value range ccp2 is optimizing
>>>>>>> without
>>>>>>> issuing a warning. I will look into it.
>>>>>>>
>>>>>>> bootstrap and regression testing is in progress.
>>>>>>>
>>>>>>> Thanks,
>>>>>>> Kugan

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [RFC][IPA-VRP] Early VRP Implementation
  2016-09-19 13:30                                           ` Richard Biener
@ 2016-09-20  5:48                                             ` kugan
  0 siblings, 0 replies; 67+ messages in thread
From: kugan @ 2016-09-20  5:48 UTC (permalink / raw)
  To: Richard Biener; +Cc: Andrew Pinski, gcc-patches, Jan Hubicka, Martin Jambor

[-- Attachment #1: Type: text/plain, Size: 14554 bytes --]

Hi Richard,

Thanks for the review.

On 19/09/16 22:56, Richard Biener wrote:
> On Sun, Sep 18, 2016 at 10:50 PM, kugan
> <kugan.vivekanandarajah@linaro.org> wrote:
>> Hi Richard,
>>
>>
>>
>> On 16/09/16 20:21, Richard Biener wrote:
>>>
>>> On Fri, Sep 16, 2016 at 7:59 AM, kugan
>>> <kugan.vivekanandarajah@linaro.org> wrote:
>>>>
>>>> Hi Richard,
>>>>
>>>> Thanks for the review.
>>>>
>>>> On 14/09/16 22:04, Richard Biener wrote:
>>>>>
>>>>>
>>>>> On Tue, Aug 23, 2016 at 4:11 AM, Kugan Vivekanandarajah
>>>>> <kugan.vivekanandarajah@linaro.org> wrote:
>>>>>>
>>>>>>
>>>>>> Hi,
>>>>>>
>>>>>> On 19 August 2016 at 21:41, Richard Biener <richard.guenther@gmail.com>
>>>>>> wrote:
>>>>>>>
>>>>>>>
>>>>>>> On Tue, Aug 16, 2016 at 9:45 AM, kugan
>>>>>>> <kugan.vivekanandarajah@linaro.org> wrote:
>>>>>>>>
>>>>>>>>
>>>>>>>> Hi Richard,
>>>>
>>>>
>>>>
>>>>>>>> I am now having -ftree-evrp which is enabled all the time. But This
>>>>>>>> will
>>>>>>>> only be used for disabling the early-vrp. That is, early-vrp will be
>>>>>>>> run
>>>>>>>> when ftree-vrp is enabled and ftree-evrp is not explicitly disabled.
>>>>>>>> Is
>>>>>>>> this
>>>>>>>> OK?
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> Why would one want to disable early-vrp?  I see you do this in the
>>>>>>> testsuite
>>>>>>> for non-early VRP unit-tests but using -fdisable-tree-evrp1 there
>>>>>>> would be ok as well.
>>>>>>
>>>>>>
>>>>>>
>>>>>> Removed it altogether. I though that you wanted a way to disable
>>>>>> early-vrp for testing purposes.
>>>>>
>>>>>
>>>>>
>>>>> But there is via the generic -fdisable-tree-DUMPFILE way.
>>>>
>>>>
>>>>
>>>> OK. I didnt know about that.
>>>>
>>>>
>>>>>>> Note that you want to have a custom valueize function instead of just
>>>>>>> follow_single_use_edges as you want to valueize all SSA names
>>>>>>> according
>>>>>>> to their lattice value (if it has a single value).  You can use
>>>>>>> vrp_valueize
>>>>>>> for this though that gets you non-single-use edge following as well.
>>>>>>> Eventually it's going to be cleaner to do what the SSA propagator does
>>>>>>> and
>>>>>>> before folding do
>>>>>>>
>>>>>>>    did_replace = replace_uses_in (stmt, vrp_valueize);
>>>>>>>    if (fold_stmt (&gsi, follow_single_use_edges)
>>>>>>>        || did_replace)
>>>>>>>      update_stmt (gsi_stmt (gsi));
>>>>>>>
>>>>>>> exporting replace_uses_in for this is ok.  I guess I prefer this for
>>>>>>> now.
>>>>>>
>>>>>>
>>>>>>
>>>>>> I also added the above.  I noticed that I need
>>>>>> recompute_tree_invariant_for_addr_expr as in ssa_propagate. My initial
>>>>>> implementation also had gimple_purge_all_dead_eh_edges and
>>>>>> fixup_noreturn_call as in ssa_propagat but I thinj that is not needed
>>>>>> as it would be done at the end of the pass.
>>>>>
>>>>>
>>>>>
>>>>> I don't see this being done at the end of the pass.  So please
>>>>> re-instantiate
>>>>> that parts.
>>>>
>>>>
>>>>
>>>> I have copied these part as well.
>>>>
>>>>>> With this I noticed more stmts are folded before vrp1. This required
>>>>>> me to adjust some testcases.
>>>>>>
>>>>>>>
>>>>>>> Overall this now looks good apart from the folding and the
>>>>>>> VR_INITIALIZER thing.
>>>>>>>
>>>>>>> You can commit the already approved refactoring changes and combine
>>>>>>> this
>>>>>>> patch with the struct value_range move, this way I can more easily
>>>>>>> look
>>>>>>> into
>>>>>>> issues with the UNDEFINED thing if you can come up with a testcase
>>>>>>> that
>>>>>>> doesn't work.
>>>>>>>
>>>>>>
>>>>>> I have now committed all the dependent patches.
>>>>>>
>>>>>> Attached patch passes regression and bootstrap except pr33738.C. This
>>>>>> is an unrelated issue as discussed in
>>>>>> https://gcc.gnu.org/ml/gcc-patches/2016-08/msg01386.html
>>>>>>
>>>>>> Is this OK?
>>>>>
>>>>>
>>>>>
>>>>> +/* Initialize local data structures for VRP.  If DOM_P is true,
>>>>> +   we will be calling this from early_vrp where value range propagation
>>>>> +   is done by visiting stmts in dominator tree.  ssa_propagate engine
>>>>> +   is not used in this case and that part of the ininitialization will
>>>>> +   be skipped.  */
>>>>> +
>>>>> +static void
>>>>> +vrp_initialize ()
>>>>>
>>>>> comment needs updating now.
>>>>>
>>>> Done.
>>>>
>>>>>
>>>>>  static void
>>>>> -extract_range_from_phi_node (gphi *phi, value_range *vr_result)
>>>>> +extract_range_from_phi_node (gphi *phi, value_range *vr_result,
>>>>> +                            bool early_vrp_p)
>>>>>  {
>>>>>
>>>>>
>>>>> I don't think you need this changes now that you have
>>>>> stmt_visit_phi_node_in_dom_p
>>>>> guarding its call.
>>>>
>>>>
>>>>
>>>> OK removed it. That also mean I had to put scev_* in the early_vrp.
>>>>
>>>>
>>>>
>>>>> +static bool
>>>>> +stmt_visit_phi_node_in_dom_p (gphi *phi)
>>>>> +{
>>>>> +  ssa_op_iter iter;
>>>>> +  use_operand_p oprnd;
>>>>> +  tree op;
>>>>> +  value_range *vr;
>>>>> +  FOR_EACH_PHI_ARG (oprnd, phi, iter, SSA_OP_USE)
>>>>> +    {
>>>>> +      op = USE_FROM_PTR (oprnd);
>>>>> +      if (TREE_CODE (op) == SSA_NAME)
>>>>> +       {
>>>>> +         vr = get_value_range (op);
>>>>> +         if (vr->type == VR_UNDEFINED)
>>>>> +           return false;
>>>>> +       }
>>>>> +    }
>>>>>
>>>>> I think this is overly conservative in never allowing UNDEFINED on PHI
>>>>> node args (even if the def was actually visited).  I think that the most
>>>>> easy way to improve this bit would be to actually track visited blocks.
>>>>> You already set the EDGE_EXECUTABLE flag on edges so you could
>>>>> clear BB_VISITED on all blocks and set it in the before_dom_children
>>>>> hook (at the end).  Then the above can be folded into the PHI visiting:
>>>>>
>>>>>     bool has_unvisited_pred = false;
>>>>>     FOR_EACH_EDGE (e, ei, bb->preds)
>>>>>        if (!(e->src->flags & BB_VISITED))
>>>>>          {
>>>>>             has_unvisited_preds = true;
>>>>>             break;
>>>>>          }
>>>>>
>>>> OK done.
>>>>
>>>> I also had to check for uninitialized variables that will have
>>>> VR_UNDEFINED
>>>> as range. We do not visit GIMPLE_NOP.
>>>
>>>
>>> But VR_UNDEFINED of uninitialized variables is fine to use.
>>
>>
>> Indeed. I was really trying to fix another problem with this.
>>
>> The real problem I am facing is:
>>
>> When we have a PHI stmt with one argument as symbolic VR_RANGE and another
>> as VR_UNDEFINED, we will copy VR_RANGE to the PHI result.
>>
>> When we fold the uses of the PHI result with vrp_valueize, we will assign
>> the symbol from VR_RANGE if that is of the form [a, a].
>>
>> However, in replace_uses_in, we dont see if the SSA definition dominates the
>> gimple that uses it. This some times results in ICE.
>
> Indeed -- ccp_lattice_meet avoids this by not merging UNDEF and SSA to SSA.
>
> VRP uses op_with_constant_singleton_value_range for the valueization at
> substitute_and_fold time which only substitutes constants.
>
>> For now, in the vrp_valueize, I have commented out the SSA_NAME part (as
>> shown in the attached patch). With that I can bootstrap and regression test
>> the patch.
>>
>> The fix is to either:
>>
>> 1. Remove SSA_NAME from vrp_valueize. Currently we use vrp_valueize with
>> gimple_fold_stmt_to_constant_1 and accepts only is_gimple_min_invariant.
>> Therefore maybe SSA_NAME is not needed?
>
> Yeah, technically it is not needed.
>
>> 2. Or, in replace_uses_in, see if the stmt dominates operand definition
>> before replacing.
>
> We need to treat the valueization as a "value number" and separately
> keep track of available DEFs we can substitute.  See for example how
> FRE/PRE handle this in eliminate_dom_walker.  The substitute-and-fold
> DOM walker would need to be adjusted similarly (and your copy of it
> in DOM VRP).
>
> Short-cutting this at vrp_valueize will remove some valid foldings to
> constants but I think you can simply use op_with_constant_singleton_value_range
> for the replace_uses_in call.
>
> The patch is ok with that change.

Attached is the patch based on the above comments. I have marked 
gcc/testsuite/g++.dg/warn/pr33738.C as XFAIL and will try to fix this 
based on the discussion from 
https://gcc.gnu.org/ml/gcc-patches/2016-08/msg01386.html

I will commit it after fresh bootstrap and regression testing.

Thanks,
Kugan


>
> Thanks,
> Richard.
>
>>>>
>>>>> +  /* Visit PHI stmts and discover any new VRs possible.  */
>>>>> +  gimple_stmt_iterator gsi;
>>>>> +  for (gphi_iterator gpi = gsi_start_phis (bb);
>>>>> +       !gsi_end_p (gpi); gsi_next (&gpi))
>>>>> +    {
>>>>> +      gphi *phi = gpi.phi ();
>>>>> +      tree lhs = PHI_RESULT (phi);
>>>>> +      value_range vr_result = VR_INITIALIZER;
>>>>> +      if (! has_unvisived_preds
>>>>>            && stmt_interesting_for_vrp (phi)
>>>>> +         && stmt_visit_phi_node_in_dom_p (phi))
>>>
>>>
>>> failed to remove this call to stmt_visit_phi_node_in_dom_p -- whether we
>>> need to
>>> drop to varying is a property that is the same for all PHI nodes in a
>>> block.
>>>
>> Done.
>>
>>>>> +       extract_range_from_phi_node (phi, &vr_result, true);
>>>>> +      else
>>>>> +       set_value_range_to_varying (&vr_result);
>>>>> +      update_value_range (lhs, &vr_result);
>>>>> +    }
>>>>>
>>>>> due to a bug in IRA you need to make sure to un-set BB_VISITED after
>>>>> early-vrp is finished again.
>>>>
>>>>
>>>> OK. Done.
>>>
>>>
>>> You set BB_VISITED in after_dom_children -- that is too late, please
>>> set it at the end
>>> of before_dom_children.  Otherwise it pessimizes handling of the PHIs
>>> in the merge
>>> block of a diamond in case the PHI args are defined in the immediate
>>> dominator.
>>>
>>> As said you need to clear BB_VISITED at the start of evrp as well
>>> (clearing at the end
>>> is just a workaround for a IRA bug).
>>
>> Done.
>>
>>>>>
>>>>> +         /* Try folding stmts with the VR discovered.  */
>>>>> +         bool did_replace = replace_uses_in (stmt, evrp_valueize);
>>>>> +         if (fold_stmt (&gsi, follow_single_use_edges)
>>>>> +             || did_replace)
>>>>> +           update_stmt (gsi_stmt (gsi));
>>>>>
>>>>> you should be able to re-use vrp_valueize here.
>>>>
>>>>
>>>> This issue is vrp_valueize accepts ranges such as [VAR + CST, VAR + CST]
>>>> which we can not set.
>>>
>>>
>>> Oh - that looks like sth we need to fix anyway then.  May I suggest to
>>> change
>>> vrp_valueize to do
>>>
>>>          && (TREE_CODE (vr->min) == SSA_NAME
>>>                 || is_gimple_min_invariant (TREE_CODE (vr->min)))
>>>
>>> which also allows [&a, &a] like constants.
>>
>>
>> Please see the error above.
>>
>>
>>>>>
>>>>> +         def_operand_p def_p = SINGLE_SSA_DEF_OPERAND (stmt,
>>>>> SSA_OP_DEF);
>>>>> +         /* Set the SSA with the value range.  */
>>>>> +         if (def_p
>>>>> +             && TREE_CODE (DEF_FROM_PTR (def_p)) == SSA_NAME
>>>>> +             && INTEGRAL_TYPE_P (TREE_TYPE (DEF_FROM_PTR (def_p))))
>>>>> +           {
>>>>> +             tree def = DEF_FROM_PTR (def_p);
>>>>> +             unsigned ver = SSA_NAME_VERSION (def);
>>>>> +             if ((vr_value[ver]->type == VR_RANGE
>>>>>
>>>>> Use get_value_range () please, not direct access to vr_value.
>>>>>
>>>> Done.
>>>>
>>>>> +                  || vr_value[ver]->type == VR_ANTI_RANGE)
>>>>> +                 && (TREE_CODE (vr_value[ver]->min) == INTEGER_CST)
>>>>> +                 && (TREE_CODE (vr_value[ver]->max) == INTEGER_CST))
>>>>> +               set_range_info (def, vr_value[ver]->type,
>>>>> vr_value[ver]->min,
>>>>> +                               vr_value[ver]->max);
>>>>> +           }
>>>>>
>>>>> Otherwise the patch looks good now (with a lot of improvement
>>>>> possibilities of course).
>>>>
>>>>
>>>> I will work on the improvement after this goes in.
>>>>
>>>> Bootstrapped and regression tested on x86_64-linux-gnu. Does this looks
>>>> OK?
>>>
>>>
>>> Please remove no-op changes like
>>
>> Done.
>>
>>
>>> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c
>>> b/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c
>>> index 7efdd63..3a433d6 100644
>>> --- a/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c
>>> +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c
>>> @@ -3,7 +3,7 @@
>>>     known to be zero after entering the first two "if" statements.  */
>>>
>>>  /* { dg-do compile } */
>>> -/* { dg-options "-O2 -fdump-tree-vrp1" } */
>>> +/* { dg-options "-O2  -fdump-tree-vrp1" } */
>>>
>>>  void link_error (void);
>>>
>>> @@ -21,4 +21,4 @@ foo (int *p, int q)
>>>      }
>>>  }
>>>
>>> -/* { dg-final { scan-tree-dump-times "Folding predicate r_.* != 0B to
>>> 0" 1 "vrp1" } } */
>>> +/* { dg-final { scan-tree-dump-times "link_error" 0 "vrp1" } } */
>>> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c
>>> b/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c
>>> index dcf9148..c4fda8b 100644
>>> --- a/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c
>>> +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c
>>> @@ -3,7 +3,7 @@
>>>     Check that VRP now gets ranges from BIT_AND_EXPRs.  */
>>>
>>>  /* { dg-do compile } */
>>> -/* { dg-options "-O2 -fno-tree-ccp -fdump-tree-vrp1" } */
>>> +/* { dg-options "-O2 -fno-tree-ccp -fdump-tree-vrp" } */
>>>
>>>  int
>>>  foo (int a)
>>>
>>>
>>> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp46.c
>>> b/gcc/testsuite/gcc.dg/tree-ssa/vrp46.c
>>> index d3c9ed1..5b279a1 100644
>>> --- a/gcc/testsuite/gcc.dg/tree-ssa/vrp46.c
>>> +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp46.c
>>> @@ -27,6 +27,5 @@ func_18 ( int t )
>>>      }
>>>  }
>>>
>>> -/* There should be a single if left.  */
>>>
>>> -/* { dg-final { scan-tree-dump-times "if" 1 "vrp1" } } */
>>> +/* { dg-final { scan-tree-dump-times "if" 0 "vrp1" } } */
>>>
>>> I'm curious -- this is not a dg-run testcase but did you investigate this
>>> isn't generating wrong code now?  At least I can't see how
>>> the if (1 & (t % rhs)) test could vanish.
>>
>> Indeed.This was a mistake and fixed it.
>>
>>
>>> I hope we'll get GIMPLE unit testing finished for GCC 7 so we can add
>>> separate
>>> unit-tests for VRP and EVRP.
>>
>>
>> I will have a look at it.
>>
>> Thanks,
>> Kugan
>>
>>
>>> Thanks,
>>> Richard.
>>>
>>>
>>>> Thanks,
>>>> Kugan
>>>>
>>>>
>>>>
>>>>>
>>>>> Thanks and sorry for the delay,
>>>>> Richard.
>>>>>
>>>>>> Thanks,
>>>>>> Kugan
>>>>>>
>>>>>>
>>>>>>> Thanks,
>>>>>>> Richard.
>>>>>>>
>>>>>>>> I also noticed that g++.dg/warn/pr33738.C testcase is now failing.
>>>>>>>> This
>>>>>>>> is
>>>>>>>> because, with early-vrp setting value range ccp2 is optimizing
>>>>>>>> without
>>>>>>>> issuing a warning. I will look into it.
>>>>>>>>
>>>>>>>> bootstrap and regression testing is in progress.
>>>>>>>>
>>>>>>>> Thanks,
>>>>>>>> Kugan

[-- Attachment #2: 0001-Add-early-vrp.patch --]
[-- Type: text/x-patch, Size: 30599 bytes --]

From 42cef3f7abc956ece46e4303e3a6d68464dde99c Mon Sep 17 00:00:00 2001
From: Kugan Vivekanandarajah <kugan.vivekanandarajah@linaro.org>
Date: Tue, 23 Aug 2016 16:18:30 +1000
Subject: [PATCH 1/3] Add early-vrp

---
 gcc/doc/invoke.texi                       |   5 +
 gcc/passes.def                            |   1 +
 gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C |   2 +-
 gcc/testsuite/g++.dg/warn/pr33738.C       |   4 +-
 gcc/testsuite/gcc.dg/tree-ssa/evrp1.c     |  13 +
 gcc/testsuite/gcc.dg/tree-ssa/evrp2.c     |  18 ++
 gcc/testsuite/gcc.dg/tree-ssa/evrp3.c     |  15 +
 gcc/testsuite/gcc.dg/tree-ssa/pr20657.c   |   4 +-
 gcc/testsuite/gcc.dg/tree-ssa/pr22117.c   |   2 +-
 gcc/testsuite/gcc.dg/tree-ssa/pr37508.c   |   2 +-
 gcc/testsuite/gcc.dg/tree-ssa/pr61839_2.c |   8 +-
 gcc/testsuite/gcc.dg/tree-ssa/pr64130.c   |   6 +-
 gcc/testsuite/gcc.dg/tree-ssa/vrp04.c     |   2 +-
 gcc/testsuite/gcc.dg/tree-ssa/vrp06.c     |   4 +-
 gcc/testsuite/gcc.dg/tree-ssa/vrp16.c     |   4 +-
 gcc/testsuite/gcc.dg/tree-ssa/vrp25.c     |   4 +-
 gcc/testsuite/gcc.dg/tree-ssa/vrp67.c     |   2 +-
 gcc/timevar.def                           |   1 +
 gcc/tree-pass.h                           |   1 +
 gcc/tree-ssa-propagate.c                  |   2 +-
 gcc/tree-ssa-propagate.h                  |   1 +
 gcc/tree-vrp.c                            | 467 ++++++++++++++++++++++++++----
 22 files changed, 492 insertions(+), 76 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/evrp1.c
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/evrp2.c
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/evrp3.c

diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 87da1f1..9ed9c24 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -12454,6 +12454,11 @@ is made by appending @file{.slp} to the source file name.
 Dump each function after Value Range Propagation (VRP).  The file name
 is made by appending @file{.vrp} to the source file name.
 
+@item early vrp
+@opindex fdump-tree-evrp
+Dump each function after Early Value Range Propagation (EVRP).  The file name
+is made by appending @file{.evrp} to the source file name.
+
 @item oaccdevlow
 @opindex fdump-tree-oaccdevlow
 Dump each function after applying device-specific OpenACC transformations.
diff --git a/gcc/passes.def b/gcc/passes.def
index 533157d..9759fed 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -89,6 +89,7 @@ along with GCC; see the file COPYING3.  If not see
 	     execute TODO_rebuild_alias at this point.  */
 	  NEXT_PASS (pass_build_ealias);
 	  NEXT_PASS (pass_fre);
+	  NEXT_PASS (pass_early_vrp);
 	  NEXT_PASS (pass_merge_phi);
           NEXT_PASS (pass_dse);
 	  NEXT_PASS (pass_cd_dce);
diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C b/gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C
index 5e09583..cf4ed33 100644
--- a/gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C
+++ b/gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O -fdump-tree-forwprop1" } */
+/* { dg-options "-O -fno-tree-vrp -fdump-tree-forwprop1" } */
 
 #include <new>
 
diff --git a/gcc/testsuite/g++.dg/warn/pr33738.C b/gcc/testsuite/g++.dg/warn/pr33738.C
index 60ee0b4..73e98d5 100644
--- a/gcc/testsuite/g++.dg/warn/pr33738.C
+++ b/gcc/testsuite/g++.dg/warn/pr33738.C
@@ -15,11 +15,11 @@ int GetM1() {
 
 int main() {
  a2 = static_cast<Alpha>(GetM1());
- if (a2 == -1) {	// { dg-warning "always false due" }
+ if (a2 == -1) {	// { dg-warning "always false due" "" { xfail *-*-* } } */
     link_error ();
  }
  a2 = static_cast<Alpha>(GetM1());
- if (-1 == a2) {	// { dg-warning "always false due" }
+ if (-1 == a2) {	// { dg-warning "always false due" "" { xfail *-*-* } } */
     link_error ();
  }
  return 0;
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/evrp1.c b/gcc/testsuite/gcc.dg/tree-ssa/evrp1.c
new file mode 100644
index 0000000..8c6e4e6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/evrp1.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+int foo (int i);
+int bar (int j)
+{
+  if (j > 2)
+    return foo (j + 2);
+  else
+    return j;
+}
+
+/* { dg-final { scan-tree-dump "\\\[5, \\+INF" "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/evrp2.c b/gcc/testsuite/gcc.dg/tree-ssa/evrp2.c
new file mode 100644
index 0000000..e6d4235
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/evrp2.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+int foo (int i);
+int bar2 (int j)
+{
+  if (j > 2)
+    {
+      if (j < 7)
+	return foo (j + 1);
+      else
+	return foo (j + 2);
+    }
+  return j;
+}
+
+
+/* { dg-final { scan-tree-dump "\\\[4, 7\\\]" "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/evrp3.c b/gcc/testsuite/gcc.dg/tree-ssa/evrp3.c
new file mode 100644
index 0000000..1a3bbd5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/evrp3.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+int foo (int i);
+void bar (int j)
+{
+  unsigned int i;
+  for (i = 0; i < 10; ++i)
+    {
+      bar (i + 1);
+    }
+}
+
+/* { dg-final { scan-tree-dump "\\\[1, 10\\\]" "evrp" } } */
+
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr20657.c b/gcc/testsuite/gcc.dg/tree-ssa/pr20657.c
index 727ca4c..e678231 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr20657.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr20657.c
@@ -3,7 +3,7 @@
    statement, which was needed to eliminate the second "if" statement.  */
 
 /* { dg-do compile } */
-/* { dg-options "-O2 -fno-tree-dominator-opts -fno-tree-fre -fdump-tree-vrp1-details" } */
+/* { dg-options "-O2 -fno-tree-dominator-opts -fno-tree-fre -fdump-tree-evrp" } */
 
 int
 foo (int a)
@@ -14,4 +14,4 @@ foo (int a)
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "Folding predicate" 1 "vrp1"} } */
+/* { dg-final { scan-tree-dump-times "if" 1 "evrp"} } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c b/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c
index 7efdd63..01cd33e 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c
@@ -21,4 +21,4 @@ foo (int *p, int q)
     }
 }
 
-/* { dg-final { scan-tree-dump-times "Folding predicate r_.* != 0B to 0" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "link_error" 0 "vrp1" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr37508.c b/gcc/testsuite/gcc.dg/tree-ssa/pr37508.c
index 0963cd9..2ba09af 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr37508.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr37508.c
@@ -46,4 +46,4 @@ int test4 (struct foo2 *x)
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "Folding" 2 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "if" 2 "vrp1" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr61839_2.c b/gcc/testsuite/gcc.dg/tree-ssa/pr61839_2.c
index ffa00a7..e44dc57 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr61839_2.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr61839_2.c
@@ -1,6 +1,6 @@
 /* PR tree-optimization/61839.  */
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1" } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
 /* { dg-require-effective-target int32plus } */
 
 __attribute__ ((noinline))
@@ -47,8 +47,8 @@ int bar2 ()
 
 
 /* Dont optimize 972195717 / 0 in function foo.  */
-/* { dg-final { scan-tree-dump-times "972195717 / _" 1  "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "972195717 / _" 1  "evrp" } } */
 /* Dont optimize 972195717 % 0 in function bar.  */
-/* { dg-final { scan-tree-dump-times "972195717 % _" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "972195717 % _" 1 "evrp" } } */
 /* Optimize in function bar2.  */
-/* { dg-final { scan-tree-dump-times "972195715 % _" 0 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "972195715 % _" 0 "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr64130.c b/gcc/testsuite/gcc.dg/tree-ssa/pr64130.c
index 0b25466..f39bd17 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr64130.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr64130.c
@@ -1,6 +1,6 @@
 
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1" } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
 
 int funsigned (unsigned a)
 {
@@ -13,6 +13,6 @@ int funsigned2 (unsigned a)
   return (-1 * 0x1ffffffffL) / a == 0;
 }
 
-/* { dg-final { scan-tree-dump ": \\\[2, 8589934591\\\]" "vrp1" } } */
-/* { dg-final { scan-tree-dump ": \\\[-8589934591, -2\\\]" "vrp1" } } */
+/* { dg-final { scan-tree-dump ": \\\[2, 8589934591\\\]" "evrp" } } */
+/* { dg-final { scan-tree-dump ": \\\[-8589934591, -2\\\]" "evrp" } } */
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp04.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp04.c
index 61b7a47..67f8f01 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp04.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp04.c
@@ -10,4 +10,4 @@ foo (int a, int b)
       return a + b;
 }
 
-/* { dg-final { scan-tree-dump-times "Folding predicate a_.*to 1" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "if" 1 "vrp1" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp06.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp06.c
index cdad534..c4ce170 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp06.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp06.c
@@ -28,6 +28,6 @@ foo (int i, int j, int a)
   return i + a + j;
 }
 
-/* { dg-final { scan-tree-dump-times "Folding predicate i_\[0-9\]+.*0 to 0" 1 "vrp1" } } */
-/* { dg-final { scan-tree-dump-times "Folding predicate j_\[0-9\]+.*0 to 1" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "Folding predicate \[i|j\]_\[0-9\]+.*0 to 0" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "Folding predicate \[i|j\]_\[0-9\]+.*0 to 1" 1 "vrp1" } } */
 /* { dg-final { scan-tree-dump-times "Folding predicate i_\[0-9]+.*j_\[0-9\]+.* to 0" 1 "vrp1" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp16.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp16.c
index 8f5d5c8..d09f3ae 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp16.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp16.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fno-tree-fre -fdump-tree-vrp1-details" } */
+/* { dg-options "-O2 -fno-tree-fre -fdump-tree-evrp" } */
 
 
 extern void abort (void) __attribute__ ((__noreturn__));
@@ -19,5 +19,5 @@ nonlocal_mentioned_p (rtx x)
 	abort ();
 }
 
-/* { dg-final { scan-tree-dump-times "Folding predicate .*to 0" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "if" 0 "evrp" } } */
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp25.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp25.c
index cbc4ec3..a49f079 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp25.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp25.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fno-tree-fre -fdump-tree-vrp1-details" } */
+/* { dg-options "-O2 -fno-tree-fre -fdump-tree-vrp1" } */
 
 extern void abort ();
 extern void arf ();
@@ -49,5 +49,5 @@ L9:
 /* The second test of (code1 != 53) and the test (D18670 <= 2) are
    both totally subsumed by earlier tests and thus should be folded
    away using VRP.  */
-/* { dg-final { scan-tree-dump-times "Folding predicate" 2 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "if" 3 "vrp1" } } */
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp67.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp67.c
index ef5e8f9..5155f7b 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp67.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp67.c
@@ -36,4 +36,4 @@ unsigned baz (unsigned i)
   return i;
 }
 
-/* { dg-final { scan-tree-dump-times "Folding predicate" 3 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "if" 3 "vrp1" } } */
diff --git a/gcc/timevar.def b/gcc/timevar.def
index 5f12118..8837832 100644
--- a/gcc/timevar.def
+++ b/gcc/timevar.def
@@ -149,6 +149,7 @@ DEFTIMEVAR (TV_TREE_CFG		     , "tree CFG construction")
 DEFTIMEVAR (TV_TREE_CLEANUP_CFG	     , "tree CFG cleanup")
 DEFTIMEVAR (TV_TREE_TAIL_MERGE       , "tree tail merge")
 DEFTIMEVAR (TV_TREE_VRP              , "tree VRP")
+DEFTIMEVAR (TV_TREE_EARLY_VRP        , "tree Early VRP")
 DEFTIMEVAR (TV_TREE_COPY_PROP        , "tree copy propagation")
 DEFTIMEVAR (TV_FIND_REFERENCED_VARS  , "tree find ref. vars")
 DEFTIMEVAR (TV_TREE_PTA		     , "tree PTA")
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index c0059de..86d797e 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -440,6 +440,7 @@ extern gimple_opt_pass *make_pass_fre (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_check_data_deps (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_copy_prop (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_isolate_erroneous_paths (gcc::context *ctxt);
+extern gimple_opt_pass *make_pass_early_vrp (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_vrp (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_uncprop (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_return_slot (gcc::context *ctxt);
diff --git a/gcc/tree-ssa-propagate.c b/gcc/tree-ssa-propagate.c
index c8cf078..97cfde5 100644
--- a/gcc/tree-ssa-propagate.c
+++ b/gcc/tree-ssa-propagate.c
@@ -863,7 +863,7 @@ static struct prop_stats_d prop_stats;
 /* Replace USE references in statement STMT with the values stored in
    PROP_VALUE. Return true if at least one reference was replaced.  */
 
-static bool
+bool
 replace_uses_in (gimple *stmt, ssa_prop_get_value_fn get_value)
 {
   bool replaced = false;
diff --git a/gcc/tree-ssa-propagate.h b/gcc/tree-ssa-propagate.h
index 30d66a9..1a96976 100644
--- a/gcc/tree-ssa-propagate.h
+++ b/gcc/tree-ssa-propagate.h
@@ -84,5 +84,6 @@ extern void propagate_value (use_operand_p, tree);
 extern void replace_exp (use_operand_p, tree);
 extern void propagate_tree_value (tree *, tree);
 extern void propagate_tree_value_into_stmt (gimple_stmt_iterator *, tree);
+extern bool replace_uses_in (gimple *stmt, ssa_prop_get_value_fn get_value);
 
 #endif /* _TREE_SSA_PROPAGATE_H  */
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index 45882c4..c8481c9 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -60,6 +60,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "case-cfn-macros.h"
 #include "params.h"
 #include "alloc-pool.h"
+#include "domwalk.h"
+#include "tree-cfgcleanup.h"
 
 #define VR_INITIALIZER { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL }
 
@@ -1455,44 +1457,17 @@ op_with_boolean_value_range_p (tree op)
 	  && integer_onep (vr->max));
 }
 
-/* Extract value range information from an ASSERT_EXPR EXPR and store
-   it in *VR_P.  */
+/* Extract value range information for VAR when (OP COND_CODE LIMIT) is
+   true and store it in *VR_P.  */
 
 static void
-extract_range_from_assert (value_range *vr_p, tree expr)
+extract_range_for_var_from_comparison_expr (tree var, enum tree_code cond_code,
+					    tree op, tree limit,
+					    value_range *vr_p)
 {
-  tree var, cond, limit, min, max, type;
+  tree  min, max, type;
   value_range *limit_vr;
-  enum tree_code cond_code;
-
-  var = ASSERT_EXPR_VAR (expr);
-  cond = ASSERT_EXPR_COND (expr);
-
-  gcc_assert (COMPARISON_CLASS_P (cond));
-
-  /* Find VAR in the ASSERT_EXPR conditional.  */
-  if (var == TREE_OPERAND (cond, 0)
-      || TREE_CODE (TREE_OPERAND (cond, 0)) == PLUS_EXPR
-      || TREE_CODE (TREE_OPERAND (cond, 0)) == NOP_EXPR)
-    {
-      /* If the predicate is of the form VAR COMP LIMIT, then we just
-	 take LIMIT from the RHS and use the same comparison code.  */
-      cond_code = TREE_CODE (cond);
-      limit = TREE_OPERAND (cond, 1);
-      cond = TREE_OPERAND (cond, 0);
-    }
-  else
-    {
-      /* If the predicate is of the form LIMIT COMP VAR, then we need
-	 to flip around the comparison code to create the proper range
-	 for VAR.  */
-      cond_code = swap_tree_comparison (TREE_CODE (cond));
-      limit = TREE_OPERAND (cond, 0);
-      cond = TREE_OPERAND (cond, 1);
-    }
-
   limit = avoid_overflow_infinity (limit);
-
   type = TREE_TYPE (var);
   gcc_assert (limit != var);
 
@@ -1538,15 +1513,15 @@ extract_range_from_assert (value_range *vr_p, tree expr)
      as well build the range [b_4, +INF] for it.
      One special case we handle is extracting a range from a
      range test encoded as (unsigned)var + CST <= limit.  */
-  if (TREE_CODE (cond) == NOP_EXPR
-      || TREE_CODE (cond) == PLUS_EXPR)
+  if (TREE_CODE (op) == NOP_EXPR
+      || TREE_CODE (op) == PLUS_EXPR)
     {
-      if (TREE_CODE (cond) == PLUS_EXPR)
+      if (TREE_CODE (op) == PLUS_EXPR)
         {
-          min = fold_build1 (NEGATE_EXPR, TREE_TYPE (TREE_OPERAND (cond, 1)),
-			     TREE_OPERAND (cond, 1));
+	  min = fold_build1 (NEGATE_EXPR, TREE_TYPE (TREE_OPERAND (op, 1)),
+			     TREE_OPERAND (op, 1));
           max = int_const_binop (PLUS_EXPR, limit, min);
-	  cond = TREE_OPERAND (cond, 0);
+	  op = TREE_OPERAND (op, 0);
 	}
       else
 	{
@@ -1730,6 +1705,41 @@ extract_range_from_assert (value_range *vr_p, tree expr)
   vrp_intersect_ranges (vr_p, get_value_range (var));
 }
 
+/* Extract value range information from an ASSERT_EXPR EXPR and store
+   it in *VR_P.  */
+
+static void
+extract_range_from_assert (value_range *vr_p, tree expr)
+{
+  tree var = ASSERT_EXPR_VAR (expr);
+  tree cond = ASSERT_EXPR_COND (expr);
+  tree limit, op;
+  enum tree_code cond_code;
+  gcc_assert (COMPARISON_CLASS_P (cond));
+
+  /* Find VAR in the ASSERT_EXPR conditional.  */
+  if (var == TREE_OPERAND (cond, 0)
+      || TREE_CODE (TREE_OPERAND (cond, 0)) == PLUS_EXPR
+      || TREE_CODE (TREE_OPERAND (cond, 0)) == NOP_EXPR)
+    {
+      /* If the predicate is of the form VAR COMP LIMIT, then we just
+	 take LIMIT from the RHS and use the same comparison code.  */
+      cond_code = TREE_CODE (cond);
+      limit = TREE_OPERAND (cond, 1);
+      op = TREE_OPERAND (cond, 0);
+    }
+  else
+    {
+      /* If the predicate is of the form LIMIT COMP VAR, then we need
+	 to flip around the comparison code to create the proper range
+	 for VAR.  */
+      cond_code = swap_tree_comparison (TREE_CODE (cond));
+      limit = TREE_OPERAND (cond, 0);
+      op = TREE_OPERAND (cond, 1);
+    }
+  extract_range_for_var_from_comparison_expr (var, cond_code, op,
+					      limit, vr_p);
+}
 
 /* Extract range information from SSA name VAR and store it in VR.  If
    VAR has an interesting range, use it.  Otherwise, create the
@@ -6947,19 +6957,24 @@ stmt_interesting_for_vrp (gimple *stmt)
   return false;
 }
 
-
-/* Initialize local data structures for VRP.  */
+/* Initialize VRP lattice.  */
 
 static void
-vrp_initialize (void)
+vrp_initialize_lattice ()
 {
-  basic_block bb;
-
   values_propagated = false;
   num_vr_values = num_ssa_names;
   vr_value = XCNEWVEC (value_range *, num_vr_values);
   vr_phi_edge_counts = XCNEWVEC (int, num_ssa_names);
   bitmap_obstack_initialize (&vrp_equiv_obstack);
+}
+
+/* Initialization required by ssa_propagate engine.  */
+
+static void
+vrp_initialize ()
+{
+  basic_block bb;
 
   FOR_EACH_BB_FN (bb, cfun)
     {
@@ -7010,6 +7025,8 @@ vrp_valueize (tree name)
     {
       value_range *vr = get_value_range (name);
       if (vr->type == VR_RANGE
+	  && (TREE_CODE (vr->min) == SSA_NAME
+	      || is_gimple_min_invariant (vr->min))
 	  && vrp_operand_equal_p (vr->min, vr->max))
 	return vr->min;
     }
@@ -10500,6 +10517,22 @@ finalize_jump_threads (void)
   delete equiv_stack;
 }
 
+/* Free VRP lattice.  */
+
+static void
+vrp_free_lattice ()
+{
+  /* Free allocated memory.  */
+  free (vr_value);
+  free (vr_phi_edge_counts);
+  bitmap_obstack_release (&vrp_equiv_obstack);
+  vrp_value_range_pool.release ();
+
+  /* So that we can distinguish between VRP data being available
+     and not available.  */
+  vr_value = NULL;
+  vr_phi_edge_counts = NULL;
+}
 
 /* Traverse all the blocks folding conditionals with known ranges.  */
 
@@ -10546,17 +10579,302 @@ vrp_finalize (bool warn_array_bounds_p)
   /* We must identify jump threading opportunities before we release
      the datastructures built by VRP.  */
   identify_jump_threads ();
+}
 
-  /* Free allocated memory.  */
-  free (vr_value);
-  free (vr_phi_edge_counts);
-  bitmap_obstack_release (&vrp_equiv_obstack);
-  vrp_value_range_pool.release ();
+/* evrp_dom_walker visits the basic blocks in the dominance order and set
+   the Value Ranges (VR) for SSA_NAMEs in the scope.  Use this VR to
+   discover more VRs.  */
 
-  /* So that we can distinguish between VRP data being available
-     and not available.  */
-  vr_value = NULL;
-  vr_phi_edge_counts = NULL;
+class evrp_dom_walker : public dom_walker
+{
+public:
+  evrp_dom_walker ()
+    : dom_walker (CDI_DOMINATORS), stack (10)
+    {
+      stmts_to_fixup.create (0);
+      need_eh_cleanup = BITMAP_ALLOC (NULL);
+    }
+  ~evrp_dom_walker ()
+    {
+      stmts_to_fixup.release ();
+      BITMAP_FREE (need_eh_cleanup);
+    }
+  virtual edge before_dom_children (basic_block);
+  virtual void after_dom_children (basic_block);
+  void push_value_range (const_tree var, value_range *vr);
+  value_range *pop_value_range (const_tree var);
+
+  /* Cond_stack holds the old VR.  */
+  auto_vec<std::pair <const_tree, value_range*> > stack;
+  bitmap need_eh_cleanup;
+  vec<gimple *> stmts_to_fixup;
+};
+
+/* See if there is any new scope is entered with new VR and set that VR to
+   ssa_name before visiting the statements in the scope.  */
+
+edge
+evrp_dom_walker::before_dom_children (basic_block bb)
+{
+  value_range *new_vr = NULL;
+  tree op0 = NULL_TREE;
+
+  push_value_range (NULL_TREE, NULL);
+  if (single_pred_p (bb))
+    {
+      edge e = single_pred_edge (bb);
+      value_range vr = VR_INITIALIZER;
+      gimple *stmt = last_stmt (e->src);
+      if (stmt
+	  && gimple_code (stmt) == GIMPLE_COND
+	  && (op0 = gimple_cond_lhs (stmt))
+	  && TREE_CODE (op0) == SSA_NAME
+	  && INTEGRAL_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt))))
+	{
+	  /* Entering a new scope.  Try to see if we can find a VR
+	     here.  */
+	  tree op1 = gimple_cond_rhs (stmt);
+	  tree_code code = gimple_cond_code (stmt);
+	  value_range *old_vr = get_value_range (op0);
+
+	  if (TREE_OVERFLOW_P (op1))
+	    op1 = drop_tree_overflow (op1);
+
+	  /* If condition is false, invert the cond.  */
+	  if (e->flags & EDGE_FALSE_VALUE)
+	    code = invert_tree_comparison (gimple_cond_code (stmt),
+					   HONOR_NANS (op0));
+	  /* Discover VR when condition is true.  */
+	  extract_range_for_var_from_comparison_expr (op0, code, op0, op1, &vr);
+	  if (old_vr->type == VR_RANGE || old_vr->type == VR_ANTI_RANGE)
+	    vrp_intersect_ranges (&vr, old_vr);
+
+	  /* If we found any usable VR, set the VR to ssa_name and create a
+	     PUSH old value in the stack with the old VR.  */
+	  if (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE)
+	    {
+	      new_vr = vrp_value_range_pool.allocate ();
+	      *new_vr = vr;
+	      push_value_range (op0, new_vr);
+	    }
+	}
+    }
+
+  /* Visit PHI stmts and discover any new VRs possible.  */
+  gimple_stmt_iterator gsi;
+  edge e;
+  edge_iterator ei;
+  bool has_unvisived_preds = false;
+
+  FOR_EACH_EDGE (e, ei, bb->preds)
+    if (!(e->src->flags & BB_VISITED))
+      {
+	has_unvisived_preds = true;
+	break;
+      }
+
+  for (gphi_iterator gpi = gsi_start_phis (bb);
+       !gsi_end_p (gpi); gsi_next (&gpi))
+    {
+      gphi *phi = gpi.phi ();
+      tree lhs = PHI_RESULT (phi);
+      value_range vr_result = VR_INITIALIZER;
+      if (!has_unvisived_preds
+	  && stmt_interesting_for_vrp (phi))
+	extract_range_from_phi_node (phi, &vr_result);
+      else
+	set_value_range_to_varying (&vr_result);
+      update_value_range (lhs, &vr_result);
+    }
+
+  /* Visit all other stmts and discover any new VRs possible.  */
+  for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+    {
+      gimple *stmt = gsi_stmt (gsi);
+      edge taken_edge;
+      tree output = NULL_TREE;
+      gimple *old_stmt = stmt;
+      bool was_noreturn = (is_gimple_call (stmt)
+			   && gimple_call_noreturn_p (stmt));
+
+      /* TODO, if found taken_edge, we should visit (return it) and travel
+	 again to improve VR as done in DOM/SCCVN optimizations.  It should
+	 be done carefully as stmts might prematurely leave a BB like
+	 in EH.  */
+      if (stmt_interesting_for_vrp (stmt))
+	{
+	  value_range vr = VR_INITIALIZER;
+	  extract_range_from_stmt (stmt, &taken_edge, &output, &vr);
+	  if (output
+	      && (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE))
+	    update_value_range (output, &vr);
+	  else
+	    {
+	      tree def;
+	      ssa_op_iter iter;
+	      FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_DEF)
+		set_value_range_to_varying (get_value_range (def));
+	    }
+
+	  /* Try folding stmts with the VR discovered.  */
+	  bool did_replace
+	    = replace_uses_in (stmt,
+			       op_with_constant_singleton_value_range);
+	  if (fold_stmt (&gsi, follow_single_use_edges)
+	      || did_replace)
+	    update_stmt (gsi_stmt (gsi));
+
+	  if (did_replace)
+	    {
+	      /* If we cleaned up EH information from the statement,
+		 remove EH edges.  */
+	      if (maybe_clean_or_replace_eh_stmt (old_stmt, stmt))
+		bitmap_set_bit (need_eh_cleanup, bb->index);
+
+	      /* If we turned a not noreturn call into a noreturn one
+		 schedule it for fixup.  */
+	      if (!was_noreturn
+		  && is_gimple_call (stmt)
+		  && gimple_call_noreturn_p (stmt))
+		stmts_to_fixup.safe_push (stmt);
+
+	      if (gimple_assign_single_p (stmt))
+		{
+		  tree rhs = gimple_assign_rhs1 (stmt);
+		  if (TREE_CODE (rhs) == ADDR_EXPR)
+		    recompute_tree_invariant_for_addr_expr (rhs);
+		}
+	    }
+
+	  def_operand_p def_p = SINGLE_SSA_DEF_OPERAND (stmt, SSA_OP_DEF);
+	  /* Set the SSA with the value range.  */
+	  if (def_p
+	      && TREE_CODE (DEF_FROM_PTR (def_p)) == SSA_NAME
+	      && INTEGRAL_TYPE_P (TREE_TYPE (DEF_FROM_PTR (def_p))))
+	    {
+	      tree def = DEF_FROM_PTR (def_p);
+	      value_range *vr = get_value_range (def);
+
+	      if ((vr->type == VR_RANGE
+		   || vr->type == VR_ANTI_RANGE)
+		  && (TREE_CODE (vr->min) == INTEGER_CST)
+		  && (TREE_CODE (vr->max) == INTEGER_CST))
+		set_range_info (def, vr->type, vr->min, vr->max);
+	    }
+	}
+      else
+	{
+	  tree def;
+	  ssa_op_iter iter;
+	  FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_DEF)
+	    set_value_range_to_varying (get_value_range (def));
+	}
+    }
+  bb->flags |= BB_VISITED;
+  return NULL;
+}
+
+/* Restore/pop VRs valid only for BB when we leave BB.  */
+
+void
+evrp_dom_walker::after_dom_children (basic_block bb ATTRIBUTE_UNUSED)
+{
+  gcc_checking_assert (!stack.is_empty ());
+  while (stack.last ().first != NULL_TREE)
+    pop_value_range (stack.last ().first);
+  pop_value_range (stack.last ().first);
+}
+
+/* Push the Value Range of VAR to the stack and update it with new VR.  */
+
+void
+evrp_dom_walker::push_value_range (const_tree var, value_range *vr)
+{
+  if (vr != NULL)
+    {
+      unsigned ver = SSA_NAME_VERSION (var);
+      gcc_checking_assert (vr_value);
+      stack.safe_push (std::make_pair (var, vr_value[ver]));
+
+      if (ver < num_vr_values)
+	vr_value[ver] = vr;
+    }
+  else
+    stack.safe_push (std::make_pair (var, vr));
+}
+
+/* Pop the Value Range from the vrp_stack and update VAR with it.  */
+
+value_range *
+evrp_dom_walker::pop_value_range (const_tree var)
+{
+  value_range *vr = stack.last ().second;
+  if (vr != NULL)
+    {
+      unsigned ver = SSA_NAME_VERSION (var);
+      gcc_checking_assert (var == stack.last ().first);
+      gcc_checking_assert (vr_value);
+
+      if (ver < num_vr_values)
+	vr_value[ver] = vr;
+    }
+  stack.pop ();
+  return vr;
+}
+
+
+/* Main entry point for the early vrp pass which is a simplified non-iterative
+   version of vrp where basic blocks are visited in dominance order.  Value
+   ranges discovered in early vrp will also be used by ipa-vrp.  */
+
+static unsigned int
+execute_early_vrp ()
+{
+  edge e;
+  edge_iterator ei;
+  basic_block bb;
+
+  loop_optimizer_init (LOOPS_NORMAL | LOOPS_HAVE_RECORDED_EXITS);
+  rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa);
+  scev_initialize ();
+  calculate_dominance_info (CDI_DOMINATORS);
+  FOR_EACH_BB_FN (bb, cfun)
+    {
+      bb->flags &= ~BB_VISITED;
+      FOR_EACH_EDGE (e, ei, bb->preds)
+	e->flags |= EDGE_EXECUTABLE;
+    }
+  vrp_initialize_lattice ();
+
+  /* Walk stmts in dominance order and propagate VRP.  */
+  evrp_dom_walker walker;
+  walker.walk (ENTRY_BLOCK_PTR_FOR_FN (cfun));
+
+  if (!bitmap_empty_p (walker.need_eh_cleanup))
+    gimple_purge_all_dead_eh_edges (walker.need_eh_cleanup);
+
+  /* Fixup stmts that became noreturn calls.  This may require splitting
+     blocks and thus isn't possible during the dominator walk.  Do this
+     in reverse order so we don't inadvertedly remove a stmt we want to
+     fixup by visiting a dominating now noreturn call first.  */
+  while (!walker.stmts_to_fixup.is_empty ())
+    {
+      gimple *stmt = walker.stmts_to_fixup.pop ();
+      fixup_noreturn_call (stmt);
+    }
+
+  if (dump_file)
+    {
+      fprintf (dump_file, "\nValue ranges after Early VRP:\n\n");
+      dump_all_value_ranges (dump_file);
+      fprintf (dump_file, "\n");
+    }
+  vrp_free_lattice ();
+  scev_finalize ();
+  loop_optimizer_finalize ();
+  FOR_EACH_BB_FN (bb, cfun)
+    bb->flags &= ~BB_VISITED;
+  return 0;
 }
 
 
@@ -10627,9 +10945,11 @@ execute_vrp (bool warn_array_bounds_p)
   /* For visiting PHI nodes we need EDGE_DFS_BACK computed.  */
   mark_dfs_back_edges ();
 
+  vrp_initialize_lattice ();
   vrp_initialize ();
   ssa_propagate (vrp_visit_stmt, vrp_visit_phi_node);
   vrp_finalize (warn_array_bounds_p);
+  vrp_free_lattice ();
 
   free_numbers_of_iterations_estimates (cfun);
 
@@ -10727,3 +11047,44 @@ make_pass_vrp (gcc::context *ctxt)
 {
   return new pass_vrp (ctxt);
 }
+
+namespace {
+
+const pass_data pass_data_early_vrp =
+{
+  GIMPLE_PASS, /* type */
+  "evrp", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_TREE_EARLY_VRP, /* tv_id */
+  PROP_ssa, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  ( TODO_cleanup_cfg | TODO_update_ssa | TODO_verify_all ),
+};
+
+class pass_early_vrp : public gimple_opt_pass
+{
+public:
+  pass_early_vrp (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_early_vrp, ctxt)
+    {}
+
+  /* opt_pass methods: */
+  opt_pass * clone () { return new pass_early_vrp (m_ctxt); }
+  virtual bool gate (function *)
+    {
+      return flag_tree_vrp != 0;
+    }
+  virtual unsigned int execute (function *)
+    { return execute_early_vrp (); }
+
+}; // class pass_vrp
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_early_vrp (gcc::context *ctxt)
+{
+  return new pass_early_vrp (ctxt);
+}
+
-- 
2.7.4


[-- Attachment #3: log1.txt --]
[-- Type: text/plain, Size: 1841 bytes --]

gcc/ChangeLog:

2016-09-20  Kugan Vivekanandarajah  <kuganv@linaro.org>

	* doc/invoke.texi: Document -fdump-tree-evrp.
	* passes.def: Define new pass_early_vrp.
	* timevar.def: Define new TV_TREE_EARLY_VRP.
	* tree-pass.h (make_pass_early_vrp): New.
	* tree-ssa-propagate.c: Make replace_uses_in non static.
	* tree-ssa-propagate.h: Export replace_uses_in.
	* tree-vrp.c (extract_range_for_var_from_comparison_expr): New.
	(extract_range_from_assert): Factor out
	extract_range_for_var_from_comparison_expr.
	(vrp_initialize_lattice): New.
	(vrp_initialize): Factor out vrp_initialize_lattice.
	(vrp_valueize): Fix it to reject complex value ranges.
	(vrp_free_lattice): New.
	(evrp_dom_walker::before_dom_children): Likewise.
	(evrp_dom_walker::after_dom_children): Likewise.
	(evrp_dom_walker::push_value_range): Likewise.
	(evrp_dom_walker::pop_value_range): Likewise.
	(execute_early_vrp): Likewise.
	(execute_vrp): Call vrp_initialize_lattice and
	vrp_free_lattice.
	(make_pass_early_vrp): New.


gcc/testsuite/ChangeLog:

2016-09-20  Kugan Vivekanandarajah  <kuganv@linaro.org>

	* g++.dg/tree-ssa/pr31146-2.C: Run with -fno-tree-evrp as evrp also
	does the same transformation.
	* g++.dg/warn/pr33738.C: XFAIL as optimization now happens in ccp.
	* gcc.dg/tree-ssa/evrp1.c: New test.
	* gcc.dg/tree-ssa/evrp2.c: New test.
	* gcc.dg/tree-ssa/evrp3.c: New test.
	* gcc.dg/tree-ssa/pr20657.c: Check for the pattern in evrp dump.
	* gcc.dg/tree-ssa/pr22117.c: Likewise.
	* gcc.dg/tree-ssa/pr61839_2.c: Likewise.
	* gcc.dg/tree-ssa/pr64130.c: Likewise.
	* gcc.dg/tree-ssa/pr37508.c: Change the pattern to be checked as foldong
	now happens early.
	* gcc.dg/tree-ssa/vrp04.c: Likewise.
	* gcc.dg/tree-ssa/vrp06.c: Likewise.
	* gcc.dg/tree-ssa/vrp16.c: Likewise.
	* gcc.dg/tree-ssa/vrp25.c: Likewise.
	* gcc.dg/tree-ssa/vrp67.c: Likewise.


^ permalink raw reply	[flat|nested] 67+ messages in thread

end of thread, other threads:[~2016-09-20  2:05 UTC | newest]

Thread overview: 67+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-07-15  4:41 [RFC][IPA-VRP] IPA VRP Implementation kugan
2016-07-15  4:42 ` [RFC][IPA-VRP] Disable setting param of __builtin_constant_p to null kugan
2016-07-15  8:43   ` Jan Hubicka
2016-07-25  6:59     ` kugan
2016-07-25 10:02       ` Richard Biener
2016-07-15  4:43 ` [RFC][IPA-VRP] Check for POINTER_TYPE_P before accessing SSA_NAME_PTR_INFO in tree-inline kugan
2016-07-15  4:47   ` Andrew Pinski
2016-07-15  7:03     ` kugan
2016-07-15  7:03     ` Jakub Jelinek
2016-07-15  7:32   ` Richard Biener
2016-07-15  4:44 ` [RFC][IPA-VRP] Re-factor tree-vrp to factor out common code kugan
2016-07-15  4:47   ` [RFC][IPA-VRP] Add support for IPA VRP in ipa-cp/ipa-prop kugan
2016-07-15 12:23     ` Martin Jambor
2016-07-19  8:22       ` kugan
2016-07-19 21:27         ` kugan
2016-07-21 12:54           ` Jan Hubicka
2016-08-30  5:21             ` Kugan Vivekanandarajah
2016-08-30 18:12               ` Prathamesh Kulkarni
2016-08-30 21:10                 ` kugan
2016-09-02 12:31               ` Jan Hubicka
2016-07-17 13:24     ` Prathamesh Kulkarni
2016-07-22 12:27   ` [RFC][IPA-VRP] Re-factor tree-vrp to factor out common code kugan
2016-07-22 12:49     ` Richard Biener
2016-07-22 14:34       ` kugan
2016-07-23 10:12         ` kugan
2016-08-16  8:09           ` kugan
2016-08-16 11:56             ` Richard Biener
2016-08-16 22:20               ` kugan
2016-08-17  2:50                 ` kugan
2016-08-17 13:46                   ` Richard Biener
2016-07-15  4:45 ` [RFC][IPA-VRP] Early VRP Implementation kugan
2016-07-15  4:52   ` Andrew Pinski
2016-07-15  7:08     ` kugan
2016-07-15  7:28       ` Andrew Pinski
2016-07-15  7:33         ` kugan
2016-07-18 11:51           ` Richard Biener
2016-07-22 12:10             ` kugan
2016-07-25 11:18               ` Richard Biener
2016-07-26 12:27                 ` kugan
2016-07-26 13:37                   ` Richard Biener
2016-07-28  7:36                     ` kugan
2016-07-28 11:34                       ` Richard Biener
2016-08-03  1:17                         ` kugan
2016-08-12 10:43                           ` Richard Biener
2016-08-16  7:39                             ` [RFC][IPA-VRP] splits out the update_value_range calls from vrp_visit_stmt kugan
2016-08-16 10:58                               ` Richard Biener
2016-08-17  2:27                                 ` kugan
2016-08-17 13:44                                   ` Richard Biener
2016-08-16  7:45                             ` [RFC][IPA-VRP] Early VRP Implementation kugan
2016-08-19 11:41                               ` Richard Biener
2016-08-23  2:12                                 ` Kugan Vivekanandarajah
2016-09-02  8:11                                   ` Kugan Vivekanandarajah
2016-09-14 12:11                                   ` Richard Biener
2016-09-14 21:47                                     ` Jan Hubicka
2016-09-15  7:23                                       ` Richard Biener
2016-09-15 14:57                                         ` Jeff Law
2016-09-16  8:59                                           ` Richard Biener
2016-09-16  6:37                                     ` kugan
2016-09-16 10:26                                       ` Richard Biener
2016-09-18 23:40                                         ` kugan
2016-09-19 13:30                                           ` Richard Biener
2016-09-20  5:48                                             ` kugan
2016-07-19 16:19     ` Jeff Law
2016-07-19 18:35       ` Richard Biener
2016-07-19 20:14         ` Jeff Law
2016-07-15  4:47 ` [RFC][IPA-VRP] Teach tree-vrp to use the VR set in params kugan
2016-07-18 11:33   ` Richard Biener

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).