[pypy-svn] r40772 - in pypy/dist/pypy: rpython translator/oosupport translator/oosupport/test

antocuni at codespeak.net antocuni at codespeak.net
Mon Mar 19 14:57:27 CET 2007


Author: antocuni
Date: Mon Mar 19 14:57:24 2007
New Revision: 40772

Added:
   pypy/dist/pypy/translator/oosupport/test/
   pypy/dist/pypy/translator/oosupport/test/__init__.py   (contents, props changed)
   pypy/dist/pypy/translator/oosupport/test/test_treebuilder.py   (contents, props changed)
   pypy/dist/pypy/translator/oosupport/treebuilder.py   (contents, props changed)
Modified:
   pypy/dist/pypy/rpython/llinterp.py
Log:
Add a general way to transform SSI graphs in stack-based machine
friendly form.

Operations now accept three kinds of arguments:

  - variables

  - constants

  - sub-operation (recursively)

The algorithm could be improved, because at the moment it simply
ignores operations involving mutable objects instead of checking if
they are effectively mutated.




Modified: pypy/dist/pypy/rpython/llinterp.py
==============================================================================
--- pypy/dist/pypy/rpython/llinterp.py	(original)
+++ pypy/dist/pypy/rpython/llinterp.py	Mon Mar 19 14:57:24 2007
@@ -226,6 +226,16 @@
                 assert False, "type error: %r val from %r var/const" % (lltype.typeOf(val), varorconst.concretetype)
         return val
 
+    def getval_or_subop(self, varorsubop):
+        from pypy.translator.oosupport.treebuilder import SubOperation
+        if isinstance(varorsubop, SubOperation):
+            self.eval_operation(varorsubop.op)
+            resultval = self.getval(varorsubop.op.result)
+            del self.bindings[varorsubop.op.result] # XXX hack
+            return resultval
+        else:
+            return self.getval(varorsubop)
+
     # _______________________________________________________
     # other helpers
     def getoperationhandler(self, opname):
@@ -365,7 +375,7 @@
         if getattr(ophandler, 'specialform', False):
             retval = ophandler(*operation.args)
         else:
-            vals = [self.getval(x) for x in operation.args]
+            vals = [self.getval_or_subop(x) for x in operation.args]
             if getattr(ophandler, 'need_result_type', False):
                 vals.insert(0, operation.result.concretetype)
             try:

Added: pypy/dist/pypy/translator/oosupport/test/__init__.py
==============================================================================

