[pypy-commit] pypy no-failargs: In-progress: reduce the various numbers assigned to ResOps, including

arigo noreply at buildbot.pypy.org
Mon Oct 29 17:23:03 CET 2012


Author: Armin Rigo <arigo at tunes.org>
Branch: no-failargs
Changeset: r58586:e0e01c9c6532
Date: 2012-10-29 16:01 +0100
http://bitbucket.org/pypy/pypy/changeset/e0e01c9c6532/

Log:	In-progress: reduce the various numbers assigned to ResOps,
	including for __str__(). Now it adds a constraint to oparsed texts:
	we cannot use e.g. both 'p0' and 'i0' (only one variable is allowed
	at position 0), or 'f0' and 'f1' (float variables are assumed to
	take two positions each). This should be nicely checked by oparser,
	though.

diff --git a/pypy/jit/backend/llgraph/runner.py b/pypy/jit/backend/llgraph/runner.py
--- a/pypy/jit/backend/llgraph/runner.py
+++ b/pypy/jit/backend/llgraph/runner.py
@@ -635,6 +635,18 @@
         self.last_exception = None
 
     def setenv(self, box, arg):
+        if box.type == INT:
+            # typecheck the result
+            if isinstance(arg, bool):
+                arg = int(arg)
+            assert lltype.typeOf(arg) == lltype.Signed
+        elif box.type == REF:
+            assert lltype.typeOf(arg) == llmemory.GCREF
+        elif box.type == FLOAT:
+            assert lltype.typeOf(arg) == longlong.FLOATSTORAGE
+        else:
+            raise AssertionError(box)
+        #
         assert box.getvarindex() >= 0
         self.env[box] = arg
         self.framecontent[box.getvarindex()] = arg
@@ -673,24 +685,15 @@
                 if hasattr(gf.descr, '_llgraph_bridge'):
                     i = 0
                     self.lltrace = gf.descr._llgraph_bridge
-                    newvals = [self.env[arg] for arg in self.lltrace.inputargs]
+                    newvals = [self.framecontent[arg._varindex]
+                               for arg in self.lltrace.inputargs]
                     self.do_renaming(self.lltrace.inputargs, newvals)
                     continue
                 raise
-            if op.type == INT:
-                # typecheck the result
-                if isinstance(resval, bool):
-                    resval = int(resval)
-                assert lltype.typeOf(resval) == lltype.Signed
-            elif op.type == REF:
-                assert lltype.typeOf(resval) == llmemory.GCREF
-            elif op.type == FLOAT:
-                assert lltype.typeOf(resval) == longlong.FLOATSTORAGE
-            else:
-                assert op.type == VOID
-                assert resval is None
             if op.type != VOID:
                 self.setenv(op, resval)
+            else:
+                assert resval is None
             i += 1
 
     def do_renaming(self, newargs, newvalues):
diff --git a/pypy/jit/backend/test/runner_test.py b/pypy/jit/backend/test/runner_test.py
--- a/pypy/jit/backend/test/runner_test.py
+++ b/pypy/jit/backend/test/runner_test.py
@@ -24,51 +24,13 @@
 
     add_loop_instruction = ['overload for a specific cpu']
     bridge_loop_instruction = ['overload for a specific cpu']
-    _nextvarindex = 0
-
-    def update_varindexes(self, newtext2op):
-        # 'self.text2op' is a dict mapping variable names (as present in
-        # the oparser source) to the corresponding ResOp.  This function
-        # updates it with 'newtext2op', then assigns '_varindex' to all
-        # the new ResOps.  The choice of '_varindex' is done automatically
-        # to avoid conflicts, but existing '_varindex' are not changed.
-        # If 'newtext2op' is not a dict but a list, comes up with names
-        # as per str(op).
-        if isinstance(newtext2op, list):
-            newtext2op = dict([(str(op), op) for op in newtext2op])
-        try:
-            text2op = self.text2op
-        except AttributeError:
-            text2op = self.text2op = {}
-        text2op.update(newtext2op)
-        if newtext2op:
-            # update 'self._nextvarindex' to a value higher than any seen
-            # in newtext2op.  Pick two more rather than one more just in
-            # case the highest so far was a FLOAT.
-            newops = newtext2op.values()
-            random.shuffle(newops)
-            maximum = max([getattr(op, '_varindex', -2) for op in newops])
-            self._nextvarindex = max(self._nextvarindex, maximum + 2)
-            for op in newops:
-                self.assign_varindex(op)
-
-    def assign_varindex(self, op):
-        if (isinstance(op, AbstractResOp) and op.type != VOID and
-                getattr(op, '_varindex', -1) == -1):
-            op._varindex = self._nextvarindex
-            if hasattr(op, '_str'):
-                del op._str     # recompute it
-            # this op consumes either one or two numbers, depending on its
-            # type as a non-FLOAT or FLOAT.  We don't care too much about
-            # being on 32-bit vs 64-bit here.
-            self._nextvarindex += 1 + (op.type == FLOAT)
 
     def execute_operation(self, opname, valueboxes, result_type, descr=None):
         inputargs, operations = self._get_single_operation_list(opname,
                                                                 result_type,
                                                                 valueboxes,
                                                                 descr)
