[pypy-svn] r20639 - in pypy/dist/pypy/rpython/l3interp: . test

arigo at codespeak.net arigo at codespeak.net
Sun Dec 4 13:46:50 CET 2005


Author: arigo
Date: Sun Dec  4 13:46:47 2005
New Revision: 20639

Modified:
   pypy/dist/pypy/rpython/l3interp/l3interp.py
   pypy/dist/pypy/rpython/l3interp/model.py
   pypy/dist/pypy/rpython/l3interp/test/test_convert.py
   pypy/dist/pypy/rpython/l3interp/test/test_l3interp.py
Log:
Simplifying the L3 graph model...


Modified: pypy/dist/pypy/rpython/l3interp/l3interp.py
==============================================================================
--- pypy/dist/pypy/rpython/l3interp/l3interp.py	(original)
+++ pypy/dist/pypy/rpython/l3interp/l3interp.py	Sun Dec  4 13:46:47 2005
@@ -1,80 +1,207 @@
 from pypy.rpython.l3interp import model
 from pypy.rpython.memory import lladdress
+from pypy.rpython.rarithmetic import r_uint
+from pypy.interpreter.miscutils import InitializedClass
+
+class L3Exception(Exception):
+    pass
 
-class LLException(Exception):
-    def __init__(self):
-        pass
-
-class LLInterpreter(object):
-    def __init__(self, globals):
-        self.globals = globals
-    def eval_graph_int(self, graph, args):
-        frame = LLFrame(graph, self)
-        returnlink = frame.eval(args)
-        return frame.get_int(0)
-
-class LLFrame(object):
-    def __init__(self, graph, lli):
-        self.interp = lli
-        self.graph = graph
-        self.int_vars = [0] * graph.max_num_ints
 
-    def eval(self, int_values):
-        link = self.graph.startlink
-        self.copy_startlink_vars(link, int_values)
-        while not link.stop_graph_evaluation:
-            link = self.eval_block(link.target)
-            self.copy_link_vars(link)
-        return link
-
-    def eval_block(self, block):
-        for op in block.operations:
-#            print op.opimpl, op.result, op.args, self.int_vars
-            op.opimpl(self, op.result, op.args)
-        exitswitch = block.exitswitch
-        if exitswitch >= 0:
-            link = block.exits[self.int_vars[exitswitch]]
-            return link
-        return block.exits[0]
-        
-    def copy_startlink_vars(self, link, int_values):
-#        print "copy_startlink_vars", int_values, link.move_int_registers
-        if link.move_int_registers is None:
-            return
-        for i in range(0, len(link.move_int_registers), 2):
-            source = link.move_int_registers[i]
-            target = link.move_int_registers[i + 1]
-            self.set_int(target, int_values[source])
-
-    def copy_link_vars(self, link):
-#        print "copy_link_vars", link.move_int_registers, self.int_vars
-        if link.move_int_registers is None: 
-            return
-        for i in range(0, len(link.move_int_registers), 2):
-            source = link.move_int_registers[i]
-            target = link.move_int_registers[i + 1]
-            self.set_int(target, self.get_int(source))
-
-    def get_int(self, index):
-        if index < 0:
-            return self.graph.constants_int[~index]
+class L3Value(object):
+    pass
+
+class L3Integer(L3Value):
+    def __init__(self, intval):
+        self.intval = intval
+
+class L3Double(L3Value):
+    def __init__(self, dblval):
+        self.dblval = dblval
+
+class L3Pointer(L3Value):
+    def __init__(self, ptrval):
+        self.ptrval = ptrval
+
+
+def l3interpret(graph, args_int, args_dbl, args_ptr):
+    assert len(args_int) == graph.nargs_int
+    assert len(args_dbl) == graph.nargs_dbl
+    assert len(args_ptr) == graph.nargs_ptr
+    frame = L3Frame(graph, args_int, args_dbl, args_ptr)
+    frame.execute()
+    nint = len(args_int) - graph.nargs_int
+    ndbl = len(args_dbl) - graph.nargs_dbl
+    nptr = len(args_ptr) - graph.nargs_ptr
+    if nint == 1 and ndbl == 0 and nptr == 0:
+        return L3Integer(args_int.pop())
+    if nint == 0 and ndbl == 1 and nptr == 0:
+        return L3Double(args_dbl.pop())
+    if nint == 0 and ndbl == 0 and nptr == 1:
+        return L3Pointer(args_ptr.pop())
+    raise AssertionError("stacks corrupted")
+
+class L3Frame(object):
+    
+    def __init__(self, graph, stack_int, stack_dbl, stack_ptr):
+        self.graph = graph
+        self.block = self.graph.startblock
+        self.i = 0
+        self.stack_int = stack_int
+        self.stack_dbl = stack_dbl
+        self.stack_ptr = stack_ptr
+        self.base_int = len(stack_int)
+        self.base_dbl = len(stack_dbl)
+        self.base_ptr = len(stack_ptr)
+
+    def nextop(self):
+        i = self.i
+        self.i = i+1
+        return self.block.insns[i]
+
+    def nextuop(self):
+        return r_uint(self.nextop())
+
+    def execute(self):
+        try:
+            while True:
+                op = self.nextuop()
+                ophandler = L3Frame.dispatch_table[op]
+                ophandler(self)
+        except L3Return:
+            pass
+
+    def followlink(self, link):
+        assert isinstance(link, model.Link)
+        if link.targetregs_int is None:
+            del self.stack_int[self.base_int:]
+        else:
+            buf = [0] * len(link.targetregs_int)
+            for i in range(len(link.targetregs_int)):
+                op = link.targetregs_int[i]
+                if op >= 0: buf[i] = self.block.constants_int[op]
+                else:       buf[i] = self.stack_int[op]
+            del self.stack_int[self.base_int:]
+            self.stack_int.extend(buf)
+        if link.targetregs_dbl is None:
+            del self.stack_dbl[self.base_dbl:]
         else:
