[pypy-svn] r74604 - in pypy/branch/blackhole-improvement/pypy/jit/codewriter: . test

arigo at codespeak.net arigo at codespeak.net
Thu May 20 19:30:52 CEST 2010


Author: arigo
Date: Thu May 20 19:30:50 2010
New Revision: 74604

Modified:
   pypy/branch/blackhole-improvement/pypy/jit/codewriter/flatten.py
   pypy/branch/blackhole-improvement/pypy/jit/codewriter/format.py
   pypy/branch/blackhole-improvement/pypy/jit/codewriter/liveness.py
   pypy/branch/blackhole-improvement/pypy/jit/codewriter/test/test_format.py
   pypy/branch/blackhole-improvement/pypy/jit/codewriter/test/test_liveness.py
Log:
Change the way I would like liveness.py to be.
Breaks all other code for now.


Modified: pypy/branch/blackhole-improvement/pypy/jit/codewriter/flatten.py
==============================================================================
--- pypy/branch/blackhole-improvement/pypy/jit/codewriter/flatten.py	(original)
+++ pypy/branch/blackhole-improvement/pypy/jit/codewriter/flatten.py	Thu May 20 19:30:50 2010
@@ -40,11 +40,14 @@
         self.kind = kind
         self.content = tuple(content)
     def __repr__(self):
-        return '%s%s' % (self.kind[0], self.content)
+        return '%s%s' % (self.kind[0].upper(), list(self.content))
     def __iter__(self):
         return iter(self.content)
     def __nonzero__(self):
         return bool(self.content)
+    def __eq__(self, other):
+        return (isinstance(other, ListOfKind) and
+                self.kind == other.kind and self.content == other.content)
 
 class IndirectCallTargets(object):
     def __init__(self, lst):
@@ -146,9 +149,11 @@
             self.emitline("reraise")
             return   # done
         if link.last_exception in link.args:
-            self.emitline("last_exception", self.getcolor(link.last_exception))
+            self.emitline("last_exception",
+                          "->", self.getcolor(link.last_exception))
         if link.last_exc_value in link.args:
-            self.emitline("last_exc_value", self.getcolor(link.last_exc_value))
+            self.emitline("last_exc_value",
+                          "->", self.getcolor(link.last_exc_value))
         self.make_link(link)
 
     def insert_exits(self, block):
@@ -292,9 +297,9 @@
                     if w is None:
                         self.emitline('%s_push' % kind, v)
                     elif v is None:
-                        self.emitline('%s_pop' % kind, w)
+                        self.emitline('%s_pop' % kind, "->", w)
                     else:
-                        self.emitline('%s_copy' % kind, v, w)
+                        self.emitline('%s_copy' % kind, v, "->", w)
 
     def emitline(self, *line):
         self.ssarepr.insns.append(line)
@@ -322,6 +327,7 @@
         if op.result is not None:
             kind = getkind(op.result.concretetype)
             if kind != 'void':
+                args.append("->")
                 args.append(self.getcolor(op.result))
         self.emitline(op.opname, *args)
 

Modified: pypy/branch/blackhole-improvement/pypy/jit/codewriter/format.py
==============================================================================
--- pypy/branch/blackhole-improvement/pypy/jit/codewriter/format.py	(original)
+++ pypy/branch/blackhole-improvement/pypy/jit/codewriter/format.py	Thu May 20 19:30:50 2010
@@ -56,9 +56,16 @@
         else:
             print >> output, asm[0],
             if len(asm) > 1:
-                lst = map(repr, asm[1:])
-                if asm[0] == '-live-': lst.sort()
-                print >> output, ', '.join(lst)
+                if asm[-2] == '->':
+                    if len(asm) == 3:
+                        print >> output, '->', repr(asm[-1])
+                    else:
+                        lst = map(repr, asm[1:-2])
+                        print >> output, ', '.join(lst), '->', repr(asm[-1])
+                else:
+                    lst = map(repr, asm[1:])
+                    if asm[0] == '-live-': lst.sort()
+                    print >> output, ', '.join(lst)
             else:
                 print >> output
     res = output.getvalue()
@@ -71,23 +78,25 @@
     explines = expected.split("\n")
     for asm, exp in zip(asmlines, explines):
         if asm != exp:
