[pypy-svn] r12224 - in pypy/dist/pypy: annotation rpython rpython/test translator translator/genc translator/tool

arigo at codespeak.net arigo at codespeak.net
Thu May 12 19:41:41 CEST 2005


Author: arigo
Date: Thu May 12 19:41:40 2005
New Revision: 12224

Added:
   pypy/dist/pypy/rpython/rlist.py   (contents, props changed)
   pypy/dist/pypy/rpython/test/test_rlist.py   (contents, props changed)
   pypy/dist/pypy/rpython/test/test_typer.py   (contents, props changed)
   pypy/dist/pypy/rpython/typer.py   (contents, props changed)
Modified:
   pypy/dist/pypy/annotation/model.py
   pypy/dist/pypy/rpython/lltypes.py
   pypy/dist/pypy/translator/genc/basetype.py
   pypy/dist/pypy/translator/tool/graphpage.py
   pypy/dist/pypy/translator/typer.py
Log:
Started to write a Typer for the low-level types.  The goal is to get rid of
the CTyper, but we can still use the abstract base Typer.

- new low-level types: PyObject (as an opaque container, not a pointer)
  and ForwardReference, used temporarily while building recursive data
  structures.

- started the implementation of the RPython list.

- minor changes in translator/ to accomodate our new stuff.



Modified: pypy/dist/pypy/annotation/model.py
==============================================================================
--- pypy/dist/pypy/annotation/model.py	(original)
+++ pypy/dist/pypy/annotation/model.py	Thu May 12 19:41:40 2005
@@ -283,14 +283,18 @@
     (SomeChar(), lltypes.Char),
 ]
 
-def annotation_to_lltype(s_val):
+def annotation_to_lltype(s_val, info=None):
     if isinstance(s_val, SomePtr):
         return s_val.ll_ptrtype
     for witness, lltype in annotation_to_ll_map:
         if witness.contains(s_val):
             return lltype
-    raise AssertionError("trying find a matching low-level type for unexpected"
-                         "%r" % s_val)
+    if info is None:
+        info = ''
+    else:
+        info = '%s: ' % info
+    raise ValueError("%sshould return a low-level type,\ngot instead %r" % (
+        info, s_val))
 
 ll_to_annotation_map = dict([(ll, ann) for ann,ll in annotation_to_ll_map])
 

Modified: pypy/dist/pypy/rpython/lltypes.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypes.py	(original)
+++ pypy/dist/pypy/rpython/lltypes.py	Thu May 12 19:41:40 2005
@@ -132,7 +132,17 @@
         def ex(*args):
             return self.RESULT._example()
         return _func(self, _callable=ex)
-       
+
+class PyObjectType(ContainerType):
+    def __str__(self):
+        return "PyObject"
+PyObject = PyObjectType()
+
+class ForwardReference(ContainerType):
+    def become(self, realcontainertype):
+        self.__class__ = realcontainertype.__class__
+        self.__dict__ = realcontainertype.__dict__
+
 
 class Primitive(LowLevelType):
     def __init__(self, name, default):

