[pypy-svn] r37377 - in pypy/dist/pypy/jit/codegen: . llgraph/test

arigo at codespeak.net arigo at codespeak.net
Fri Jan 26 12:26:54 CET 2007


Author: arigo
Date: Fri Jan 26 12:26:53 2007
New Revision: 37377

Added:
   pypy/dist/pypy/jit/codegen/llgraph/test/test_graph2rgenop.py   (contents, props changed)
Modified:
   pypy/dist/pypy/jit/codegen/graph2rgenop.py
Log:
Adapt graph2rgenop to work with graphs with exitswitches as well.


Modified: pypy/dist/pypy/jit/codegen/graph2rgenop.py
==============================================================================
--- pypy/dist/pypy/jit/codegen/graph2rgenop.py	(original)
+++ pypy/dist/pypy/jit/codegen/graph2rgenop.py	Fri Jan 26 12:26:53 2007
@@ -4,18 +4,32 @@
 """
 from pypy.rpython.lltypesystem import lltype
 from pypy.objspace.flow import model as flowmodel
+import random
 
 
-def compile_graph(rgenop, graph):
+def rcompile(rgenop, entrypoint, argtypes):
+    from pypy.translator.translator import TranslationContext
+    from pypy import conftest
+    t = TranslationContext()
+    t.buildannotator().build_types(entrypoint, argtypes)
+    t.buildrtyper().specialize()
+    if conftest.option.view:
+        t.view()
+
+    from pypy.translator.c.genc import CStandaloneBuilder
+    cbuild = CStandaloneBuilder(t, entrypoint, config=t.config)
+    db = cbuild.generate_graphs_for_llinterp()
+    entrypointptr = cbuild.getentrypointptr()
+    entrygraph = entrypointptr._obj.graph
+    return compile_graph(rgenop, entrygraph)
+
+
+def compile_graph(rgenop, graph, random_seed=0):
     FUNC = lltype.FuncType([v.concretetype for v in graph.getargs()],
                            graph.getreturnvar().concretetype)
     sigtoken = rgenop.sigToken(FUNC)
     builder, gv_entrypoint, args_gv = rgenop.newgraph(sigtoken,
                                          "compiled_%s" % (graph.name,))
-    builder.start_writing()
-
-    pending_blocks = {graph.startblock: (builder, args_gv)}
-    seen_blocks = {}
 
     def varkind(v):
         return rgenop.kindToken(v.concretetype)
@@ -26,69 +40,112 @@
         else:
             return rgenop.genconst(v.value)
 
-    for block in graph.iterblocks():
-        builder, args_gv = pending_blocks.pop(block)
-        assert len(args_gv) == len(block.inputargs)
-        label = builder.enter_next_block(map(varkind, block.inputargs),
-                                         args_gv)
-        seen_blocks[block] = label
-        varmap = dict(zip(block.inputargs, args_gv))
-
-        if not block.exits:
-            [retvar] = block.inputargs
-            builder.finish_and_return(sigtoken, varmap[retvar])
-            continue
-
-        for op in block.operations:
-            # XXX only supports some operations for now
-            if op.opname == 'malloc':
-                token = rgenop.allocToken(op.args[0].value)
-                gv_result = builder.genop_malloc_fixedsize(token)
-            elif op.opname == 'getfield':
-                token = rgenop.fieldToken(op.args[0].concretetype.TO,
-                                          op.args[1].value)
-                gv_result = builder.genop_getfield(token,
-                                                   var2gv(op.args[0]))
-            elif op.opname == 'setfield':
-                token = rgenop.fieldToken(op.args[0].concretetype.TO,
-                                          op.args[1].value)
-                gv_result = builder.genop_setfield(token,
-                                                   var2gv(op.args[0]),
-                                                   var2gv(op.args[2]))
-            elif op.opname == 'malloc_varsize':
-                token = rgenop.varsizeAllocToken(op.args[0].value)
-                gv_result = builder.genop_malloc_varsize(token,
-                                                         var2gv(op.args[1]))
-            elif op.opname == 'getarrayitem':
-                token = rgenop.arrayToken(op.args[0].concretetype.TO)
-                gv_result = builder.genop_getarrayitem(token,
-                                                       var2gv(op.args[0]),
-                                                       var2gv(op.args[1]))
-            elif op.opname == 'setarrayitem':
-                token = rgenop.arrayToken(op.args[0].concretetype.TO)
-                gv_result = builder.genop_setarrayitem(token,
-                                                       var2gv(op.args[0]),
-                                                       var2gv(op.args[1]),
-                                                       var2gv(op.args[2]))
-            elif op.opname == 'same_as':
-                token = rgenop.kindToken(op.args[0])
-                gv_result = builder.genop_same_as(token, var2gv(op.args[0]))
-            elif len(op.args) == 1:
-                gv_result = builder.genop1(op.opname, var2gv(op.args[0]))
-            elif len(op.args) == 2:
-                gv_result = builder.genop2(op.opname, var2gv(op.args[0]),
-                                                      var2gv(op.args[1]))
+    map(varkind, graph.getargs())    # for the py.test.skip() in some backends
+    pending_blocks = [(graph.startblock, builder, args_gv)]
+    more_pending_blocks = []
+    entrymap = flowmodel.mkentrymap(graph)
+    entrymap[graph.returnblock] = "force a label"
+    labels = {graph.returnblock: None}
+    r = random.Random(random_seed)
+
+    while pending_blocks or more_pending_blocks:
+        if not pending_blocks:
+            r.shuffle(more_pending_blocks)
+            pending_blocks = more_pending_blocks
+            more_pending_blocks = []
+        block, builder, args_gv = pending_blocks.pop()
+        builder.start_writing()
+
+        # the following loop generates a chain of blocks
+        # (a branch in the graph)
+        while True:
+            assert len(args_gv) == len(block.inputargs)
+            if len(entrymap[block]) > 1:
+                # need a label at the start of this block
+                if block in labels:
+                    # already got one, jump to it
+                    label = labels[block]
+                    if label is not None:
+                        builder.finish_and_goto(args_gv, labels[block])
+                    else:
+                        [retvar] = args_gv
+                        builder.finish_and_return(sigtoken, retvar)
+                    break    # done along this branch
+                else:
+                    # create a label and proceed
+                    kinds = map(varkind, block.inputargs)
+                    labels[block] = builder.enter_next_block(kinds, args_gv)
+
+            # generate the operations
+            varmap = dict(zip(block.inputargs, args_gv))
+            for op in block.operations:
+                gv_result = generate_operation(rgenop, builder, op, var2gv)
+                varmap[op.result] = gv_result
+
+            if block.exitswitch is None:
+                [link] = block.exits
             else:
-                raise NotImplementedError(op.opname)
-            varmap[op.result] = gv_result
+                if block.exitswitch.concretetype is not lltype.Bool:
+                    raise NotImplementedError("XXX switches")
+                i = r.randrange(0, 2)
+                jumplink = block.exits[i]
+                args_gv = map(var2gv, jumplink.args)
+                if jumplink.exitcase:
+                    meth = builder.jump_if_true
+                else:
+                    meth = builder.jump_if_false
+                newbuilder = meth(varmap[block.exitswitch], args_gv)
+                more_pending_blocks.append((jumplink.target,
+                                            newbuilder,
+                                            args_gv))
+                link = block.exits[1-i]
 
-        if block.exitswitch is not None:
-            raise NotImplementedError("XXX exitswitch")
-        else:
-            [link] = block.exits
-            args_gv = [var2gv(v) for v in link.args]
-            pending_blocks[link.target] = builder, args_gv
+            args_gv = map(var2gv, link.args)
+            block = link.target
 
     builder.end()
     return gv_entrypoint
-           
+
+
+def generate_operation(rgenop, builder, op, var2gv):
+    # XXX only supports some operations for now
+    if op.opname == 'malloc':
+        token = rgenop.allocToken(op.args[0].value)
+        gv_result = builder.genop_malloc_fixedsize(token)
+    elif op.opname == 'getfield':
+        token = rgenop.fieldToken(op.args[0].concretetype.TO,
+                                  op.args[1].value)
+        gv_result = builder.genop_getfield(token,
+                                           var2gv(op.args[0]))
+    elif op.opname == 'setfield':
+        token = rgenop.fieldToken(op.args[0].concretetype.TO,
+                                  op.args[1].value)
+        gv_result = builder.genop_setfield(token,
+                                           var2gv(op.args[0]),
+                                           var2gv(op.args[2]))
+    elif op.opname == 'malloc_varsize':
+        token = rgenop.varsizeAllocToken(op.args[0].value)
+        gv_result = builder.genop_malloc_varsize(token,
+                                                 var2gv(op.args[1]))
+    elif op.opname == 'getarrayitem':
+        token = rgenop.arrayToken(op.args[0].concretetype.TO)
+        gv_result = builder.genop_getarrayitem(token,
+                                               var2gv(op.args[0]),
+                                               var2gv(op.args[1]))
+    elif op.opname == 'setarrayitem':
+        token = rgenop.arrayToken(op.args[0].concretetype.TO)
+        gv_result = builder.genop_setarrayitem(token,
+                                               var2gv(op.args[0]),
+                                               var2gv(op.args[1]),
+                                               var2gv(op.args[2]))
+    elif op.opname == 'same_as':
+        token = rgenop.kindToken(op.args[0].concretetype)
+        gv_result = builder.genop_same_as(token, var2gv(op.args[0]))
+    elif len(op.args) == 1:
+        gv_result = builder.genop1(op.opname, var2gv(op.args[0]))
+    elif len(op.args) == 2:
+        gv_result = builder.genop2(op.opname, var2gv(op.args[0]),
+                                              var2gv(op.args[1]))
+    else:
+        raise NotImplementedError(op.opname)
+    return gv_result

Added: pypy/dist/pypy/jit/codegen/llgraph/test/test_graph2rgenop.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/jit/codegen/llgraph/test/test_graph2rgenop.py	Fri Jan 26 12:26:53 2007
@@ -0,0 +1,22 @@
+from pypy.rpython.lltypesystem import lltype
+from pypy.jit.codegen.graph2rgenop import rcompile
+from pypy.jit.codegen.llgraph.rgenop import rgenop
+from pypy.jit.codegen.llgraph.llimpl import testgengraph
+
+
+def demo(n):
+    result = 1
+    while n > 1:
+        if n & 1:
+            result *= n
+        n -= 1
+    return result
+
+
+def test_demo():
+    gv = rcompile(rgenop, demo, [int])
+    F1 = lltype.FuncType([lltype.Signed], lltype.Signed)
+    ptr = gv.revealconst(lltype.Ptr(F1))
+
+    res = testgengraph(ptr._obj.graph, [10])
+    assert res == demo(10) == 945



More information about the Pypy-commit mailing list