-            return self.int_vars[index]
+            buf = [0.0] * len(link.targetregs_dbl)
+            for i in range(len(link.targetregs_dbl)):
+                op = link.targetregs_dbl[i]
+                if op >= 0: buf[i] = self.block.constants_dbl[op]
+                else:       buf[i] = self.stack_dbl[op]
+            del self.stack_dbl[self.base_dbl:]
+            self.stack_dbl.extend(buf)
+        if link.targetregs_ptr is None:
+            del self.stack_ptr[self.base_ptr:]
+        else:
+            buf = [lladdress.NULL] * len(link.targetregs_ptr)
+            for i in range(len(link.targetregs_ptr)):
+                op = link.targetregs_ptr[i]
+                if op >= 0: buf[i] = self.block.constants_ptr[op]
+                else:       buf[i] = self.stack_ptr[op]
+            del self.stack_ptr[self.base_ptr:]
+            self.stack_ptr.extend(buf)
+        self.block = link.target
+        self.i = 0
+
+    __metaclass__ = InitializedClass
+    def __initclass__(cls):
+        "NOT_RPYTHON"
+        def make_missing_handler(opname):
+            def missing_handler(self):
+                print 'XXX missing handler for operation', opname
+                raise NotImplementedError
+        cls.dispatch_table = []
+        for opname in model.very_low_level_ops:
+            try:
+                fn = getattr(cls, 'op_' + opname).im_func
+            except AttributeError:
+                fn = make_missing_handler(opname)
+            cls.dispatch_table.append(fn)
+
+    # ____________________________________________________________
+
+    def getint(self):
+        op = self.nextop()
+        if op >= 0: return self.block.constants_int[op]
+        else:       return self.stack_int[op]
+
+    def getdbl(self):
+        op = self.nextop()
+        if op >= 0: return self.block.constants_dbl[op]
+        else:       return self.stack_dbl[op]
+
+    def getptr(self):
+        op = self.nextop()
+        if op >= 0: return self.block.constants_ptr[op]
+        else:       return self.stack_ptr[op]
+
+    def restorestacks(self):
+        del self.stack_int[self.base_int:]
+        del self.stack_dbl[self.base_dbl:]
+        del self.stack_ptr[self.base_ptr:]
+
+    def op_void_return(self):
+        self.restorestacks()
+        raise L3Return
+
+    def op_int_return(self):
+        x = self.getint()
+        self.restorestacks()
+        self.stack_int.append(x)
+        raise L3Return
+
+    def op_dbl_return(self):
+        x = self.getdbl()
+        self.restorestacks()
+        self.stack_dbl.append(x)
+        raise L3Return
+
+    def op_ptr_return(self):
+        x = self.getptr()
+        self.restorestacks()
+        self.stack_ptr.append(x)
+        raise L3Return
+
+    def op_jump(self):
+        self.followlink(self.block.exit0)
+
+    def op_jump_cond(self):
+        x = self.getint()
+        if x:
+            link = self.block.exit1
+        else:
+            link = self.block.exit0
+        self.followlink(link)
+
+    def op_int_add(self):
+        x = self.getint()
+        y = self.getint()
+        self.stack_int.append(x + y)
+
+    def op_direct_call(self):
+        assert self.block.called_graphs is not None
+        graph = self.block.called_graphs[self.nextuop()]
+        if graph.nargs_int:
+            buf = [0] * graph.nargs_int
+            for i in range(graph.nargs_int):
+                buf[i] = self.getint()
+            self.stack_int.extend(buf)
+        if graph.nargs_dbl:
+            buf = [0.0] * graph.nargs_dbl
+            for i in range(graph.nargs_dbl):
+                buf[i] = self.getdbl()
+            self.stack_dbl.extend(buf)
+        if graph.nargs_ptr:
+            buf = [lladdress.NULL] * graph.nargs_ptr
+            for i in range(graph.nargs_ptr):
+                buf[i] = self.getptr()
+            self.stack_ptr.extend(buf)
+        frame = L3Frame(graph, self.stack_int, self.stack_dbl, self.stack_ptr)
+        frame.execute()
 