Added: pypy/dist/pypy/rpython/rlist.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/rpython/rlist.py	Thu May 12 19:41:40 2005
@@ -0,0 +1,68 @@
+import py
+from pypy.annotation.model import *
+from pypy.rpython.lltypes import *
+
+
+def substitute_newlist(typer, op):
+    s_result = typer.annotator.binding(op.result)
+    LIST = getlisttype(typer, s_result)
+    T = getlistitemtype(typer, s_result)
+    n = len(op.args)
+    inputsignature = (T,) * n
+    try:
+        newlist = typer.newlistcache[LIST, n]
+    except KeyError:
+        # Make an implementation of newlist(x1,..,xn) which allocates
+        # a list with n elements and initialize them.
+ 
+        args = ', '.join(['arg%d' % i for i in range(n)])
+        lines = []
+        lines.append(    'def newlist(%s):' % args)
+        lines.append(    '    l = malloc(List_typ)')
+        lines.append(    '    l.items = malloc(List_typ.items.TO, %d)' % n)
+        for i in range(n):
+            lines.append('    l.items[%d].item = arg%d' % (i, i))
+        lines.append(    '    return l')
+        lines.append(    '')
+        miniglobal = {'List_typ': LIST.TO, 'malloc': malloc}
+        exec py.code.Source('\n'.join(lines)).compile() in miniglobal
+        newlist = typer.newlistcache[LIST, n] = miniglobal['newlist']
+    return typer.substitute_op(op, (newlist,) + inputsignature +  (LIST,))
+
+def getlisttype(typer, s_list):
+    assert isinstance(s_list, SomeList)
+    listdef = s_list.listdef
+    try:
+        return typer.listtypecache[listdef]
+    except KeyError:
+        List_typ = ForwardReference()
+        result = typer.listtypecache[listdef] = GcPtr(List_typ)
+        define_list(typer, s_list, List_typ)
+        return result
+
+def getlistitemtype(typer, s_list):
+    return typer.annotation2concretetype(s_list.listdef.listitem.s_value)
+
+
+def define_list(typer, s_list, List_typ):
+    T = getlistitemtype(typer, s_list)
+    List_typ.become(Struct("list",
+                           ("items", GcPtr(Array(('item',T))))))
+
+    def getitem(l, i):
+        return l.items[i].item
+
+    typer['getitem', s_list, SomeInteger()] = (
+        getitem, GcPtr(List_typ), Signed, T)
+
+##    def append(l, newitem):
+##        length = len(l.items)
+##        newitems = malloc(List_typ.items.TO, length+1)
+##        i = 0
+##        while i<length:
+##          newitems[i].item = l.items[i].item
+##          i += 1
+##        newitems[length].item = newitem
+##        l.items = newitems
+
+##    Registry['getattr', ...

Added: pypy/dist/pypy/rpython/test/test_rlist.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/rpython/test/test_rlist.py	Thu May 12 19:41:40 2005
@@ -0,0 +1,16 @@
+from pypy.translator.translator import Translator
+from pypy.rpython.lltypes import *
+from pypy.rpython.typer import RPythonTyper
+
+
+def test_simple():
+    def dummyfn():
+        l = [10,20,30]
+        return l[2]
+
+    t = Translator(dummyfn)
+    t.annotate([])
+    typer = RPythonTyper(t.annotator)
+    typer.specialize()
+    #t.view()
+    assert "did not crash"

Added: pypy/dist/pypy/rpython/test/test_typer.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/rpython/test/test_typer.py	Thu May 12 19:41:40 2005
@@ -0,0 +1,15 @@
+from pypy.translator.translator import Translator
+from pypy.rpython.lltypes import *
+from pypy.rpython.typer import RPythonTyper
+
+
+def test_simple():
+    def dummyfn(x):
+        return x+1
+
+    t = Translator(dummyfn)
+    t.annotate([int])
+    typer = RPythonTyper(t.annotator)
+    typer.specialize()
+    #t.view()
+    assert "did not crash"

