[pypy-commit] pypy vecopt-merge: path iteration on a dependecy graph can enable blacklisting nodes that have already been visited.this cuts down the search space. this is only valid if a property must hold along all the paths and once for one path proven, any subpath must not be checked anymore (is the case in guard early exit

plan_rich noreply at buildbot.pypy.org
Tue Aug 18 17:49:26 CEST 2015


Author: Richard Plangger <rich at pasra.at>
Branch: vecopt-merge
Changeset: r79042:4886c173125a
Date: 2015-08-18 17:49 +0200
http://bitbucket.org/pypy/pypy/changeset/4886c173125a/

Log:	path iteration on a dependecy graph can enable blacklisting nodes
	that have already been visited.this cuts down the search space. this
	is only valid if a property must hold along all the paths and once
	for one path proven, any subpath must not be checked anymore (is the
	case in guard early exit

diff --git a/rpython/jit/metainterp/optimizeopt/dependency.py b/rpython/jit/metainterp/optimizeopt/dependency.py
--- a/rpython/jit/metainterp/optimizeopt/dependency.py
+++ b/rpython/jit/metainterp/optimizeopt/dependency.py
@@ -44,7 +44,12 @@
     def last_but_one(self):
         if len(self.path) < 2:
             return None
-        return self.path[len(self.path)-2]
+        return self.path[-2]
+
+    def last(self):
+        if len(self.path) < 1:
+            return None
+        return self.path[-1]
 
     def is_always_pure(self, exclude_first=False, exclude_last=False):
         last = len(self.path)-1
@@ -261,10 +266,16 @@
                 worklist.append(dep.to)
         return True
 
-    def iterate_paths(self, to, backwards=False, path_max_len=-1):
-        """ yield all nodes from self leading to 'to' """
+    def iterate_paths(self, to, backwards=False, path_max_len=-1, blacklist=False):
+        """ yield all nodes from self leading to 'to'. backwards determines
+        the iteration direction and blacklist marks nodes that have already been visited.
+        blacklist comes in handy if a property must hold for every path. not *every* possible
+        instance must be iterated, but trees that have already been visited can be ignored
+        after the have been visited
+        """
         if self is to:
             return
+        blacklist_visit = {}
         path = Path([self])
         worklist = [(0, self, 1)]
         while len(worklist) > 0:
@@ -274,19 +285,28 @@
             else:
                 iterdir = node.provides()
             if index >= len(iterdir):
+                if blacklist:
+                    blacklist_visit[node] = None
                 continue
             else:
                 next_dep = iterdir[index]
                 next_node = next_dep.to
                 index += 1
+                if blacklist and next_node in blacklist_visit:
+                    yield Path(path.path[:])
+                    continue
                 if index < len(iterdir):
                     worklist.append((index, node, pathlen))
+                else:
+                    blacklist_visit[node] = None
                 path.cut_off_at(pathlen)
                 path.walk(next_node)
                 pathlen += 1
 
                 if next_node is to or (path_max_len > 0 and pathlen >= path_max_len):
                     yield Path(path.path[:])
+                    if blacklist:
+                        blacklist_visit[next_node] = None
                 else:
                     worklist.append((0, next_node, pathlen))
 
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_dependency.py b/rpython/jit/metainterp/optimizeopt/test/test_dependency.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_dependency.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_dependency.py
@@ -434,5 +434,35 @@
         for i in r:
             assert paths[i].as_str() == "n0 -> %s -> n%d" % (nodes[i], len(r)+1)
 
+    def test_iterate_paths_blacklist_diamond(self):
+        blacklist = {}
+        n1,n2,n3,n4 = [FakeNode(i+1) for i in range(4)]
+        # n1 -> n2 -> n4
+        #  +---> n3 --^
+        n1.edge_to(n2); n2.edge_to(n4);
+        n1.edge_to(n3); n3.edge_to(n4);
+
+        paths = list(n1.iterate_paths(n4, blacklist=True))
+        assert len(paths) == 2
+        assert paths[0].as_str() == "n1 -> n2 -> n4"
+        assert paths[1].as_str() == "n1 -> n3"
+
+    def test_iterate_paths_blacklist_double_diamond(self):
+        blacklist = {}
+        n1,n2,n3,n4,n5,n6,n7,n8 = [FakeNode(i+1) for i in range(8)]
+        # n1 -> n2 -> n4 -> n5 -> n6 --> n8
+        #  +---> n3 --^      +---> n7 --^
+        n1.edge_to(n2); n2.edge_to(n4);
+        n1.edge_to(n3); n3.edge_to(n4);
+        n4.edge_to(n5)
+        n5.edge_to(n6); n6.edge_to(n8);
+        n5.edge_to(n7); n7.edge_to(n8);
+
+        paths = list(n1.iterate_paths(n8, blacklist=True))
+        assert len(paths) == 3
+        assert paths[0].as_str() == "n1 -> n2 -> n4 -> n5 -> n6 -> n8"
+        assert paths[1].as_str() == "n1 -> n2 -> n4 -> n5 -> n7"
+        assert paths[2].as_str() == "n1 -> n3"
+
 class TestLLtype(BaseTestDependencyGraph, LLtypeMixin):
     pass
diff --git a/rpython/jit/metainterp/optimizeopt/vectorize.py b/rpython/jit/metainterp/optimizeopt/vectorize.py
--- a/rpython/jit/metainterp/optimizeopt/vectorize.py
+++ b/rpython/jit/metainterp/optimizeopt/vectorize.py
@@ -521,7 +521,7 @@
             modify_later = []
             last_prev_node = None
             i = 0
-            for path in guard_node.iterate_paths(ee_guard_node, True):
+            for path in guard_node.iterate_paths(ee_guard_node, backwards=True, blacklist=True):
                 if not we_are_translated():
                     path.check_acyclic()
                 print "loop", i
@@ -545,7 +545,8 @@
                 else:
                     if path.is_always_pure(exclude_first=True, exclude_last=True):
                         path.set_schedule_priority(10)
-                        modify_later.append((path.last_but_one(), None))
+                        if path.last() is ee_guard_node:
+                            modify_later.append((path.last_but_one(), None))
                     else:
                         # transformation is invalid.
                         # exit and do not enter else branch!


More information about the pypy-commit mailing list