-            print
-            print "Got:      " + asm
-            print "Expected: " + exp
+            msg = [""]
+            msg.append("Got:      " + asm)
+            msg.append("Expected: " + exp)
             lgt = 0
             for i in range(min(len(asm), len(exp))):
                 if exp[i] == asm[i]:
                     lgt += 1
                 else:
                     break
-            print "          " + " " * lgt + "^^^^"
-            raise AssertionError
+            msg.append("          " + " " * lgt + "^^^^")
+            raise AssertionError('\n'.join(msg))
     assert len(asmlines) == len(explines)
 
 def unformat_assembler(text, registers=None):
     # XXX limited to simple assembler right now
     #
     def unformat_arg(s):
+        if s.endswith(','):
+            s = s[:-1].rstrip()
         if s[0] == '%':
             try:
                 return registers[s]
@@ -104,6 +113,21 @@
             return Constant(intvalue, lltype.Signed)
         elif s[0] == 'L':
             return TLabel(s)
+        elif s[0] in 'IRF' and s[1] == '[' and s[-1] == ']':
+            items = split_words(s[2:-1])
+            items = map(unformat_arg, items)
+            return ListOfKind({'I': 'int', 'R': 'ref', 'F': 'float'}[s[0]],
+                              items)
+        elif s.startswith('<SwitchDictDescr '):
+            assert s.endswith('>')
+            switchdict = SwitchDictDescr()
+            switchdict._labels = []
+            items = split_words(s[len('<SwitchDictDescr '):-1])
+            for item in items:
+                key, value = item.split(':')
+                value = value.rstrip(',')
+                switchdict._labels.append((int(key), TLabel(value)))
+            return switchdict
         else:
             raise AssertionError("unsupported argument: %r" % (s,))
     #
@@ -121,7 +145,33 @@
                 opname, line = line.split(None, 1)
             except ValueError:
                 opname, line = line, ''
-            line = [s.strip() for s in line.split(',')]
-            insn = [opname] + [unformat_arg(s) for s in line if s]
+            words = list(split_words(line))
+            if '->' in words:
+                assert words.index('->') == len(words) - 2
+                extra = ['->', unformat_arg(words[-1])]
+                del words[-2:]
+            else:
+                extra = []
+            insn = [opname] + [unformat_arg(s) for s in words] + extra
             ssarepr.insns.append(tuple(insn))
     return ssarepr
+
+
+def split_words(line):
+    word = ''
+    nested = 0
+    for i, c in enumerate(line):
+        if c == ' ' and nested == 0:
+            if word:
+                yield word
+                word = ''
+        else:
+            word += c
+            if c in '<([':
+                nested += 1
+            if c in '])>' and line[i-2:i+2] != ' -> ':
+                nested -= 1
+                assert nested >= 0
+    if word:
+        yield word
+    assert nested == 0

Modified: pypy/branch/blackhole-improvement/pypy/jit/codewriter/liveness.py
==============================================================================
--- pypy/branch/blackhole-improvement/pypy/jit/codewriter/liveness.py	(original)
+++ pypy/branch/blackhole-improvement/pypy/jit/codewriter/liveness.py	Thu May 20 19:30:50 2010
@@ -1,45 +1,79 @@
-from pypy.objspace.flow.model import Variable, SpaceOperation, c_last_exception
-from pypy.jit.codewriter.flatten import ListOfKind
+from pypy.jit.codewriter.flatten import Register, ListOfKind, Label, TLabel
+from pypy.jit.codewriter.jitcode import SwitchDictDescr
 
 
-# Some instruction require liveness information (the ones that can end up
-# in generate_guard() in pyjitpl.py); jtransform.py prefixes these opnames
-# with a 'G_'.  Additionally, boolean and general switches in the flow graph
-# will turn in 'goto_if_not_*' operations, which also require liveness info.
+# Some instructions require liveness information (the ones that can end up
+# in generate_guard() in pyjitpl.py).  This is done by putting special
+# space operations called '-live-' in the graph.  They turn into '-live-'
+# operation in the ssarepr.  Then this module expands the arguments of
+# the '-live-' operations to also include all values that are alive at
+# this point: more precisely, all values that are created before the
+# '-live-' operation and that are needed afterwards, with the exception
+# of the values that are needed only in the very next instruction.  These
+# are not considered alive any more.  You can force them to be alive by
+# putting them as args of the '-live-' operation in the first place.
+
+# For this to work properly, a special operation called '---' must be
+# used to mark unreachable places (e.g. just after a 'goto').
 
 # ____________________________________________________________
 