Added: pypy/dist/pypy/translator/oosupport/test/test_treebuilder.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/oosupport/test/test_treebuilder.py	Mon Mar 19 14:57:24 2007
@@ -0,0 +1,89 @@
+from pypy.rpython.llinterp import LLInterpreter
+from pypy.translator.translator import TranslationContext, graphof
+from pypy.translator.oosupport.treebuilder import build_trees, SubOperation
+from pypy.conftest import option
+from pypy.rpython.test.test_rlist import BaseTestRlist
+from pypy.rpython.test.tool import BaseRtypingTest, OORtypeMixin
+from pypy.rpython.test.test_llinterp import get_interpreter
+
+def translate(func, argtypes):
+    t = TranslationContext()
+    t.buildannotator().build_types(func, argtypes)
+    t.buildrtyper(type_system='ootype').specialize()
+    return t
+
+def check_trees(func, argtypes):
+    t = translate(func, argtypes)
+    if option.view:
+        t.view()
+    graph = graphof(t, func)
+    build_trees(graph)
+    if option.view:
+        t.view()
+    interp = LLInterpreter(t.rtyper)
+    def eval_func(*args):
+        return interp.eval_graph(graph, args)
+    return graph, eval_func
+
+def test_simple():
+    def fn(x):
+        x = x+1
+        x = x+1
+        return x
+    graph, eval_func = check_trees(fn, [int])
+    block = graph.startblock
+    assert len(block.operations) == 1
+    assert isinstance(block.operations[0].args[0], SubOperation)
+    assert eval_func(0) == 2
+
+def test_function_call():
+    def g(x):
+        return x+1
+    def fn(x):
+        a = g(x)
+        b = g(x+1)
+        return a + b
+    graph, eval_func = check_trees(fn, [int])
+    block = graph.startblock
+    assert len(block.operations) == 1
+    assert isinstance(block.operations[0].args[0], SubOperation)
+    assert isinstance(block.operations[0].args[1], SubOperation)
+    assert eval_func(1) == 5
+
+def test_count_exit_links():
+    def g(x):
+        pass
+    def fn(x):
+        res = x+1
+        g(res)
+        return res
+    graph, eval_func = check_trees(fn, [int])
+    block = graph.startblock
+    assert len(block.operations) == 2
+    v0 = block.operations[0].result
+    assert block.exits[0].args == [v0]
+    assert eval_func(0) == 1
+
+def test_mutable_values():
+    def fn():
+        lst = []
+        length = len(lst)
+        lst.append(42)
+        return length + 1
+    graph, eval_func = check_trees(fn, [])
+    block = graph.startblock
+    assert not isinstance(block.operations[-1].args[0], SubOperation)
+    assert eval_func() == 1
+
+class BuildTreeRtypingTest(BaseRtypingTest, OORtypeMixin):
+    def interpret(self, fn, args):
+        interp, graph = get_interpreter(fn, args, view=False, viewbefore=False, type_system=self.type_system)
+        if option.view:
+            interp.typer.annotator.translator.view()
+        build_trees(graph)
+        if option.view:
+            interp.typer.annotator.translator.view()
+        return interp.eval_graph(graph, args)
+
+class TestBuildTreeList(BuildTreeRtypingTest, BaseTestRlist):
+    pass

Added: pypy/dist/pypy/translator/oosupport/treebuilder.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/oosupport/treebuilder.py	Mon Mar 19 14:57:24 2007
@@ -0,0 +1,59 @@
+from pypy.rpython.ootypesystem import ootype
+from pypy.objspace.flow import model as flowmodel
+
+class SubOperation(object):
+    def __init__(self, op):
+        self.op = op
+        self.concretetype = op.result.concretetype
+
+    def __repr__(self):
+        return "[%s(%s)]" % (self.op.opname,
+                           ", ".join(map(repr, self.op.args)))
+
+def is_mutable(TYPE):
+    return isinstance(TYPE, (ootype.Instance,
+                             ootype.Record,
+                             ootype.List,
+                             ootype.Dict,
+                             ootype.StringBuilder.__class__,
+                             ootype.CustomDict,
+                             ootype.DictItemsIterator))
+
+def can_be_inlined(op):
+    for v in op.args:
+        if isinstance(v, flowmodel.Variable) and is_mutable(v.concretetype):
+            return False
+    return True
+
+def build_op_map(block):
+    var_count = {}
+    var_to_op = {}
+    def inc(v):
+        if isinstance(v, flowmodel.Variable):
+            var_count[v] = var_count.get(v, 0) + 1
+
+    for i, op in enumerate(block.operations):
+        var_to_op[op.result] = i, op
+        for v in op.args:
+            inc(v)
+    for link in block.exits:
+        for v in link.args:
+            inc(v)
+    return var_count, var_to_op
+
+def build_trees_for_block(block):
+    var_count, var_to_op = build_op_map(block)
+    for op in block.operations:
+        for i, v in enumerate(op.args):
+            if var_count.get(v, None) == 1 and v not in block.inputargs: # "inline" the operation
+                sub_i, sub_op = var_to_op[v]
+                if can_be_inlined(sub_op):
+                    op.args[i] = SubOperation(sub_op)
+                    block.operations[sub_i] = None
+    block.operations = [op for op in block.operations if op is not None]
+
+def build_trees(graph):
+    if not getattr(graph, 'tree_built', False):
+        for block in graph.iterblocks():
+            build_trees_for_block(block)
+        graph.tree_built = True



More information about the Pypy-commit mailing list