[pypy-svn] r10221 - pypy/dist/pypy/translator
arigo at codespeak.net
arigo at codespeak.net
Fri Apr 1 16:29:46 CEST 2005
Author: arigo
Date: Fri Apr 1 16:29:46 2005
New Revision: 10221
Added:
pypy/dist/pypy/translator/genc_pyobj.py (contents, props changed)
pypy/dist/pypy/translator/genc_type.py (contents, props changed)
Modified:
pypy/dist/pypy/translator/typer.py
Log:
The 'typer' can be done with reasonably clean code, at least so far. Its
purpose is to put type-specific operations and conversion operations in the
flow graph, but also a 'type_cls' attribute on all Variables and Constants
that appear. This 'type_cls' points to one of the new CType_Xxx classes in
genc_pyobj.py or genc_type.py. The idea is that the generic GenC.nameof()
method would be replaced by a nameof() method per CType_Xxx class, in order to
generate the appropriate representation for a typed constant. This should
allow most of the mess that remains in genc.py to be moved to genc_pyobj.py.
Added: pypy/dist/pypy/translator/genc_pyobj.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/genc_pyobj.py Fri Apr 1 16:29:46 2005
@@ -0,0 +1,4 @@
+
+
+class CType_PyObject:
+ pass
Added: pypy/dist/pypy/translator/genc_type.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/genc_type.py Fri Apr 1 16:29:46 2005
@@ -0,0 +1,5 @@
+
+
+class CType_Int:
+ convert_to_obj = 'int2obj'
+ convert_from_obj = 'obj2int'
Modified: pypy/dist/pypy/translator/typer.py
==============================================================================
--- pypy/dist/pypy/translator/typer.py (original)
+++ pypy/dist/pypy/translator/typer.py Fri Apr 1 16:29:46 2005
@@ -1,88 +1,189 @@
import autopath
-from pypy.annotation.model import *
from pypy.objspace.flow.model import SpaceOperation, Variable, Constant
-from pypy.translator.transform import fully_annotated_blocks
+from pypy.objspace.flow.model import Block, Link
-S_INT = SomeInteger()
-
-SpecializationTable = [
- ('add', 'int_add', S_INT, S_INT),
- ('sub', 'int_sub', S_INT, S_INT),
- ('is_true', 'int_is_true', S_INT),
- ]
-
-TypesToConvert = {
- SomeInteger: ('int2obj', 'obj2int'),
- }
-
-def setup_specialization_dict():
- for e in SpecializationTable:
- spectypes = e[2:]
- opname1 = e[0]
- opname2 = e[1]
- SpecializationDict.setdefault(opname1, []).append((opname2, spectypes))
- SpecializationDict.setdefault(opname2, []).append((opname2, spectypes))
+class TypeMatch:
+ def __init__(self, s_type, type_cls):
+ self.s_type = s_type
+ self.type_cls = type_cls
+
+
+class Specializer:
+ specializationdict = {}
+
+ def __init__(self, annotator):
+ if not self.specializationdict:
+ # setup the class
+ d = self.specializationdict
+ for e in self.specializationtable:
+ opname1 = e[0]
+ opname2 = e[1]
+ spectypes = e[2:-1]
+ restypecls = e[-1]
+ info = opname2, spectypes, restypecls
+ d.setdefault(opname1, []).append(info)
+ d.setdefault(opname2, []).append(info)
+ self.annotator = annotator
+
+ def specialize(self):
+ for block in self.annotator.annotated:
+ if block.operations:
+ self.specialize_block(block)
+
+ def settype(self, a, type_cls):
+ """Set the type_cls of a Variable or Constant."""
+ assert not hasattr(a, 'type_cls')
+ a.type_cls = type_cls
+
+ def setbesttype(self, a):
+ """Set the best type_cls for a Variable or Constant according to
+ the annotations."""
+ try:
+ return a.type_cls
+ except AttributeError:
+ besttype = self.defaulttypecls
+ s_value = self.annotator.binding(a, True)
+ if s_value is not None:
+ for tmatch in self.typematches:
+ if tmatch.s_type.contains(s_value):
+ besttype = tmatch.type_cls
+ break
+ self.settype(a, besttype)
+ return besttype
-SpecializationDict = {}
-setup_specialization_dict()
+ def convertvar(self, v, type_cls):
+ """Get the operation(s) needed to convert 'v' to the given type."""
+ ops = []
+ if isinstance(v, Constant):
+ self.settype(v, type_cls) # mark the concrete type of the Constant
+
+ elif v.type_cls is not type_cls:
+ # XXX do we need better conversion paths?
+
+ # 1) convert to the generic type
+ if v.type_cls is not self.defaulttypecls:
+ v2 = Variable()
+ v2.type_cls = self.defaulttypecls
+ op = SpaceOperation(v.type_cls.convert_to_obj, [v], v2)
+ v = v2
+ ops.append(op)
+
+ # 2) convert back from the generic type
+ if type_cls is not self.defaulttypecls:
+ v2 = Variable()
+ v2.type_cls = type_cls
+ op = SpaceOperation(type_cls.convert_from_obj, [v], v2)
+ v = v2
+ ops.append(op)
+
+ return v, ops
+
+ def specialize_block(self, block):
+ # give the best possible types to the input args
+ for a in block.inputargs:
+ self.setbesttype(a)
-# ____________________________________________________________
-
-def specialize(annotator):
- for block in fully_annotated_blocks(annotator):
- if not block.operations:
- continue
+ # specialize all the operations, as far as possible
newops = []
for op in block.operations:
indices = range(len(op.args))
args = list(op.args)
- bindings = [annotator.binding(a, True) for a in args]
- noteworthyindices = []
+ bindings = [self.annotator.binding(a, True) for a in args]
+ # replace constant annotations with real Constants
for i in indices:
if isinstance(args[i], Variable) and bindings[i] is not None:
if bindings[i].is_constant():
args[i] = Constant(bindings[i].const)
- else:
- noteworthyindices.append(i)
- specializations = SpecializationDict.get(op.opname, ())
- for opname2, spectypes in specializations:
- assert len(spectypes) == len(op.args)
- for i in indices:
- if bindings[i] is None:
- break
- if not spectypes[i].contains(bindings[i]):
- break
- else:
- op = SpaceOperation(opname2, args, op.result)
- break
- else:
- for i in noteworthyindices:
- for cls in bindings[i].__class__.__mro__:
- if cls in TypesToConvert:
- convert, backconvert = TypesToConvert[cls]
- result = Variable()
- newops.append(SpaceOperation(convert, [args[i]],
- result))
- args[i] = result
- break
- if args != op.args:
- op = SpaceOperation(op.opname, args, op.result)
- result = op.result
- result_binding = annotator.binding(result, True)
- if result_binding is not None:
- for cls in result_binding.__class__.__mro__:
- if cls in TypesToConvert:
- convert, backconvert = TypesToConvert[cls]
- intermediate = Variable()
- newops.append(SpaceOperation(op.opname, args,
- intermediate))
- op = SpaceOperation(backconvert, [intermediate],
- result)
- break
+ # look for a specialized version of the current operation
+ opname2, argtypes, restypecls = self.getspecializedop(op, bindings)
+
+ # type-convert the input arguments
+ for i in indices:
+ args[i], convops = self.convertvar(args[i], argtypes[i])
+ newops += convops
+ # store the result variable's type
+ self.settype(op.result, restypecls)
+
+ # store the possibly modified SpaceOperation
+ if opname2 != op.opname or args != op.args:
+ op = SpaceOperation(opname2, args, op.result)
newops.append(op)
+
block.operations[:] = newops
+
+ # insert the needed conversions on the links
+ for link in block.exits:
+ # numbering of Variables:
+ # a1 in the original Link
+ # a2 in the inserted block before conversion
+ # a3 in the inserted block after conversion
+ # a4 in the original target block's inputargs
+ convargs = []
+ convops = []
+ for i in range(len(link.args)):
+ a1 = link.args[i]
+ a4 = link.target.inputargs[i]
+ a4type = self.setbesttype(a4)
+ a3, convop1 = self.convertvar(a1, a4type)
+ convargs.append(a3)
+ convops += convop1
+ # if there are conversion operations, they are inserted into
+ # a new block along this link
+ if convops:
+ newblock = Block([])
+ mapping = {}
+ for a1 in link.args:
+ a2 = Variable()
+ a2.type_cls = a1.type_cls
+ newblock.inputargs.append(a2)
+ mapping[a1] = a2
+ newblock.operations = convops
+ newblock.closeblock(Link(convargs, link.target))
+ newblock.renamevariables(mapping)
+ link.target = newblock
+
+ def getspecializedop(self, op, bindings):
+ specializations = self.specializationdict.get(op.opname, ())
+ for opname2, spectypes, restypecls in specializations:
+ assert len(spectypes) == len(op.args) == len(bindings)
+ for i in range(len(spectypes)):
+ if bindings[i] is None:
+ break
+ if not spectypes[i].s_type.contains(bindings[i]):
+ break
+ else:
+ # specialization found
+ # opname2 and restypecls are set above by the for loop
+ argtypes = [tmatch.type_cls for tmatch in spectypes]
+ break
+ else:
+ # specialization not found
+ opname2 = op.opname
+ argtypes = [CType_PyObject] * len(op.args)
+ restypecls = self.defaulttypecls
+ return opname2, argtypes, restypecls
+
+# ____________________________________________________________
+# GenC-specific specializer
+
+from pypy.annotation.model import SomeInteger
+from pypy.translator.genc_pyobj import CType_PyObject
+from pypy.translator.genc_type import CType_Int
+
+class GenCSpecializer(Specializer):
+
+ TInt = TypeMatch(SomeInteger(), CType_Int)
+ typematches = [TInt] # in more-specific-first, more-general-last order
+ defaulttypecls = CType_PyObject
+
+ specializationtable = [
+ ## op specialized op arg types concrete return type
+ ('add', 'int_add', TInt, TInt, CType_Int),
+ ('sub', 'int_sub', TInt, TInt, CType_Int),
+ ('is_true', 'int_is_true', TInt, CType_Int),
+ ]
More information about the pypy-svn
mailing list