-    def set_int(self, index, val):
-        self.int_vars[index] = val
+    # ____________________________________________________________
 
-    def op_int_add(self, result, args):
-        int1 = self.get_int(args[0])
-        int2 = self.get_int(args[1])
-        self.set_int(result, int1 + int2)
-        
-    def op_int_is_true(self, result, args):
-        int1 = self.get_int(args[0])
-        self.set_int(result, bool(int1))
-
-    def op_call_graph_int(self, result, args):
-        graph = self.interp.globals.graphs[args[0]]
-        concrete_args = [self.get_int(arg) for arg in args[1:]]
-        r = self.interp.eval_graph_int(graph, concrete_args)
-        self.set_int(result, r)
+class L3Return(Exception):
+    pass

Modified: pypy/dist/pypy/rpython/l3interp/model.py
==============================================================================
--- pypy/dist/pypy/rpython/l3interp/model.py	(original)
+++ pypy/dist/pypy/rpython/l3interp/model.py	Sun Dec  4 13:46:47 2005
@@ -3,6 +3,12 @@
 from pypy.rpython.lltypesystem import lltype
 
 very_low_level_ops = [
+    'nop',
+
+    #control flow operations (only at the end of blocks)
+    'jump', 'jump_cond',
+    'void_return', 'int_return', 'float_return', 'adr_return',
+
     #operations with adresses:
     'adr_add', 'adr_delta', 'adr_eq', 'adr_ge', 'adr_gt', 'adr_le',
     'adr_lt', 'adr_ne', 'adr_sub',
@@ -72,7 +78,11 @@
     'unichar_eq', 'unichar_ne'
     ]
 