Added: pypy/dist/pypy/rpython/typer.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/rpython/typer.py	Thu May 12 19:41:40 2005
@@ -0,0 +1,184 @@
+import types
+from pypy.rpython.lltypes import *
+from pypy.annotation.model import *
+from pypy.objspace.flow.model import Variable, Constant, SpaceOperation
+from pypy.translator.typer import Specializer, flatten_ops, TyperError
+from pypy.rpython.rlist import substitute_newlist, getlisttype
+
+
+PyObjPtr = GcPtr(PyObject)
+
+
+class RPythonTyper(Specializer):
+
+    def __init__(self, annotator):
+        # initialization
+        Specializer.__init__(self, annotator, defaultconcretetype=PyObjPtr,
+                             typematches = [], specializationtable = [],
+                             )
+        self.registry = {}
+        SINT = SomeInteger()
+        self['add', SINT, SINT] = 'int_add', Signed, Signed, Signed
+        #self['add', UINT, UINT] = 'int_add', Unsigned, Unsigned, Unsigned
+
+        s_malloc = annotator.bookkeeper.immutablevalue(malloc)
+        self['simple_call', s_malloc, ...] = substitute_malloc
+        
+        # ____________________ lists ____________________
+        self.listtypecache = {}
+        self.newlistcache = {}
+        self['newlist', ...] = substitute_newlist
+
+        # ____________________ conversions ____________________
+        self.concreteconversions = {
+            (Signed, PyObjPtr): ('int2obj', Signed, PyObjPtr),
+            (PyObjPtr, Signed): ('obj2int', PyObjPtr, Signed),
+            }
+
+    def __setitem__(self, pattern, substitution):
+        patternlist = self.registry.setdefault(pattern[0], [])
+        patternlist.append((pattern[1:], substitution))
+
+    def annotation2concretetype(self, s_value):
+        try:
+            return annotation_to_lltype(s_value)
+        except ValueError:
+            if isinstance(s_value, SomeList):
+                return getlisttype(self, s_value)
+            return PyObjPtr
+
+    def convertvar(self, v, concretetype):
+        """Get the operation(s) needed to convert 'v' to the given type."""
+        ops = []
+        v_concretetype = getattr(v, 'concretetype', PyObjPtr)
+        if isinstance(v, Constant):
+            # we should never modify a Constant in-place
+            v = Constant(v.value)
+            v.concretetype = concretetype
+
+        elif v_concretetype != concretetype:
+            try:
+                subst = self.concreteconversions[v_concretetype, concretetype]
+            except KeyError:
+                raise TyperError("cannot convert from %r\n"
+                                 "to %r" % (v_concretetype, concretetype))
+            vresult = Variable()
+            op = SpaceOperation('?', [v], vresult)
+            flatten_ops(self.substitute_op(op, subst), ops)
+            v = vresult
+
+        return v, ops
+
+    def specialized_op(self, op, bindings):
+        assert len(op.args) == len(bindings)
+
+        # first check for direct low-level operations on pointers
+        if op.args and isinstance(bindings[0], SomePtr):
+            PTR = bindings[0].ll_ptrtype
+
+            if op.opname == 'getitem':
+                s_result = self.annotator.binding(op.result)
+                T = annotation_to_lltype(s_result, 'getitem')
+                return self.typed_op(op, [PTR, Signed], T,
+                                     newopname='getarrayitem')
+
+            if op.opname == 'len':
+                return self.typed_op(op, [PTR], Signed,
+                                     newopname='getarraysize')
+
+            if op.opname == 'getattr':
+                assert isinstance(op.args[1], Constant)
+                s_result = self.annotator.binding(op.result)
+                FIELD_TYPE = PTR.TO._flds[op.args[1].value]
+                T = annotation_to_lltype(s_result, 'getattr')
+                if isinstance(FIELD_TYPE, ContainerType):
+                    newopname = 'getsubstruct'
+                else:
+                    newopname = 'getfield'
+                return self.typed_op(op, [PTR, Void], T, newopname=newopname)
+
+            if op.opname == 'setattr':
+                assert isinstance(op.args[1], Constant)
+                FIELD_TYPE = PTR.TO._flds[op.args[1].value]
+                assert not isinstance(FIELD_TYPE, ContainerType)
+                return self.typed_op(op, [PTR, Void, FIELD_TYPE], Void,
+                                     newopname='setfield')
+
+            if op.opname == 'eq':
+                return self.typed_op(op, [PTR, PTR], Bool,
+                                     newopname='ptr_eq')
+            if op.opname == 'ne':
+                return self.typed_op(op, [PTR, PTR], Bool,
+                                     newopname='ptr_ne')
+
+        # generic specialization based on the registration table
+        patternlist = self.registry.get(op.opname, [])
+        for pattern, substitution in patternlist:
+            if pattern and pattern[-1] is Ellipsis:
+                pattern = pattern[:-1]
+                if len(pattern) > len(op.args):
+                    continue
+            elif len(pattern) != len(op.args):
+                continue
+            for s_match, s_value in zip(pattern, bindings):
+                if not s_match.contains(s_value):
+                    break
+            else:
+                # match!
+                return self.substitute_op(op, substitution)
+        # specialization not found
+        argtypes = [self.defaultconcretetype] * len(op.args)
+        return self.typed_op(op, argtypes, self.defaultconcretetype)
+
+    def substitute_op(self, op, substitution):
+        if isinstance(substitution, tuple):
+            newopname = substitution[0]
+            argtypes = substitution[1:-1]
+            resulttype = substitution[-1]
+            assert len(argtypes) == len(op.args)
+            # None in the substitution list means "remove this argument"
+            while None in argtypes:
+                argtypes = list(argtypes)
+                i = argtypes.index(None)
+                del argtypes[i]
+                args = list(op.args)
+                del args[i]
+                op = SpaceOperation(op.opname, args, op.result)
+            return self.typed_op(op, argtypes, resulttype,
+                                 newopname = newopname)
+        else:
+            assert callable(substitution), "type error in the registry tables"
+            return substitution(self, op)
+
+    def typed_op(self, op, argtypes, restype, newopname=None):
+        if isinstance(newopname, types.FunctionType):
+            python_function = newopname
+            newargs = [Constant(python_function)] + op.args
+            op = SpaceOperation('simple_call', newargs, op.result)
+            try:
+                functyp = python_function.TYPE
+            except AttributeError:
+                s_returnvalue = self.annotator.build_types(python_function,
+                                                           argtypes)
+                inferred_type = annotation_to_lltype(s_returnvalue,
+                                                     info=python_function)
+                if inferred_type != restype:
+                    raise TyperError("%r return type mismatch:\n"
+                                     "declared %r\n"
+                                     "inferred %r" % (python_function,
+                                                      inferred_type, restype))
+                functyp = NonGcPtr(FuncType(argtypes, restype))
+                python_function.TYPE = functyp
+            argtypes = [functyp] + list(argtypes)
+            newopname = None
+        return Specializer.typed_op(self, op, argtypes, restype, newopname)
+
+
+def substitute_malloc(typer, op):
+    s_result = typer.annotator.binding(op.result)
+    T = annotation_to_lltype(s_result, 'malloc')
+    if len(op.args) == 2:
+        substitution = 'malloc', None, Void, T
+    else:
+        substitution = 'malloc_varsize', None, Void, Signed, T
+    return typer.substitute_op(op, substitution)

