[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