-
+#assert len(very_low_level_ops) <= 256
+very_low_level_opcode = {}
+for i, op in enumerate(very_low_level_ops):
+    very_low_level_opcode[op] = i
+del i, op
 
 
 primitives = [lltype.Signed, lltype.Unsigned, lltype.Float, lltype.Char,
@@ -81,56 +91,41 @@
 primitive_to_number = {}
 for i, p in enumerate(primitives):
     primitive_to_number[p] = -i - 1
-del p
+del i, p
 
+class Op: "Attribute-based interface to very_low_level_opcode"
+Op = Op()
+Op.__dict__ = very_low_level_opcode
 
-# possible values for exitswitch:
-ONE_EXIT = -1
-LAST_EXCEPTION = -2
-
-class Operation(object):
-    def __init__(self, opimpl, result, args):
-        self.opimpl = opimpl # unbound method of LLFrame
-        self.args = args     # list of ints: how to represent constants?
-        self.result = result # resulting variable
-
-class Link(object):
-    stop_graph_evaluation = False
-    def __init__(self, target, exitcase=None):
-        self.target = target # target is a Block
-        self.exitcase = exitcase  # NULL for non-exceptional case
-                                  # address of exception class else
-        self.move_int_registers = None
-
-class ReturnLink(Link):
-    stop_graph_evaluation = True
-    def __init__(self, return_val=0, exitcase=None):
-        Link.__init__(self, None, exitcase)
-        if return_val != 0:
-            self.move_int_registers = [return_val, 0]
-    pass
-
-class StartLink(Link):
-    pass
 
 class Block(object):
-    def __init__(self):
-        self.operations = [] # list of Operations
-        self.exitswitch = 0  # positives are variables
-                             # negatives see above
-        self.exits = []      # list of Links
+    def __init__(self, insns, exit0=None,
+                              exit1=None,
+                              constants_int=None,
+                              constants_dbl=None,
+                              constants_ptr=None,
+                              called_graphs=None):
+        self.insns = insns
+        self.exit0 = exit0
+        self.exit1 = exit1
+        self.constants_int = constants_int
+        self.constants_dbl = constants_dbl
+        self.constants_ptr = constants_ptr
+        self.called_graphs = called_graphs
 
-class Graph(object):
-    def __init__(self, name, startlink):
-        self.name = name             # string
-        self.startlink = startlink # Block
-        self.constants_int = []
-        self.max_num_ints = 17 #XXX calculate this
-
-    def set_constants_int(self, constants):
-        self.constants_int = constants
-
-class Globals(object):
-    def __init__(self):
-        self.graphs = []    # list of Graphs
+class Link(object):
+    def __init__(self, target, targetregs_int=None,
+                               targetregs_dbl=None,
+                               targetregs_ptr=None):
+        self.target = target
+        self.targetregs_int = targetregs_int
+        self.targetregs_dbl = targetregs_dbl
+        self.targetregs_ptr = targetregs_ptr
 
+class Graph(object):
+    def __init__(self, name, startblock, nargs_int, nargs_dbl, nargs_ptr):
+        self.name = name
+        self.startblock = startblock
+        self.nargs_int = nargs_int
+        self.nargs_dbl = nargs_dbl
+        self.nargs_ptr = nargs_ptr

Modified: pypy/dist/pypy/rpython/l3interp/test/test_convert.py
==============================================================================
--- pypy/dist/pypy/rpython/l3interp/test/test_convert.py	(original)
+++ pypy/dist/pypy/rpython/l3interp/test/test_convert.py	Sun Dec  4 13:46:47 2005
@@ -1,7 +1,9 @@
+import py
 from pypy.rpython.l3interp import convertgraph, l3interp
 from pypy.translator.translator import TranslationContext
 
 def test_convert_add():
+    py.test.skip("in-progress")
     def f(x):
         return x + 4
     t = TranslationContext()

Modified: pypy/dist/pypy/rpython/l3interp/test/test_l3interp.py
==============================================================================
--- pypy/dist/pypy/rpython/l3interp/test/test_l3interp.py	(original)
+++ pypy/dist/pypy/rpython/l3interp/test/test_l3interp.py	Sun Dec  4 13:46:47 2005
@@ -1,5 +1,6 @@
 from pypy.rpython.l3interp import l3interp
 from pypy.rpython.l3interp import model
+from pypy.rpython.l3interp.model import Op
 from pypy.translator.c.test.test_genc import compile
 from pypy.translator.translator import TranslationContext
 from pypy.annotation import policy
@@ -24,19 +25,13 @@
 def eval_seven():
     #def f():
     #    return 3 + 4
-    op = model.Operation(l3interp.LLFrame.op_int_add, 0, [-1, -2])
-    returnlink = model.ReturnLink()
-    block = model.Block()
-    block.exitswitch = model.ONE_EXIT
-    block.exits = [returnlink]
-    block.operations.append(op)
-    startlink = model.Link(block, [])
-    graph = model.Graph("testgraph", startlink)
-    graph.set_constants_int([3, 4])
-    g = model.Globals()
-    g.graphs = [graph]
-    interp = l3interp.LLInterpreter(g)
-    return interp.eval_graph_int(graph, [])
+    block = model.Block([Op.int_add, 0, 1,
+                         Op.int_return, -1],
+                        constants_int = [3, 4])
+    graph = model.Graph("testgraph", block, 0, 0, 0)
+    value = l3interp.l3interpret(graph, [], [], [])
+    assert isinstance(value, l3interp.L3Integer)
+    return value.intval
       
 def test_very_simple():
     result = eval_seven()
@@ -50,20 +45,13 @@
 def eval_eight(number):
     #def f(x):
     #    return x + 4
-    op = model.Operation(l3interp.LLFrame.op_int_add, 1, [0, -1])
-    returnlink = model.ReturnLink(return_val=1)
-    block = model.Block()
-    block.exitswitch = model.ONE_EXIT
-    block.exits = [returnlink]
-    block.operations.append(op)
-    startlink = model.Link(target=block)
-    startlink.move_int_registers = [0, 0]
-    graph = model.Graph("testgraph", startlink)
-    graph.set_constants_int([4])
-    g = model.Globals()
-    g.graphs = [graph]
-    interp = l3interp.LLInterpreter(g)
-    return interp.eval_graph_int(graph, [number])
+    block = model.Block([Op.int_add, -1, 0,
+                         Op.int_return, -1],
+                        constants_int = [4])
+    graph = model.Graph("testgraph", block, 1, 0, 0)
+    value = l3interp.l3interpret(graph, [number], [], [])
+    assert isinstance(value, l3interp.L3Integer)
+    return value.intval
 
 def test_simple():
     result = eval_eight(4)
@@ -77,69 +65,51 @@
 def eval_branch(number):
     #def f(x):
     #    if x:
-    #        return 2
+    #        return x
     #    return 1
-    op = model.Operation(l3interp.LLFrame.op_int_is_true, 1, [0])
-    returnlink1 = model.ReturnLink(-1)
-    returnlink2 = model.ReturnLink(-2)
-    block = model.Block()
-    block.exitswitch = 1
-    block.exits = [returnlink1, returnlink2]
-    block.operations.append(op)
-    startlink = model.Link(target=block)
-    startlink.move_int_registers = [0, 0]
-    graph = model.Graph("testgraph", startlink)
-    graph.set_constants_int([1, 2])
-    g = model.Globals()
-    g.graphs = [graph]
-    interp = l3interp.LLInterpreter(g)
-    return interp.eval_graph_int(graph, [number])
+    block1 = model.Block([Op.jump_cond, -1])
+    block2 = model.Block([Op.int_return, -1])
+    block3 = model.Block([Op.int_return, 0], constants_int=[1])
+    block1.exit0 = model.Link(block3)
+    block1.exit1 = model.Link(block2, targetregs_int=[-1])
+    graph = model.Graph("testgraph", block1, 1, 0, 0)
+    value = l3interp.l3interpret(graph, [number], [], [])
+    assert isinstance(value, l3interp.L3Integer)
+    return value.intval
 
 def test_branch():
     result = eval_branch(4)
-    assert result == 2
+    assert result == 4
     result = eval_branch(0)
     assert result == 1
 
 def test_branch_translated():
     fn = translate(eval_branch, [int]) 
-    assert fn(4) == 2 
+    assert fn(4) == 4
     assert fn(0) == 1
 
 #----------------------------------------------------------------------
 
 def eval_call(number):
-    #XXX uh: this isn't funny anymore
     #def g(x):
     #    return x + 1
     #def f(x):
     #    return g(x) + 2
-    op_g = model.Operation(l3interp.LLFrame.op_int_add, 1, [0, -1])
-    op_f = model.Operation(l3interp.LLFrame.op_int_add, 2, [1, -1])
-    call_op = model.Operation(l3interp.LLFrame.op_call_graph_int, 1, [0, 0])
-    returnlink_g = model.ReturnLink(1)
-    returnlink_f = model.ReturnLink(2)
-    block_g = model.Block()
-    block_g.exitswitch = model.ONE_EXIT
-    block_g.exits = [returnlink_g]
-    block_g.operations.append(op_g)
-    startlink_g = model.StartLink(target=block_g)
-    startlink_g.move_int_registers = [0, 0]
-    graph_g = model.Graph("g", startlink_g)
-    graph_g.set_constants_int([1])
-
-    block_f = model.Block()
-    block_f.exitswitch = model.ONE_EXIT
-    block_f.exits = [returnlink_f]
-    block_f.operations.extend([call_op, op_f])
-    startlink_f = model.StartLink(target=block_f)
-    startlink_f.move_int_registers = [0, 0]
-    graph_f = model.Graph("f", startlink_f)
-    graph_f.set_constants_int([2])
-    g = model.Globals()
-    g.graphs = [graph_g, graph_f]
-    interp = l3interp.LLInterpreter(g)
-    return interp.eval_graph_int(graph_f, [number])
+    block = model.Block([Op.int_add, -1, 0,
+                         Op.int_return, -1],
+                        constants_int = [1])
+    graph1 = model.Graph("g", block, 1, 0, 0)
+
+    block = model.Block([Op.direct_call, 0, -1,
+                         Op.int_add, -1, 0,
+                         Op.int_return, -1],
+                        constants_int = [2],
+                        called_graphs = [graph1])
+    graph2 = model.Graph("f", block, 1, 0, 0)
+
+    value = l3interp.l3interpret(graph2, [number], [], [])
+    assert isinstance(value, l3interp.L3Integer)
+    return value.intval
 
 def test_call():
     result = eval_call(4)
@@ -151,5 +121,3 @@
     fn = translate(eval_call, [int]) 
     assert fn(4) == 7 
     assert fn(0) == 3
-
-



More information about the Pypy-commit mailing list