[pypy-svn] r73764 - in pypy/branch/blackhole-improvement/pypy: jit/metainterp jit/metainterp/test tool/algo

arigo at codespeak.net arigo at codespeak.net
Thu Apr 15 15:27:22 CEST 2010


Author: arigo
Date: Thu Apr 15 15:27:20 2010
New Revision: 73764

Added:
   pypy/branch/blackhole-improvement/pypy/jit/metainterp/codewriter2.py   (contents, props changed)
   pypy/branch/blackhole-improvement/pypy/jit/metainterp/test/test_codewriter2.py   (contents, props changed)
Modified:
   pypy/branch/blackhole-improvement/pypy/jit/metainterp/test/test_codewriter.py
   pypy/branch/blackhole-improvement/pypy/tool/algo/color.py
Log:
For now, start from scratch a codewriter2.  The coloring tests
pass.


Added: pypy/branch/blackhole-improvement/pypy/jit/metainterp/codewriter2.py
==============================================================================
--- (empty file)
+++ pypy/branch/blackhole-improvement/pypy/jit/metainterp/codewriter2.py	Thu Apr 15 15:27:20 2010
@@ -0,0 +1,77 @@
+import sys
+from pypy.tool.algo.color import DependencyGraph
+from pypy.tool.algo.unionfind import UnionFind
+from pypy.objspace.flow.model import Variable
+
+
+class BytecodeMaker(object):
+    DEBUG_REGALLOC = False
+
+    def __init__(self, graph):
+        self.graph = graph
+
+    def generate(self):
+        self.register_allocation()
+
+    def register_allocation(self):
+        dg = DependencyGraph()
+        #
+        pendingblocks = list(self.graph.iterblocks())
+        for block in pendingblocks:
+            # Compute die_at = {Variable: index_of_operation_with_last_usage}
+            die_at = dict.fromkeys(block.inputargs, 0)
+            for i, op in enumerate(block.operations):
+                for v in op.args:
+                    if isinstance(v, Variable):
+                        die_at[v] = i
+                if op.result is not None:
+                    die_at[op.result] = i
+            die_at[block.exitswitch] = sys.maxint
+            for link in block.exits:
+                for v in link.args:
+                    die_at[v] = sys.maxint
+            # Add the variables of this block to the dependency graph
+            for i, v in enumerate(block.inputargs):
+                dg.add_node(v)
+                for j in range(i):
+                    dg.add_edge(block.inputargs[j], v)
+            livevars = set(block.inputargs)
+            die_at = [(value, key) for (key, value) in die_at.items()]
+            die_at.sort()
+            die_at.append((sys.maxint,))
+            die_index = 0
+            for i, op in enumerate(block.operations):
+                while die_at[die_index][0] == i:
+                    livevars.remove(die_at[die_index][1])
+                    die_index += 1
+                if op.result is not None:
+                    livevars.add(op.result)
+                    dg.add_node(op.result)
+                    for v in livevars:
+                        dg.add_edge(v, op.result)
+        #
+        uf = UnionFind()
+        while pendingblocks:
+            block = pendingblocks.pop()
+            # Aggressively try to coalesce each source variable with its target
+            for link in block.exits:
+                for i, v in enumerate(link.args):
+                    if isinstance(v, Variable):
+                        w = link.target.inputargs[i]
+                        v0 = uf.find_rep(v)
+                        w0 = uf.find_rep(w)
+                        if v0 not in dg.neighbours[w0]:
+                            _, rep, _ = uf.union(v0, w0)
+                            assert rep is v0
+                            dg.coalesce(w0, v0)
+        #
+        self._coloring = dg.find_node_coloring()
+        self._unionfind = uf
+        if self.DEBUG_REGALLOC:
+            for block in self.graph.iterblocks():
+                print block
+                for v in block.getvariables():
+                    print '\t', v, '\t', self.getcolor(v)
+
+    def getcolor(self, v):
+        return self._coloring[self._unionfind.find_rep(v)]

Modified: pypy/branch/blackhole-improvement/pypy/jit/metainterp/test/test_codewriter.py
==============================================================================
--- pypy/branch/blackhole-improvement/pypy/jit/metainterp/test/test_codewriter.py	(original)
+++ pypy/branch/blackhole-improvement/pypy/jit/metainterp/test/test_codewriter.py	Thu Apr 15 15:27:20 2010
@@ -174,115 +174,6 @@
         rtyper = self.metainterp_sd.cpu.rtyper
         return graphof(rtyper.annotator.translator, func)
 