Modified: pypy/dist/pypy/translator/genc/basetype.py
==============================================================================
--- pypy/dist/pypy/translator/genc/basetype.py	(original)
+++ pypy/dist/pypy/translator/genc/basetype.py	Thu May 12 19:41:40 2005
@@ -10,6 +10,9 @@
     def debugname(self):
         return self.typename
 
+    def __str__(self):
+        return self.debugname()
+
     def genc():
         """A hack to get at the currently running GenC instance."""
         from pypy.translator.genc.genc import TLS

Modified: pypy/dist/pypy/translator/tool/graphpage.py
==============================================================================
--- pypy/dist/pypy/translator/tool/graphpage.py	(original)
+++ pypy/dist/pypy/translator/tool/graphpage.py	Thu May 12 19:41:40 2005
@@ -128,9 +128,8 @@
             if isinstance(node, Block):
                 for var in node.getvariables():
                     if hasattr(var, 'concretetype'):
-                        typename = var.concretetype.debugname()
                         info = self.links.get(var.name, var.name)
-                        info = '(%s) %s' % (typename, info)
+                        info = '(%s) %s' % (var.concretetype, info)
                         self.links[var.name] = info
         for graph in graphs:
             traverse(visit, graph)

Modified: pypy/dist/pypy/translator/typer.py
==============================================================================
--- pypy/dist/pypy/translator/typer.py	(original)
+++ pypy/dist/pypy/translator/typer.py	Thu May 12 19:41:40 2005
@@ -29,9 +29,18 @@
         self.specializationdict = d
 
     def specialize(self):
-        for block in self.annotator.annotated:
-            if block.operations != ():
-                self.specialize_block(block)
+        """Main entry point: specialize all annotated blocks of the program."""
+        # new blocks can be created as a result of specialize_block(), so
+        # we need to be careful about the loop here.
+        already_seen = {}
+        pending = self.annotator.annotated.keys()
+        while pending:
+            for block in pending:
+                if block.operations != ():
+                    self.specialize_block(block)
+                already_seen[block] = True
+            pending = [block for block in self.annotator.annotated
+                             if block not in already_seen]
 
     def settype(self, a, concretetype):
         """Set the concretetype of a Variable."""



More information about the Pypy-commit mailing list