The following refactors range extraction from edges and makes EVRP
able to merge such edge based ranges for the case of multiple 
predecessors.  This allows it to catch anti-ranges from
if (a < 4 || a > 8) if that is not re-written to a single test like
when using gotos.

I don't expect this to catch very much in practice but the refactoring
means we can incorporate the tricks from register_edge_assert_for
more easily (we "simply" have to use extract_ranges_from_edge as the
one-and-true kind-of interface).

Motivated by Martin Sebors work on b_o_s and the appearant inability
of EVRP to do anything useful for him.

Bootstrap & regtest running on x86_64-unknown-linux-gnu.

Richard.

2016-12-02  Richard Biener  <rguent...@suse.de>

        * tree-vrp.c (evrp_dom_walker::extract_ranges_from_edge): New method
        split out from evrp_dom_walker::before_dom_children.
        (evrp_dom_walker::before_dom_children): Use it and implement merging
        of edge range info from multiple predecessors.

        * gcc.dg/tree-ssa/evrp7.c: New testcase.

diff --git a/gcc/testsuite/gcc.dg/tree-ssa/evrp7.c 
b/gcc/testsuite/gcc.dg/tree-ssa/evrp7.c
new file mode 100644
index 0000000..c28347d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/evrp7.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fgimple -fdump-tree-evrp" } */
+
+void __GIMPLE (startwith("evrp"))
+f (unsigned int a)
+{
+  if (a < 4U)
+    goto x;
+  else
+    goto bb_3;
+
+bb_3:
+  if (a > 8U)
+    goto x;
+  else
+    goto bb_4;
+
+x:
+  if (a == 5U)
+    goto bb_5;
+  else
+    goto bb_4;
+
+bb_5:
+  __builtin_abort ();
+
+bb_4:
+  return;
+}
+
+/* { dg-final { scan-tree-dump-times "evrp" 0 "if" } } */
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index 600634d..592d3b0 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -10700,6 +10700,7 @@ public:
   void push_value_range (tree var, value_range *vr);
   value_range *pop_value_range (tree var);
   value_range *try_find_new_range (tree op, tree_code code, tree limit);
+  void extract_ranges_from_edge (edge, vec<std::pair <tree, value_range*> > &);
 
   /* Cond_stack holds the old VR.  */
   auto_vec<std::pair <tree, value_range*> > stack;
@@ -10736,13 +10737,69 @@ evrp_dom_walker::try_find_new_range (tree op, 
tree_code code, tree limit)
   return NULL;
 }
 
+/* Extract ranges on E and store them into V.  */
+
+void
+evrp_dom_walker::extract_ranges_from_edge (edge e,
+                                          vec<std::pair
+                                               <tree, value_range*> > & v)
+{
+  gimple *stmt = last_stmt (e->src);
+  tree op0;
+  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)))
+         || POINTER_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt)))))
+    {
+      if (dump_file && (dump_flags & TDF_DETAILS))
+       {
+         fprintf (dump_file, "Visiting controlling predicate ");
+         print_gimple_stmt (dump_file, stmt, 0, 0);
+       }
+      /* 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);
+
+      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));
+      /* Add VR when (OP0 CODE OP1) condition is true.  */
+      value_range *op0_range = try_find_new_range (op0, code, op1);
+
+      /* Register ranges for y in x < y where
+        y might have ranges that are useful.  */
+      tree limit;
+      tree_code new_code;
+      if (TREE_CODE (op1) == SSA_NAME
+         && extract_code_and_val_from_cond_with_ops (op1, code,
+                                                     op0, op1,
+                                                     false,
+                                                     &new_code, &limit))
+       {
+         /* Add VR when (OP1 NEW_CODE LIMIT) condition is true.  */
+         value_range *op1_range = try_find_new_range (op1, new_code, limit);
+         if (op1_range)
+           v.safe_push (std::make_pair (op1, op1_range));
+       }
+
+      if (op0_range)
+       v.safe_push (std::make_pair (op0, op0_range));
+    }
+}
+
 /* 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)
 {
-  tree op0 = NULL_TREE;
   edge_iterator ei;
   edge e;
 
@@ -10768,53 +10825,10 @@ evrp_dom_walker::before_dom_children (basic_block bb)
     }
   if (pred_e)
     {
-      gimple *stmt = last_stmt (pred_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)))
-             || POINTER_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt)))))
-       {
-         if (dump_file && (dump_flags & TDF_DETAILS))
-           {
-             fprintf (dump_file, "Visiting controlling predicate ");
-             print_gimple_stmt (dump_file, stmt, 0, 0);
-           }
-         /* 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);
-
-         if (TREE_OVERFLOW_P (op1))
-           op1 = drop_tree_overflow (op1);
-
-         /* If condition is false, invert the cond.  */
-         if (pred_e->flags & EDGE_FALSE_VALUE)
-           code = invert_tree_comparison (gimple_cond_code (stmt),
-                                          HONOR_NANS (op0));
-         /* Add VR when (OP0 CODE OP1) condition is true.  */
-         value_range *op0_range = try_find_new_range (op0, code, op1);
-
-         /* Register ranges for y in x < y where
-            y might have ranges that are useful.  */
-         tree limit;
-         tree_code new_code;
-         if (TREE_CODE (op1) == SSA_NAME
-             && extract_code_and_val_from_cond_with_ops (op1, code,
-                                                         op0, op1,
-                                                         false,
-                                                         &new_code, &limit))
-           {
-             /* Add VR when (OP1 NEW_CODE LIMIT) condition is true.  */
-             value_range *op1_range = try_find_new_range (op1, new_code, 
limit);
-             if (op1_range)
-               push_value_range (op1, op1_range);
-           }
-
-         if (op0_range)
-           push_value_range (op0, op0_range);
-       }
+      auto_vec<std::pair<tree, value_range *>, 2> ranges;
+      extract_ranges_from_edge (pred_e, ranges);
+      for (unsigned i = 0; i < ranges.length (); ++i)
+       push_value_range (ranges[i].first, ranges[i].second);
     }
 
   /* Visit PHI stmts and discover any new VRs possible.  */