-    def encoding_test(self, func, args, ...):
-        graphs = self.make_graphs(func, args)
-        cw = CodeWriter(self.rtyper)
-        cw.candidate_graphs = graphs
-        cw._start(self.metainterp_sd, None)
-        maker = BytecodeMaker(cw, (graphs[0], None), False)
-        maker.generate()
-        ...
-
-    def test_bytecodemaker_generate_simple(self):
-        def f(n):
-            return n + 10
-        self.encoding_test(f, [5], """
-            [%i0]
-            int_add %i0 $10 %i0
-            int_return %i0
-        """)
-
-    def test_bytecodemaker_generate_regs(self):
-        def f(a, b, c):
-            return (((a + 10) * 2) + (b - c)) * a
-        self.encoding_test(f, [5, 6, 7], """
-            [%i0, %i1, %i2]
-            int_add %i0 $10 %i3
-            int_mul %i3 $2 %i3
-            int_sub %i1 %i2 %i1
-            int_add %i3 %i1 %i1
-            int_mul %i1 %i0 %i0
-            int_return %i0
-        """)
-
-    def test_bytecodemaker_generate_loop(self):
-        def f(a, b):
-            while a > 0:
-                b += a
-                a -= 1
-            return b
-        self.encoding_test(f, [5, 6], """
-            [%i0, %i1]
-            L0:
-            goto_if_not_int_gt %i0 $0 L1
-            int_add %i1 %i0 %i1
-            int_sub %i0 $1 %i0
-            goto L0
-            L1:
-            int_return %i1
-        """)
-
-    def test_bytecodemaker_generate_swap(self):
-        def f(a, b):
-            while a > 0:
-                a, b = b, b+a
-            return b
-        self.encoding_test(f, [5, 6], """
-            [%i0, %i1]
-            L0:
-            goto_if_not_int_gt %i0 $0 L1
-            int_add %i1 %i0 %i0
-            int_swap %i0 %i1
-            goto L0
-            L1:
-            int_return %i1
-        """)
-
-    def test_bytecodemaker_generate_cycle(self):
-        def f(a, b, c):
-            while a > 0:
-                a, b, c = b, c, a
-            return b
-        self.encoding_test(f, [5, 6], """
-            [%i0, %i1, %i2]
-            L0:
-            goto_if_not_int_gt %i0 $0 L1
-            int_swap_cycle [%i0, %i2, %i1]
-            goto L0
-            L1:
-            int_return %i1
-        """)
-
-    def test_bytecodemaker_generate_same_as_var(self):
-        def f(a, b, c):
-            while a > 0:
-                b = c
-            return b
-        self.encoding_test(f, [5, 6], """
-            [%i0, %i1, %i2]
-            L0:
-            goto_if_not_int_gt %i0 $0 L1
-            int_same_as %i2 %i1
-            goto L0
-            L1:
-            int_return %i1
-        """)
-
-    def test_bytecodemaker_generate_same_as_const(self):
-        def f(a, b, c):
-            while a > 0:
-                b = -17
-            return b
-        self.encoding_test(f, [5, 6], """
-            [%i0, %i1, %i2]
-            L0:
-            goto_if_not_int_gt %i0 $0 L1
-            int_same_as $-17 %i1
-            goto L0
-            L1:
-            int_return %i1
-        """)
-
     def test_basic(self):
         def f(n):
             return n + 10