-        self.update_varindexes(inputargs + operations)
+        oparser.assign_all_varindices(inputargs + operations)
         looptoken = JitCellToken()
         self.cpu.compile_loop(inputargs, operations, looptoken)
         args = []
@@ -151,14 +113,11 @@
             namespace['faildescr3'] = BasicFailDescr(3)
         if 'faildescr4' not in namespace:
             namespace['faildescr4'] = BasicFailDescr(4)
-        loop = oparser.parse(s, namespace=namespace, mutable=True,
-                             oldvars=getattr(self, 'text2op', {}))
-        self.update_varindexes(loop.text2op)
+        loop = oparser.parse(s, namespace=namespace, mutable=True)
         return loop.inputargs, loop.operations, JitCellToken()
 
     def get_frame_value(self, frame, varname):
-        op = self.text2op[varname]
-        index = op.getvarindex()
+        index = int(varname[1:])
         if varname.startswith('i'):
             return self.cpu.get_frame_value_int(frame, index)
         if varname.startswith('p'):
@@ -184,8 +143,8 @@
         faildescr = BasicFailDescr(1)
         inputargs, ops, token = self.parse("""
         [f0]
-        f1 = float_add(f0, 1.)
-        finish(f1, descr=faildescr)
+        f2 = float_add(f0, 1.)
+        finish(f2, descr=faildescr)
         """, namespace=locals())
         self.cpu.compile_loop(inputargs, ops, token)
         frame = self.cpu.execute_token(token, longlong.getfloatstorage(2.8))
@@ -1208,9 +1167,9 @@
             label(%s, descr=targettoken)
             i1 = int_sub(i0, 1)
             i2 = int_ge(i1, 0)
-            guard_true(i2, descr=faildescr) [%s]
+            guard_true(i2, descr=faildescr)
             jump(%s, descr=targettoken)
-            """ % (inp, inp, inp, ", ".join(jumpargs)), None)
+            """ % (inp, inp, ", ".join(jumpargs)), None)
             #
             self.cpu.compile_loop(inpargs, operations, looptoken)
             #
@@ -1241,15 +1200,9 @@
             #
             assert dstvalues[index_counter] == 11
             dstvalues[index_counter] = 0
-            for i, (box, val) in enumerate(zip(inpargs, dstvalues)):
-                if box.type == 'i':
-                    got = self.cpu.get_latest_value_int(frame, i)
-                elif box.type == 'r':
-                    got = self.cpu.get_latest_value_ref(frame, i)
-                elif box.type == 'f':
-                    got = self.cpu.get_latest_value_float(frame, i)
-                else:
-                    assert 0
+            assert len(inputargs) == len(inpargs) == len(dstvalues)
+            for (name, val) in zip(inputargs, dstvalues):
+                got = self.get_frame_value(frame, name)
                 assert type(got) == type(val)
                 assert got == val
 
@@ -1264,8 +1217,8 @@
         [%(fboxes)s]
         label(%(fboxes)s, descr=targettoken)
         i2 = float_le(f0, 9.2)
