Add transitive inferred range processing.
authorAndrew MacLeod <amacleod@redhat.com>
Mon, 7 Nov 2022 20:07:35 +0000 (15:07 -0500)
committerAndrew MacLeod <amacleod@redhat.com>
Tue, 8 Nov 2022 00:22:19 +0000 (19:22 -0500)
Rewalk statements at the end of a block to see if any inferred ranges
affect earlier calculations and register those as inferred ranges.

gcc/
PR tree-optimization/104530
* gimple-range-cache.cc (ranger_cache::register_inferred_value):
New.  Split from:
(ranger_cache::apply_inferred_ranges): Move setting cache to
separate function.
* gimple-range-cache.h (register_inferred_value): New prototype.
* gimple-range-infer.cc (infer_range_manager::has_range_p): New.
* gimple-range-infer.h (has_range_p): New prototype.
* gimple-range.cc (register_transitive_inferred_ranges): New.
* gimple-range.h (register_transitive_inferred_ranges): New proto.
* tree-vrp.cc (rvrp_folder::fold_stmt): Check for transitive inferred
ranges at the end of the block before folding final stmt.

gcc/testsuite/
* gcc.dg/pr104530.c: New.

gcc/gimple-range-cache.cc
gcc/gimple-range-cache.h
gcc/gimple-range-infer.cc
gcc/gimple-range-infer.h
gcc/gimple-range.cc
gcc/gimple-range.h
gcc/testsuite/gcc.dg/pr104530.c [new file with mode: 0644]
gcc/tree-vrp.cc

index 89e2403..ce5a0c8 100644 (file)
@@ -1544,8 +1544,27 @@ ranger_cache::range_from_dom (vrange &r, tree name, basic_block start_bb,
   return true;
 }
 
-// This routine is used during a block walk to move the state of non-null for
-// any operands on stmt S to nonnull.
+// This routine will register an inferred value in block BB, and possibly
+// update the on-entry cache if appropriate.
+
+void
+ranger_cache::register_inferred_value (const vrange &ir, tree name,
+                                      basic_block bb)
+{
+  Value_Range r (TREE_TYPE (name));
+  if (!m_on_entry.get_bb_range (r, name, bb))
+    exit_range (r, name, bb, RFD_READ_ONLY);
+  if (r.intersect (ir))
+    {
+      m_on_entry.set_bb_range (name, bb, r);
+      // If this range was invariant before, remove invariance.
+      if (!m_gori.has_edge_range_p (name))
+       m_gori.set_range_invariant (name, false);
+    }
+}
+
+// This routine is used during a block walk to adjust any inferred ranges
+// of operands on stmt S.
 
 void
 ranger_cache::apply_inferred_ranges (gimple *s)
@@ -1574,17 +1593,6 @@ ranger_cache::apply_inferred_ranges (gimple *s)
       tree name = infer.name (x);
       m_exit.add_range (name, bb, infer.range (x));
       if (update)
-       {
-         Value_Range r (TREE_TYPE (name));
-         if (!m_on_entry.get_bb_range (r, name, bb))
-           exit_range (r, name, bb, RFD_READ_ONLY);
-         if (r.intersect (infer.range (x)))
-           {
-             m_on_entry.set_bb_range (name, bb, r);
-             // If this range was invariant before, remove invariance.
-             if (!m_gori.has_edge_range_p (name))
-               m_gori.set_range_invariant (name, false);
-           }
-       }
+       register_inferred_value (infer.range (x), name, bb);
     }
 }
index 45053b5..8e3ae8f 100644 (file)
@@ -87,6 +87,7 @@ public:
 
   void propagate_updated_value (tree name, basic_block bb);
 
+  void register_inferred_value (const vrange &r, tree name, basic_block bb);
   void apply_inferred_ranges (gimple *s);
   gori_compute m_gori;
   infer_range_manager m_exit;
index 010b34a..8714ef2 100644 (file)
@@ -252,6 +252,17 @@ infer_range_manager::get_nonzero (tree name)
   return *(m_nonzero[v]);
 }
 
+// Return TRUE if there are any range inferences in block BB.
+
+bool
+infer_range_manager::has_range_p (basic_block bb)
+{
+  if (bb->index >= (int)m_on_exit.length ())
+    return false;
+  bitmap b = m_on_exit[bb->index].m_names;
+  return b && !bitmap_empty_p (b);
+}
+
 // Return TRUE if NAME has a range inference in block BB.
 
 bool