@@ -10827,6 +10841,71 @@ evrp_dom_walker::before_dom_children (basic_block bb)
        break;
       }
 
+  /* If we have multiple predecessors try merging range info from them.  */
+  edge first = NULL;
+  if (! pred_e
+      && ! has_unvisited_preds)
+    FOR_EACH_EDGE (e, ei, bb->preds)
+      if ((e->flags & EDGE_EXECUTABLE)
+         && ! dominated_by_p (CDI_DOMINATORS, e->dest, e->src))
+       {
+         first = e;
+         break;
+       }
+  if (first)
+    {
+      auto_vec<std::pair<tree, value_range *>, 2> ranges;
+      extract_ranges_from_edge (first, ranges);
+      if (! ranges.is_empty ())
+       {
+         FOR_EACH_EDGE (e, ei, bb->preds)
+           {
+             if (! (e->flags & EDGE_EXECUTABLE)
+                 || e == first)
+               continue;
+             bool can_use_lattice_for_edge
+               = dominated_by_p (CDI_DOMINATORS, e->dest, e->src);
+             auto_vec<std::pair<tree, value_range *>, 2> e_ranges;
+             extract_ranges_from_edge (e, e_ranges);
+             /* ??? Sort the range vectors once we may get more than two
+                ranges and remove the quadratic seach below.  */
+             for (unsigned i = 0; i < ranges.length ();)
+               {
+                 tree name = ranges[i].first;
+                 bool found = false;
+                 for (unsigned j = 0; j < e_ranges.length (); ++j)
+                   {
+                     if (e_ranges[j].first == name)
+                       {
+                         found = true;
+                         vrp_meet (ranges[i].second, e_ranges[j].second);
+                       }
+                   }
+                 if (! found
+                     && can_use_lattice_for_edge)
+                   {
+                     found = true;
+                     vrp_meet (ranges[i].second, get_value_range (name));
+                   }
+                 if (! found
+                     || ranges[i].second->type == VR_VARYING)
+                   {
+                     vrp_value_range_pool.remove (ranges[i].second);
+                     ranges.unordered_remove (i);
+                     continue;
+                   }
+                 ++i;
+               }
+             for (unsigned i = 0; i < e_ranges.length (); ++i)
+               vrp_value_range_pool.remove (e_ranges[i].second);
+             if (ranges.is_empty ())
+               break;
+           }
+         for (unsigned i = 0; i < ranges.length (); ++i)
+           push_value_range (ranges[i].first, ranges[i].second);
+       }
+    }
+
   for (gphi_iterator gpi = gsi_start_phis (bb);
        !gsi_end_p (gpi); gsi_next (&gpi))
     {

Reply via email to