-        guard_true(i2, descr=faildescr1) [%(fboxes)s]
-        finish(descr=faildescr2) [%(fboxes)s]
+        guard_true(i2, descr=faildescr1)
+        finish(descr=faildescr2)
         """ % {'fboxes': fboxes}, {'faildescr1': faildescr1,
                                    'faildescr2': faildescr2,
                                    'targettoken': targettoken})
@@ -1285,55 +1238,53 @@
             args.append(longlong.getfloatstorage(x))
         frame = self.cpu.execute_token(looptoken, *args)
         assert self.cpu.get_latest_descr(frame).identifier == 2
-        res = self.cpu.get_latest_value_float(frame, 0)
+        res = self.get_frame_value(frame, "f0")
         assert longlong.getrealfloat(res) == 8.5
-        for i in range(1, len(fboxes.split(","))):
-            got = longlong.getrealfloat(self.cpu.get_latest_value_float(frame, i))
+        fboxeslist = map(str.strip, fboxes.split(","))
+        for i in range(1, len(fboxeslist)):
+            res = self.get_frame_value(frame, fboxeslist[i])
+            got = longlong.getrealfloat(res)
             assert got == 13.5 + 6.73 * i
 
     def test_compile_bridge_spilled_float(self):
         if not self.cpu.supports_floats:
             py.test.skip("requires floats")
         fboxes = [boxfloat() for i in range(3)]
-        faildescr1 = BasicFailDescr(100)
         loopops = """
-        [i0,f1, f2]
+        [i0, f1, f2]
         f3 = float_add(f1, f2)
         force_spill(f3)
         force_spill(f1)
         force_spill(f2)
-        guard_false(i0, descr=faildescr0) [f1, f2, f3]
-        finish() []"""
+        guard_false(i0, descr=faildescr0)
+        finish()"""
         inputargs, operations, looptoken = self.parse(
             loopops, namespace={'faildescr0': BasicFailDescr(1)})
         self.cpu.compile_loop(inputargs, operations, looptoken)
         args = [1]
         args.append(longlong.getfloatstorage(132.25))
         args.append(longlong.getfloatstorage(0.75))
-        frame = self.cpu.execute_token(looptoken, *args)  #xxx check
+        frame = self.cpu.execute_token(looptoken, *args)
         assert operations[-2].getdescr()== self.cpu.get_latest_descr(frame)
-        f1 = self.cpu.get_latest_value_float(frame, 0)
-        f2 = self.cpu.get_latest_value_float(frame, 1)
-        f3 = self.cpu.get_latest_value_float(frame, 2)
+        f1 = self.get_frame_value(frame, "f1")
+        f2 = self.get_frame_value(frame, "f2")
+        f3 = self.get_frame_value(frame, "f3")
         assert longlong.getrealfloat(f1) == 132.25
         assert longlong.getrealfloat(f2) == 0.75
         assert longlong.getrealfloat(f3) == 133.0
 
+        faildescr1 = BasicFailDescr(100)
         bridgeops = [
             create_resop(rop.FINISH, None, [], descr=faildescr1,
                          mutable=True),
             ]
-        bridgeops[-1].setfailargs(fboxes)
         self.cpu.compile_bridge(operations[-2].getdescr(), fboxes,
                                 bridgeops, looptoken)
-        args = [1,
-                longlong.getfloatstorage(132.25),
-                longlong.getfloatstorage(0.75)]
         frame = self.cpu.execute_token(looptoken, *args)
         assert self.cpu.get_latest_descr(frame).identifier == 100
-        f1 = self.cpu.get_latest_value_float(frame, 0)
-        f2 = self.cpu.get_latest_value_float(frame, 1)
-        f3 = self.cpu.get_latest_value_float(frame, 2)
+        f1 = self.get_frame_value(frame, "f1")
+        f2 = self.get_frame_value(frame, "f2")
+        f3 = self.get_frame_value(frame, "f3")
         assert longlong.getrealfloat(f1) == 132.25
         assert longlong.getrealfloat(f2) == 0.75
         assert longlong.getrealfloat(f3) == 133.0
diff --git a/pypy/jit/metainterp/resoperation.py b/pypy/jit/metainterp/resoperation.py
--- a/pypy/jit/metainterp/resoperation.py
+++ b/pypy/jit/metainterp/resoperation.py
@@ -557,21 +557,21 @@
             return object.__repr__(self)
 
     def __str__(self):
-        if not hasattr(self, '_str'):
-            if self.type == INT:
-                t = 'i'
-            elif self.type == FLOAT:
-                t = 'f'
-            elif self.type == REF:
-                t = 'p'
-            else:
-                t = '?'
-            if getattr(self, '_varindex', -1) < 0:
-                self._str = '%s%d' % (t, AbstractResOp._counter)
+        if self.type == INT:
+            t = 'i'
+        elif self.type == FLOAT:
+            t = 'f'
+        elif self.type == REF:
+            t = 'p'
+        else:
+            t = '?'
+        if getattr(self, '_varindex', -1) < 0:
+            if not hasattr(self, '_str'):
                 AbstractResOp._counter += 1
