Add Early VRP
authorKugan Vivekanandarajah <kuganv@linaro.org>
Tue, 20 Sep 2016 23:23:55 +0000 (23:23 +0000)
committerKugan Vivekanandarajah <kugan@gcc.gnu.org>
Tue, 20 Sep 2016 23:23:55 +0000 (23:23 +0000)
gcc/ChangeLog:

2016-09-21  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-21  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
foling 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.

From-SVN: r240291

24 files changed:
gcc/ChangeLog
gcc/doc/invoke.texi
gcc/passes.def
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C
gcc/testsuite/g++.dg/warn/pr33738.C
gcc/testsuite/gcc.dg/tree-ssa/evrp1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/evrp2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/evrp3.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/pr20657.c
gcc/testsuite/gcc.dg/tree-ssa/pr22117.c
gcc/testsuite/gcc.dg/tree-ssa/pr37508.c
gcc/testsuite/gcc.dg/tree-ssa/pr61839_2.c
gcc/testsuite/gcc.dg/tree-ssa/pr64130.c
gcc/testsuite/gcc.dg/tree-ssa/vrp04.c
gcc/testsuite/gcc.dg/tree-ssa/vrp06.c
gcc/testsuite/gcc.dg/tree-ssa/vrp16.c
gcc/testsuite/gcc.dg/tree-ssa/vrp25.c
gcc/testsuite/gcc.dg/tree-ssa/vrp67.c
gcc/timevar.def
gcc/tree-pass.h
gcc/tree-ssa-propagate.c
gcc/tree-ssa-propagate.h
gcc/tree-vrp.c

index c7f108013e373c975f19170870378c36b743bc5f..fe7376ebf1be08c3bcb8726df027eb9a1bf58eb7 100644 (file)
@@ -1,3 +1,27 @@
+2016-09-21  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.
+
 2016-09-20  Uros Bizjak  <ubizjak@gmail.com>
 
        * config/i386/i386.md (mult->ashift peephole2s): Use pow2p_hwi
index d171cfd9aebe58a523615e97e352b5b7db1c0380..05566ba62a0fa067cf006fb1fba04d1b291ad877 100644 (file)
@@ -12523,6 +12523,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.
index e98a719fc2b08adaf6d8dfb478df5840bc8c92f8..6a83371f8c23af3745d9a125ce2c7d8643be2a1b 100644 (file)
@@ -90,6 +90,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);
index 89024bb89d0f6950f7a043b38e5cda45c10b0841..4efb5894b560e6a01a681e7130e3261b571f8755 100644 (file)
@@ -1,3 +1,23 @@
+2016-09-21  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
+       foling 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.
+
 2016-09-20  Uros Bizjak  <ubizjak@gmail.com>
 
        PR target/77621
index 5e095831be88aa14bde0a50d75e962862500a75f..cf4ed33dd50db88e6319dbc24f2a586e247e4101 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O -fdump-tree-forwprop1" } */
+/* { dg-options "-O -fno-tree-vrp -fdump-tree-forwprop1" } */
 
 #include <new>
 
index 60ee0b4841237ff0d630f7268595b16b3232d43e..73e98d5e083c4e419e6df0ec651a0bdc0704eb2e 100644 (file)
@@ -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 (file)
index 0000000..8c6e4e6
--- /dev/null
@@ -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 (file)
index 0000000..e6d4235
--- /dev/null
@@ -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 (file)
index 0000000..1a3bbd5
--- /dev/null
@@ -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" } } */
+
index 727ca4c116a1179483411cc36667b7b03b7e9297..e67823150dab50a1e971f5fc329f096fa064d260 100644 (file)
@@ -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"} } */
index 7efdd634fff4d5ab9cb008dce47e500e8367a820..01cd33e958179e6690f3acf712727b7810feb176 100644 (file)
@@ -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" } } */
index 0963cd99281a32d5992562e1b9fec97abe2f9579..2ba09afe4819e622e34798dcbe935a184fe39e77 100644 (file)
@@ -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" } } */
index ffa00a7e6746b103e87457618df32441bb5becc5..e44dc576c5143507d0ce134e1b44b275965844e1 100644 (file)
@@ -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" } } */
index 0b254660c99d6f878db6025238df92fc1a6c45aa..f39bd179a8c99e29b69610089ef7e80e4a63eebc 100644 (file)
@@ -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" } } */
 
index 61b7a47a1945b6a79a5f5c5b854f80c5edb63fdb..67f8f01139eff96a229d7ee86241566ea0f7ec78 100644 (file)
@@ -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" } } */
index cdad534ef04c6854a8edef8f253893d08ec8e843..c4ce1703f551a7a0d64fc14e0ce4c13f63b72f2d 100644 (file)
@@ -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" } } */
index 8f5d5c85b933b7d55673409dd9be34d760a2aa2e..d09f3aea46aa3eb4c501e215b4f5d01aa7c211f5 100644 (file)
@@ -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" } } */
 
index cbc4ec354c44fb66b8fda0efba2733c5ad461986..a49f0793f96299d061dc00293f5e05f75db98d9c 100644 (file)
@@ -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" } } */
 
index ef5e8f9b58ee8fe93cdf60bded21ee91253dfd47..5155f7b6daf5c95f7d1b3a2f90f1f93892e25e4c 100644 (file)
@@ -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" } } */
index 5f121182e14955218d4da63bcf664197e74731e3..88378328a795e9d2c4a22d8a4ebc685913522b40 100644 (file)
@@ -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")
index cc87b184d670faa5bdef69619ccd1e0c564ed02c..251b30ffcdffb21a466cfed8eb2507dbda4f2a4b 100644 (file)
@@ -441,6 +441,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);
index c8cf0783e103a7c23e899847d17c25a3706e3eca..97cfde57c9d88053541c9d06148c71a9d179edb4 100644 (file)
@@ -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;
index 30d66a9742cbfce7287f2cd29edbd74c489e3af1..1a969765f09283bdde73a00296084706c6dcb791 100644 (file)
@@ -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  */
index e7067ab8e6ecc9950f3f8de2653fd32af9454171..e779759d3816b8f0cfffcd097d20163ab969a542 100644 (file)
@@ -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 }
 
@@ -1461,44 +1463,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);
 
@@ -1544,15 +1519,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
        {
@@ -1736,6 +1711,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
@@ -6953,19 +6963,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)
     {
@@ -7016,6 +7031,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;
     }
@@ -10506,6 +10523,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.  */
 
@@ -10552,17 +10585,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;
 }
 
 
@@ -10633,9 +10951,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);
 
@@ -10733,3 +11053,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);
+}
+