-def compute_liveness(graph, switches_require_liveness=True):
-    for block in graph.iterblocks():
-        num_operations = len(block.operations)
-        alive = set()
-        for link in block.exits:
-            for v in link.args:
-                if (v is not link.last_exception and
-                    v is not link.last_exc_value):
-                    alive.add(v)
-        if switches_require_liveness:
-            if len(block.exits) > 1 and block.exitswitch != c_last_exception:
-                block.operations.append(_livespaceop(alive))
-        if isinstance(block.exitswitch, tuple):
-            for v in block.exitswitch[1:]:
-                alive.add(v)
-        else:
-            alive.add(block.exitswitch)
-        for i in range(num_operations-1, -1, -1):
-            op = block.operations[i]
-            try:
-                alive.remove(op.result)
-            except KeyError:
-                pass
-            if op.opname.startswith('G_'):
-                block.operations.insert(i, _livespaceop(alive))
-            for v in op.args:
-                if isinstance(v, ListOfKind):
-                    alive.update(v)
-                else:
-                    alive.add(v)
-
-def _livespaceop(alive):
-    livevars = [v for v in alive if isinstance(v, Variable)]
-    return SpaceOperation('-live-', livevars, None)
+def compute_liveness(ssarepr):
+    label2alive = {}
+    while _compute_liveness_must_continue(ssarepr, label2alive):
+        pass
+
+def _compute_liveness_must_continue(ssarepr, label2alive):
+    alive = set()
+    prevalive = None
+    must_continue = False
+
+    for i in range(len(ssarepr.insns)-1, -1, -1):
+        insn = ssarepr.insns[i]
+
+        if isinstance(insn[0], Label):
+            alive_at_point = label2alive.setdefault(insn[0].name, set())
+            prevlength = len(alive_at_point)
+            alive_at_point.update(alive)
+            if prevlength != len(alive_at_point):
+                must_continue = True
+            prevalive = None
+            continue
+
+        if insn[0] == '-live-':
+            assert prevalive is not None
+            for x in insn[1:]:
+                prevalive.discard(x)
+            ssarepr.insns[i] = insn + tuple(prevalive)
+            prevalive = None
+            continue
+
+        if insn[0] == '---':
+            alive = set()
+            prevalive = None
+            continue
+
+        args = insn[1:]
+        #
+        if len(args) >= 2 and args[-2] == '->':
+            reg = args[-1]
+            assert isinstance(reg, Register)
+            alive.discard(reg)
+            args = args[:-2]
+        #
+        prevalive = alive.copy()
+        #
+        for x in args:
+            if isinstance(x, Register):
+                alive.add(x)
+            elif isinstance(x, ListOfKind):
+                alive.update(x)
+            elif isinstance(x, TLabel):
+                alive_at_point = label2alive.get(x.name, ())
+                alive.update(alive_at_point)
+            elif isinstance(x, SwitchDictDescr):
+                for key, label in x._labels:
+                    alive_at_point = label2alive.get(label.name, ())
+                    alive.update(alive_at_point)
+
+    return must_continue

Modified: pypy/branch/blackhole-improvement/pypy/jit/codewriter/test/test_format.py
==============================================================================
--- pypy/branch/blackhole-improvement/pypy/jit/codewriter/test/test_format.py	(original)
+++ pypy/branch/blackhole-improvement/pypy/jit/codewriter/test/test_format.py	Thu May 20 19:30:50 2010
@@ -4,6 +4,7 @@
 from pypy.jit.codewriter.flatten import Label, TLabel, SSARepr, Register
 from pypy.jit.codewriter.flatten import ListOfKind
 from pypy.jit.metainterp.history import AbstractDescr
+from pypy.jit.codewriter.jitcode import SwitchDictDescr
 from pypy.rpython.lltypesystem import lltype
 
 