Added: pypy/branch/blackhole-improvement/pypy/jit/metainterp/test/test_codewriter2.py
==============================================================================
--- (empty file)
+++ pypy/branch/blackhole-improvement/pypy/jit/metainterp/test/test_codewriter2.py	Thu Apr 15 15:27:20 2010
@@ -0,0 +1,165 @@
+from pypy.jit.metainterp import support
+from pypy.jit.metainterp.codewriter2 import BytecodeMaker
+
+
+class TestBytecodeMaker:
+
+    def make_graphs(self, func, values, type_system='lltype'):
+        self.rtyper = support.annotate(func, values, type_system=type_system)
+        return self.rtyper.annotator.translator.graphs
+
+    def coloring_test(self, func, args, expected_lambda):
+        graphs = self.make_graphs(func, args)
+        maker = BytecodeMaker(graphs[0])
+        maker.register_allocation()
+        expected = expected_lambda(graphs[0].startblock)
+        for v, num in expected.items():
+            print '\t%s\tcolor %d\texpected %d' % (v, maker.getcolor(v), num)
+        for v, num in expected.items():
+            assert maker.getcolor(v) == num
+
+    def encoding_test(self, func, args, expected):
+        graphs = self.make_graphs(func, args)
+        maker = BytecodeMaker(graphs[0])
+        maker.generate()
+        asm = maker.format_assembler()
+        expected = str(py.code.Source(expected)).strip()
+        assert asm == expected + '\n'
+
+    def test_coloring_simple(self):
+        def f(n):
+            return n + 10
+        self.coloring_test(f, [5],
+            lambda startblock:
+                {startblock.inputargs[0]: 0,
+                 startblock.operations[0].result: 0,
+                 startblock.exits[0].target.inputargs[0]: 0})
+
+    def test_coloring_bigblock(self):
+        def f(a, b, c):
+            return (((a + 10) * 2) + (b - c)) * a
+        self.coloring_test(f, [5, 6, 7],
+            lambda startblock:
+                {startblock.inputargs[0]: 0,
+                 startblock.inputargs[1]: 1,
+                 startblock.inputargs[2]: 2,
+                 startblock.operations[0].result: 3,
+                 startblock.operations[1].result: 3,
+                 startblock.operations[2].result: 1,
+                 startblock.operations[3].result: 1,
+                 startblock.operations[4].result: 0,
+                 startblock.exits[0].target.inputargs[0]: 0})
+
+    def test_bytecodemaker_generate_simple(self):
+        def f(n):
+            return n + 10
+        self.encoding_test(f, [5], """
+            [%i0]
+            int_add %i0, $10, %i0
+            int_return %i0
+        """)
+
+    def test_bytecodemaker_generate_bigblock(self):
+        def f(a, b, c):
+            return (((a + 10) * 2) + (b - c)) * a
+        self.encoding_test(f, [5, 6, 7], """
+            [%i0, %i1, %i2]
+            int_add %i0, $10, %i3
+            int_mul %i3, $2, %i3
+            int_sub %i1, %i2, %i1
+            int_add %i3, %i1, %i1
+            int_mul %i1, %i0, %i0
+            int_return %i0
+        """)
+
+    def test_bytecodemaker_generate_loop(self):
+        def f(a, b):
+            while a > 0:
+                b += a
+                a -= 1
+            return b
+        self.encoding_test(f, [5, 6], """
+            [%i0, %i1]
+            L0:
+            goto_if_not_int_gt %i0, $0, L1
+            int_add %i1, %i0, %i1
+            int_sub %i0, $1, %i0
+            goto L0
+            L1:
+            int_return %i1
+        """)
+
+    def test_bytecodemaker_generate_swap(self):
+        def f(a, b):
+            while a > 0:
+                a, b = b, b+a
+            return b
+        self.encoding_test(f, [5, 6], """
+            [%i0, %i1]
+            L0:
+            goto_if_not_int_gt %i0, $0, L1
+            int_add %i1, %i0, %i0
+            int_swap %i0, %i1
+            goto L0
+            L1:
+            int_return %i1
+        """)
+
+    def test_bytecodemaker_generate_cycle(self):
+        def f(a, b, c):
+            while a > 0:
+                a, b, c = b, c, a
+            return b
+        self.encoding_test(f, [5, 6, 7], """
+            [%i0, %i1, %i2]
+            L0:
+            goto_if_not_int_gt %i0, $0, L1
+            int_swap_cycle [%i0, %i2, %i1]
+            goto L0
+            L1:
+            int_return %i1
+        """)
+
+    def test_bytecodemaker_generate_same_as_var(self):
+        def f(a, b, c):
+            while a > 0:
+                b = c
+            return b
+        self.encoding_test(f, [5, 6, 7], """
+            [%i0, %i1, %i2]
+            L0:
+            goto_if_not_int_gt %i0, $0, L1
+            int_same_as %i2, %i1
+            goto L0
+            L1:
+            int_return %i1
+        """)
+
+    def test_bytecodemaker_generate_same_as_const(self):
+        def f(a, b):
+            while a > 0:
+                b = -17
+            return b
+        self.encoding_test(f, [5, 6], """
+            [%i0, %i1]
+            L0:
+            goto_if_not_int_gt %i0, $0, L1
+            int_same_as $-17, %i1
+            goto L0
+            L1:
+            int_return %i1
+        """)
+
+    def test_bytecodemaker_generate_return_const(self):
+        def f(a, b):
+            if a > b:
+                b = -17
+            return 1 + b
+        self.encoding_test(f, [5, 6], """
+            [%i0, %i1]
+            goto_if_not_int_gt %i0, %i1, L1
+            int_return $-16
+            L1:
+            int_add $1, %i1, %i0
+            int_return %i0
+        """)

Modified: pypy/branch/blackhole-improvement/pypy/tool/algo/color.py
==============================================================================
--- pypy/branch/blackhole-improvement/pypy/tool/algo/color.py	(original)
+++ pypy/branch/blackhole-improvement/pypy/tool/algo/color.py	Thu Apr 15 15:27:20 2010
@@ -2,21 +2,33 @@
 class DependencyGraph(object):
 
     def __init__(self):
-        self.nodes = []
+        self._all_nodes = []
         self.neighbours = {}
 
     def add_node(self, v):
         assert v not in self.neighbours, "duplicate vertex %r" % (v,)
-        self.nodes.append(v)
+        self._all_nodes.append(v)
         self.neighbours[v] = set()
 
     def add_edge(self, v1, v2):
         self.neighbours[v1].add(v2)
         self.neighbours[v2].add(v1)
 
+    def coalesce(self, vold, vnew):
+        """Remove vold from the graph, and attach all its edges to vnew."""
+        for n in self.neighbours.pop(vold):
+            self.neighbours[n].remove(vold)
+            self.neighbours[n].add(vnew)
+            self.neighbours[vnew].add(n)
+        # we should remove vold from self._all_nodes, but it's too costly
+        # so we rely on getnodes() to filter self._all_nodes.
+
+    def getnodes(self):
+        return [v for v in self._all_nodes if v in self.neighbours]
+
     def lexicographic_order(self):
         """Enumerate a lexicographic breath-first ordering of the nodes."""
-        sigma = [self.nodes[:]]
+        sigma = [self.getnodes()[::-1]]
         while sigma:
             v = sigma[0].pop()
             yield v



More information about the Pypy-commit mailing list