-            else:
-                self._str = '%s%s' % (t.upper(), self._varindex)
-        return self._str
+                self._str = '%s-%d' % (t, AbstractResOp._counter)
+            return self._str
+        else:
+            return '%s%d' % (t, self._varindex)
 
     def repr(self, graytext=False):
         # RPython-friendly version
diff --git a/pypy/jit/tool/oparser.py b/pypy/jit/tool/oparser.py
--- a/pypy/jit/tool/oparser.py
+++ b/pypy/jit/tool/oparser.py
@@ -7,7 +7,7 @@
 
 from pypy.jit.metainterp.resoperation import rop, opclasses, rop_lowercase,\
      ResOpWithDescr, N_aryOp, UnaryOp, PlainResOp, create_resop_dispatch,\
-     ResOpNone, create_resop_0, example_for_opnum
+     ResOpNone, create_resop_0, example_for_opnum, FLOAT
 from pypy.jit.metainterp import optmodel
 from pypy.rpython.lltypesystem import lltype, llmemory
 from pypy.rlib.objectmodel import Symbolic
@@ -20,10 +20,8 @@
     use_mock_model = False
 
     def __init__(self, input, cpu, namespace, type_system,
-                 invent_fail_descr=True, results=None, mutable=False,
-                 oldvars={}):
+                 invent_fail_descr=True, results=None, mutable=False):
         self.input = input
-        self.oldvars = oldvars
         self.vars = {}
         self.cpu = cpu
         self._consts = namespace
@@ -33,6 +31,7 @@
         self.original_jitcell_token = self.model.JitCellToken()
         self.results = results
         self.mutable = mutable
+        self.allops = []
 
     def get_const(self, name, typ):
         if self._consts is None:
@@ -77,20 +76,17 @@
 
     def newvar(self, elem):
         if elem not in self.vars:
-            if elem not in self.oldvars:
-                if elem[0] in 'ifp':
-                    if elem[0] == 'p':
-                        p = 'r'
-                    else:
-                        p = elem[0]
-                    opnum = getattr(rop, 'INPUT_' + p)
-                    box = create_resop_0(opnum, example_for_opnum(opnum),
-                                         mutable=self.mutable)
+            if elem[0] in 'ifp':
+                if elem[0] == 'p':
+                    p = 'r'
                 else:
-                    raise ParseError("Unknown variable type: %s" % elem)
-                box._str = elem
+                    p = elem[0]
+                opnum = getattr(rop, 'INPUT_' + p)
+                box = create_resop_0(opnum, example_for_opnum(opnum),
+                                     mutable=self.mutable)
             else:
-                box = self.oldvars[elem]
+                raise ParseError("Unknown variable type: %s" % elem)
+            self.setstr(box, elem)
             self.vars[elem] = box
         return self.vars[elem]
 
@@ -203,10 +199,20 @@
         else:
             result = self.results[num]
         opres = self.create_op(opnum, result, args, descr)
-        opres._str = res
+        self.setstr(opres, res)
         self.vars[res] = opres
         return opres
 
+    def setstr(self, op, text):
+        op._str = text
+        try:
+            num = int(text[1:])
+        except ValueError:
+            num = -1
+        if num >= 0:
+            op._varindex = num
+        self.allops.append(op)
+
     def parse_op_no_result(self, line):
         opnum, args, descr = self.parse_op(line)
         res = self.create_op(opnum, None, args, descr)
@@ -242,13 +248,13 @@
         num, ops, last_offset = self.parse_ops(base_indent, newlines, 0)
         if num < len(newlines):
             raise ParseError("unexpected dedent at line: %s" % newlines[num])
+        assign_all_varindices(self.allops)
         loop = self.model.ExtendedTreeLoop("loop")
         loop.comment = first_comment
         loop.original_jitcell_token = self.original_jitcell_token
         loop.operations = ops
         loop.inputargs = inpargs
         loop.last_offset = last_offset
-        loop.text2op = self.vars
         return loop
 
     def parse_ops(self, indent, lines, start):