@@ -11,12 +12,12 @@
     ssarepr = SSARepr("test")
     i0, i1, i2 = Register('int', 0), Register('int', 1), Register('int', 2)
     ssarepr.insns = [
-        ('int_add', i0, i1, i2),
+        ('int_add', i0, i1, '->', i2),
         ('int_return', i2),
         ]
     asm = format_assembler(ssarepr)
     expected = """
-        int_add %i0, %i1, %i2
+        int_add %i0, %i1 -> %i2
         int_return %i2
     """
     assert asm == str(py.code.Source(expected)).strip() + '\n'
@@ -39,11 +40,11 @@
     s.x = 123
     ssarepr = SSARepr("test")
     ssarepr.insns = [
-        ('foobar', Constant(s, lltype.typeOf(s))),
+        ('foobar', '->', Constant(s, lltype.typeOf(s))),
         ]
     asm = format_assembler(ssarepr)
     expected = """
-        foobar $<* struct S>
+        foobar -> $<* struct S>
     """
     assert asm == str(py.code.Source(expected)).strip() + '\n'
 
@@ -53,8 +54,8 @@
     ssarepr.insns = [
         (Label('L1'),),
         ('goto_if_not_int_gt', i0, Constant(0, lltype.Signed), TLabel('L2')),
-        ('int_add', i1, i0, i1),
-        ('int_sub', i0, Constant(1, lltype.Signed), i0),
+        ('int_add', i1, i0, '->', i1),
+        ('int_sub', i0, Constant(1, lltype.Signed), '->', i0),
         ('goto', TLabel('L1')),
         (Label('L2'),),
         ('int_return', i1),
@@ -63,8 +64,8 @@
     expected = """
         L1:
         goto_if_not_int_gt %i0, $0, L2
-        int_add %i1, %i0, %i1
-        int_sub %i0, $1, %i0
+        int_add %i1, %i0 -> %i1
+        int_sub %i0, $1 -> %i0
         goto L1
         L2:
         int_return %i1
@@ -99,7 +100,7 @@
 
 def test_unformat_assembler_simple():
     input = """
-        int_add %i0, %i1, %i2
+        int_add %i0, %i1 -> %i2
         int_return %i2
     """
     regs = {}
@@ -107,7 +108,7 @@
     assert regs['%i2'].kind == 'int'
     assert regs['%i2'].index == 2
     assert ssarepr.insns == [
-        ('int_add', regs['%i0'], regs['%i1'], regs['%i2']),
+        ('int_add', regs['%i0'], regs['%i1'], '->', regs['%i2']),
         ('int_return', regs['%i2']),
         ]
 
@@ -134,3 +135,30 @@
         (Label('L2'),),
         ('bar', TLabel('L1')),
         ]
+
+def test_unformat_assembler_lists():
+    input = """
+        foo F[%f0, %f3]
+    """
+    regs = {}
+    ssarepr = unformat_assembler(input, regs)
+    assert ssarepr.insns == [
+        ('foo', ListOfKind('float', [regs['%f0'], regs['%f3']]))
+        ]
+
+def test_unformat_switchdictdescr():
+    input = """
+        foo <SwitchDictDescr 4:L2, 5:L1>
+        L1:
+        L2:
+    """
+    regs = {}
+    ssarepr = unformat_assembler(input, regs)
+    sdd = ssarepr.insns[0][1]
+    assert ssarepr.insns == [
+        ('foo', sdd),
+        (Label('L1'),),
+        (Label('L2'),),
+        ]
+    assert isinstance(sdd, SwitchDictDescr)
+    assert sdd._labels == [(4, TLabel('L2')), (5, TLabel('L1'))]

Modified: pypy/branch/blackhole-improvement/pypy/jit/codewriter/test/test_liveness.py
==============================================================================
--- pypy/branch/blackhole-improvement/pypy/jit/codewriter/test/test_liveness.py	(original)
+++ pypy/branch/blackhole-improvement/pypy/jit/codewriter/test/test_liveness.py	Thu May 20 19:30:50 2010
@@ -1,153 +1,189 @@
-from pypy.jit.codewriter import support
 from pypy.jit.codewriter.liveness import compute_liveness
-from pypy.jit.codewriter.test.test_flatten import fake_regallocs
-from pypy.jit.codewriter.flatten import flatten_graph, ListOfKind
-from pypy.jit.codewriter.format import assert_format
-from pypy.objspace.flow.model import SpaceOperation
+from pypy.jit.codewriter.format import unformat_assembler, assert_format
 
 
 class TestFlatten:
 
-    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 add_G_prefix(self, graph):
-        """Add a 'G_' prefix to the opnames 'int_add' and 'int_mul'.
-        Turn the arguments of float_add into a ListOfKind()."""
-        def with_prefix(op):
-            if op.opname in ('int_add', 'int_mul'):
-                return SpaceOperation('G_' + op.opname, op.args, op.result)
-            if op.opname == 'float_add':
-                return SpaceOperation(op.opname,
-                                      [ListOfKind('float', op.args)],
-                                      op.result)
-            return op
-        #
-        for block in graph.iterblocks():
-            if block.operations:
-                block.operations = map(with_prefix, block.operations)
-
-    def encoding_test(self, func, args, expected,
-                      switches_require_liveness=False):
-        graphs = self.make_graphs(func, args)
-        self.add_G_prefix(graphs[0])
-        compute_liveness(graphs[0], switches_require_liveness)
-        ssarepr = flatten_graph(graphs[0], fake_regallocs())
-        assert_format(ssarepr, expected)
+    def liveness_test(self, input, output):
+        ssarepr = unformat_assembler(input)
+        compute_liveness(ssarepr)
+        assert_format(ssarepr, output)
 
     def test_simple_no_live(self):
-        def f(n):
-            return n + 10
-        self.encoding_test(f, [5], """
+        self.liveness_test("""
             -live-
-            G_int_add %i0, $10, %i1
-            int_return %i1
+            int_add %i0, $10 -> %i1
+        """, """
+            -live-
+            int_add %i0, $10 -> %i1
         """)
 
     def test_simple(self):
-        def f(n):
-            return (n + 10) * (n + 3) * (n + 6)
-        self.encoding_test(f, [5], """
+        self.liveness_test("""
+            -live-
+            int_add %i0, $10 -> %i1
+            -live-
+            int_add %i0, $3 -> %i2
+            -live-
+            int_mul %i1, %i2 -> %i3
+            -live-
+            int_add %i0, $6 -> %i4
+            -live-
+            int_mul %i3, %i4 -> %i5
+            int_return %i5
+        """, """
             -live- %i0
-            G_int_add %i0, $10, %i1
+            int_add %i0, $10 -> %i1
             -live- %i0, %i1
-            G_int_add %i0, $3, %i2
+            int_add %i0, $3 -> %i2
             -live- %i0
-            G_int_mul %i1, %i2, %i3
+            int_mul %i1, %i2 -> %i3
             -live- %i3
-            G_int_add %i0, $6, %i4
+            int_add %i0, $6 -> %i4
             -live-
-            G_int_mul %i3, %i4, %i5
+            int_mul %i3, %i4 -> %i5
             int_return %i5
         """)
 
     def test_one_path(self):
-        def f(x, y):
-            if x+5:
-                return x+1
-            return y+2
-        self.encoding_test(f, [5, 6], """
+        self.liveness_test("""
+            -live-
+            int_add %i0, $5 -> %i2
+            int_is_true %i2 -> %i3
+            goto_if_not %i3, L1
+            int_copy %i0 -> %i4
+            -live-
+            int_add %i4, $1 -> %i5
+            int_return %i5
+            ---
+            L1:
+            int_copy %i1 -> %i6
+            -live-
+            int_add %i6, $2 -> %i7
+            int_return %i7
+        """, """
             -live- %i0, %i1
-            G_int_add %i0, $5, %i2
-            int_is_true %i2, %i3
+            int_add %i0, $5 -> %i2
+            int_is_true %i2 -> %i3
             goto_if_not %i3, L1
-            int_copy %i0, %i4
+            int_copy %i0 -> %i4
             -live-
-            G_int_add %i4, $1, %i5
+            int_add %i4, $1 -> %i5
             int_return %i5
+            ---
             L1:
-            int_copy %i1, %i6
+            int_copy %i1 -> %i6
             -live-
-            G_int_add %i6, $2, %i7
+            int_add %i6, $2 -> %i7
             int_return %i7
         """)
 
     def test_other_path(self):
-        def f(x, y):
-            if x+5:
-                return x+y
-            return x+2
-        self.encoding_test(f, [5, 6], """
+        self.liveness_test("""
+            -live-
+            int_add %i0, $5 -> %i2
+            int_is_true %i2 -> %i3
+            goto_if_not %i3, L1
+            int_copy %i0 -> %i4
+            int_copy %i1 -> %i5
+            -live-
+            int_add %i4, %i5 -> %i6
+            int_return %i6
+            ---
+            L1:
+            int_copy %i0 -> %i7
+            -live-
+            int_add %i7, $2 -> %i8
+            int_return %i8
+        """, """
             -live- %i0, %i1
-            G_int_add %i0, $5, %i2
-            int_is_true %i2, %i3
+            int_add %i0, $5 -> %i2
+            int_is_true %i2 -> %i3
             goto_if_not %i3, L1
-            int_copy %i0, %i4
-            int_copy %i1, %i5
+            int_copy %i0 -> %i4
+            int_copy %i1 -> %i5
             -live-
-            G_int_add %i4, %i5, %i6
+            int_add %i4, %i5 -> %i6
             int_return %i6
+            ---
             L1:
-            int_copy %i0, %i7
+            int_copy %i0 -> %i7
             -live-
-            G_int_add %i7, $2, %i8
+            int_add %i7, $2 -> %i8
             int_return %i8
         """)
 
     def test_no_path(self):
-        def f(x, y):
-            if x+y:
-                return x+5
-            return x+2
-        self.encoding_test(f, [5, 6], """
+        self.liveness_test("""
+            -live-
+            int_add %i0, %i1 -> %i2
+            int_is_true %i2 -> %i3
+            goto_if_not %i3, L1
+            int_copy %i0 -> %i4
+            -live-
+            int_add %i4, $5 -> %i5
+            int_return %i5
+            ---
+            L1:
+            int_copy %i0 -> %i6
+            -live-
+            int_add %i6, $2 -> %i7
+            int_return %i7
+        """, """
             -live- %i0
-            G_int_add %i0, %i1, %i2
-            int_is_true %i2, %i3
+            int_add %i0, %i1 -> %i2
+            int_is_true %i2 -> %i3
             goto_if_not %i3, L1
-            int_copy %i0, %i4
+            int_copy %i0 -> %i4
             -live-
-            G_int_add %i4, $5, %i5
+            int_add %i4, $5 -> %i5
             int_return %i5
+            ---
             L1:
-            int_copy %i0, %i6
+            int_copy %i0 -> %i6
             -live-
-            G_int_add %i6, $2, %i7
+            int_add %i6, $2 -> %i7
             int_return %i7
         """)
 
-    def test_switch_require_liveness(self):
-        def f(x, y):
-            if x:
-                return x
-            return y
-        self.encoding_test(f, [5, 6], """
-            int_is_true %i0, %i2
-            -live- %i0, %i1
-            goto_if_not %i2, L1
-            int_return %i0
-            L1:
-            int_return %i1
-        """, switches_require_liveness=True)
-
     def test_list_of_kind(self):
-        def f(x, y, z, t):
-            return (x + y) * (z + t)
-        self.encoding_test(f, [5, 6, 3.2, 4.3], """
-            -live- %f0, %f1
-            G_int_add %i0, %i1, %i2
-            float_add F[%f0, %f1], %f2
-            cast_int_to_float %i2, %f3
-            float_mul %f3, %f2, %f4
-            float_return %f4
+        self.liveness_test("""
+            -live-
+            stub
+            foobar F[%f0]
+        """, """
+            -live- %f0
+            stub
+            foobar F[%f0]
+        """)
+
+    def test_switch(self):
+        self.liveness_test("""
+            goto_maybe L1
+            -live-
+            stub
+            fooswitch <SwitchDictDescr 4:L2, 5:L3>
+            ---
+            L3:
+            int_return %i7
+            ---
+            L1:
+            int_return %i4
+            ---
+            L2:
+            int_return %i3
+        """, """
+            goto_maybe L1
+            -live- %i3, %i7
+            stub
+            fooswitch <SwitchDictDescr 4:L2, 5:L3>
+            ---
+            L3:
+            int_return %i7
+            ---
+            L1:
+            int_return %i4
+            ---
+            L2:
+            int_return %i3
         """)



More information about the Pypy-commit mailing list