index adfe1fd..10705e0 100644 (file)
@@ -62,6 +62,7 @@ public:
   void add_range (tree name, basic_block bb, const vrange &r);
   void add_nonzero (tree name, basic_block bb);
   bool has_range_p (tree name, basic_block bb);
+  bool has_range_p (basic_block bb);
   bool maybe_adjust_range (vrange &r, tree name, basic_block bb);
 private:
   class exit_range_head
index 8063869..2885d0f 100644 (file)
@@ -482,6 +482,54 @@ gimple_ranger::register_inferred_ranges (gimple *s)
   m_cache.apply_inferred_ranges (s);
 }
 
+// This function will walk the statements in BB to determine if any
+// discovered inferred ranges in the block have any transitive effects,
+// and if so, register those effects in BB.
+
+void
+gimple_ranger::register_transitive_inferred_ranges (basic_block bb)
+{
+  // Return if there are no inferred ranges in BB.
+  infer_range_manager &infer = m_cache.m_exit;
+  if (!infer.has_range_p (bb))
+    return;
+
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    fprintf (dump_file, "Checking for transitive inferred ranges in BB %d\n",
+            bb->index);
+
+  for (gimple_stmt_iterator si = gsi_start_bb (bb); !gsi_end_p (si);
+       gsi_next (&si))
+    {
+      gimple *s = gsi_stmt (si);
+      tree lhs = gimple_get_lhs (s);
+      // If the LHS alreayd has an inferred effect, leave it be.
+      if (!gimple_range_ssa_p (lhs) || infer.has_range_p (lhs, bb))
+       continue;
+      // Pick up global value.
+      Value_Range g (TREE_TYPE (lhs));
+      range_of_expr (g, lhs);
+
+      // If either dependency has an inferred range, check if recalculating
+      // the LHS is different than the global value. If so, register it as
+      // an inferred range as well.
+      Value_Range r (TREE_TYPE (lhs));
+      r.set_undefined ();
+      tree name1 = gori ().depend1 (lhs);
+      tree name2 = gori ().depend2 (lhs);
+      if ((name1 && infer.has_range_p (name1, bb))
+         || (name2 && infer.has_range_p (name2, bb)))
+       {
+         // Check if folding S produces a different result.
+         if (fold_range (r, s, this) && g != r)
+           {
+             infer.add_range (lhs, bb, r);
+             m_cache.register_inferred_value (r, lhs, bb);
+           }
+       }
+    }
+}
+
 // When a statement S has changed since the result was cached, re-evaluate
 // and update the global cache.
 
index 22e05f6..dfe8199 100644 (file)
@@ -62,6 +62,7 @@ public:
   auto_edge_flag non_executable_edge_flag;
   bool fold_stmt (gimple_stmt_iterator *gsi, tree (*) (tree));
   void register_inferred_ranges (gimple *s);
+  void register_transitive_inferred_ranges (basic_block bb);
 protected:
   bool fold_range_internal (vrange &r, gimple *s, tree name);
   void prefill_name (vrange &r, tree name);
diff --git a/gcc/testsuite/gcc.dg/pr104530.c b/gcc/testsuite/gcc.dg/pr104530.c
new file mode 100644 (file)
index 0000000..1ec1015
--- /dev/null
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+void foo(void);
+
+static int a, *b = &a, c, d = 1;
+
+int main() {
+    c = 0 == b;
+    a = *b;
+    if (c % d)
+        for (; d; --d)
+            foo();
+    b = 0;
+}
+
+
+/* { dg-final { scan-tree-dump-not "foo" "evrp" } }  */
+
index 39f7eb7..3393c73 100644 (file)
@@ -4501,6 +4501,15 @@ public:
 
   bool fold_stmt (gimple_stmt_iterator *gsi) override
   {
+    gimple *s = gsi_stmt (*gsi);
+    // If this is a block ending condition, and there are inferred ranges,
+    // reparse the block to see if there are any transitive inferred ranges.
+    if (is_a<gcond *> (s))
+      {
+       basic_block bb = gimple_bb (s);
+       if (bb && s == gimple_outgoing_range_stmt_p (bb))
+         m_ranger->register_transitive_inferred_ranges (bb);
+      }
     bool ret = m_simplifier.simplify (gsi);
     if (!ret)
       ret = m_ranger->fold_stmt (gsi, follow_single_use_edges);