@@ -306,12 +312,42 @@
 
 def parse(input, cpu=None, namespace=DEFAULT, type_system='lltype',
           invent_fail_descr=True, OpParser=OpParser,
-          results=None, mutable=False, oldvars={}):
+          results=None, mutable=False):
     if namespace is DEFAULT:
         namespace = {}
     return OpParser(input, cpu, namespace, type_system,
-                    invent_fail_descr, results, mutable, oldvars).parse()
+                    invent_fail_descr, results, mutable).parse()
 
 def pure_parse(*args, **kwds):
     kwds['invent_fail_descr'] = False
     return parse(*args, **kwds)
+
+
+def assign_all_varindices(allops):
+    assigned_varindices = {}
+    unassigned_varindices = []
+    #
+    for op in allops:
+        if getattr(op, '_varindex', -1) >= 0:
+            num = op._varindex
+            assert num not in assigned_varindices, (
+                "duplicate or overlapping var: %s and %s" % (
+                op, assigned_varindices[num]))
+            assigned_varindices[num] = op
+            if op.type == FLOAT:
+                assert (num + 1) not in assigned_varindices, (
+                    "duplicate or overlapping var: %s and %s" % (
+                    op, assigned_varindices[num + 1]))
+                assigned_varindices[num + 1] = op
+        else:
+            unassigned_varindices.append(op)
+    #
+    nextindex = 0
+    for op in unassigned_varindices:
+        while (nextindex in assigned_varindices or
+               (op.type == FLOAT and (nextindex + 1) in assigned_varindices)):
+            nextindex += 1
+        op._varindex = nextindex
+        nextindex += 1
+        if op.type == FLOAT:
+            nextindex += 1
diff --git a/pypy/jit/tool/test/test_oparser.py b/pypy/jit/tool/test/test_oparser.py
--- a/pypy/jit/tool/test/test_oparser.py
+++ b/pypy/jit/tool/test/test_oparser.py
@@ -2,8 +2,8 @@
 import sys
 from pypy.rpython.lltypesystem import lltype, llmemory
 
-from pypy.jit.tool.oparser import parse, OpParser
-from pypy.jit.metainterp.resoperation import rop
+from pypy.jit.tool.oparser import parse, OpParser, assign_all_varindices
+from pypy.jit.metainterp.resoperation import rop, INT, FLOAT
 from pypy.jit.metainterp.history import AbstractDescr, JitCellToken,\
      TargetToken
 
@@ -250,3 +250,45 @@
         for modname, mod in sys.modules.iteritems():
             if isinstance(mod, ForbiddenModule):
                 sys.modules[modname] = mod.old_mod
+
+
+def test_assign_all_varindices():
+    class FakeOp:
+        def __init__(self, varindex=-1, type=INT):
+            self._varindex = varindex
+            self.type = type
+    def indices(lst):
+        return [op._varindex for op in lst]
+
+    ops = [FakeOp(5), FakeOp(6)]
+    assign_all_varindices(ops)
+    assert indices(ops) == [5, 6]
+
+    ops = [FakeOp(5), FakeOp(6, FLOAT)]
+    assign_all_varindices(ops)
+    assert indices(ops) == [5, 6]
+
+    ops = [FakeOp(5), FakeOp(5)]
+    py.test.raises(AssertionError, assign_all_varindices, ops)
+    ops = [FakeOp(5), FakeOp(5, FLOAT)]
+    py.test.raises(AssertionError, assign_all_varindices, ops)
+    ops = [FakeOp(5), FakeOp(4, FLOAT)]
+    py.test.raises(AssertionError, assign_all_varindices, ops)
+    ops = [FakeOp(4, FLOAT), FakeOp(5)]
+    py.test.raises(AssertionError, assign_all_varindices, ops)
+
+    ops = [FakeOp(), FakeOp(type=FLOAT), FakeOp(1)]
+    assign_all_varindices(ops)
+    assert indices(ops) == [0, 2, 1]
+
+    ops = [FakeOp(), FakeOp(type=FLOAT), FakeOp(2)]
+    assign_all_varindices(ops)
+    assert indices(ops) == [0, 3, 2]
+
+    ops = [FakeOp(), FakeOp(type=FLOAT), FakeOp(3)]
+    assign_all_varindices(ops)
+    assert indices(ops) == [0, 1, 3]
+
+    ops = [FakeOp(), FakeOp(type=FLOAT), FakeOp(2, FLOAT)]
+    assign_all_varindices(ops)
+    assert indices(ops) == [0, 4, 2]


More information about the pypy-commit mailing list