[pypy-svn] r34479 - in pypy/dist/pypy/jit/codegen: ppc test

mwh at codespeak.net mwh at codespeak.net
Sat Nov 11 02:09:49 CET 2006


Author: mwh
Date: Sat Nov 11 02:09:47 2006
New Revision: 34479

Modified:
   pypy/dist/pypy/jit/codegen/ppc/rgenop.py
   pypy/dist/pypy/jit/codegen/test/rgenop_tests.py
Log:
handle switch overflow, and actually check in the flexswitch test for ppc.


Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py
==============================================================================
--- pypy/dist/pypy/jit/codegen/ppc/rgenop.py	(original)
+++ pypy/dist/pypy/jit/codegen/ppc/rgenop.py	Sat Nov 11 02:09:47 2006
@@ -14,11 +14,9 @@
 from pypy.translator.asm.ppcgen.rassemblermaker import make_rassembler
 from pypy.translator.asm.ppcgen.ppc_assembler import MyPPCAssembler
 
-RPPCAssembler = make_rassembler(MyPPCAssembler)
-
-def emit(self, value):
-    self.mc.write(value)
-RPPCAssembler.emit = emit
+class RPPCAssembler(make_rassembler(MyPPCAssembler)):
+    def emit(self, value):
+        self.mc.write(value)
 
 NSAVEDREGISTERS = 19
 
@@ -355,6 +353,8 @@
         # register allocation for this block we don't know how much
         # stack will be required, so we patch it later (see
         # patch_stack_adjustment below).
+        # note that this stomps on both rSCRATCH (not a problem) and
+        # crf0 (a very small chance of being a problem)
         self.stack_adj_addr = self.asm.mc.tell()
         self.asm.addi(rSCRATCH, rFP, 0) # this is the immediate that later gets patched
         self.asm.subx(rSCRATCH, rSCRATCH, rSP) # rSCRATCH should now be <= 0
@@ -586,6 +586,9 @@
 
 class FlexSwitch(CodeGenSwitch):
 
+    # a fair part of this code could likely be shared with the i386
+    # backend.
+
     def __init__(self, rgenop, mc, switch_reg, crf, var2loc):
         self.rgenop = rgenop
         self.crf = crf
@@ -595,13 +598,31 @@
         self.asm.mc = mc
         self.default_target_addr = 0
 
-##     def _reserve_more(self):
-##         XXX
-
     def add_case(self, gv_case):
         targetbuilder = self.rgenop.openbuilder()
         targetbuilder.make_fresh_from_jump(self.var2loc)
         target_addr = targetbuilder.asm.mc.tell()
+        p = self.asm.mc.getpos()
+        # that this works depends a bit on the fixed length of the
+        # instruction sequences we use to jump around.  if the code is
+        # ever updated to use the branch-relative instructions (a good
+        # idea, btw) this will need to be thought about again
+        try:
+            self._add_case(gv_case, target_addr)
+        except codebuf.CodeBlockOverflow:
+            self.asm.mc.setpos(p)
+            mc = self.rgenop.open_mc()
+            newmc = mc.reserve(7 * 5 + 4)
+            self.rgenop.close_mc(mc)
+            new_addr = newmc.tell()
+            self.asm.load_word(rSCRATCH, new_addr)
+            self.asm.mtctr(rSCRATCH)
+            self.asm.bctr()
+            self.asm.mc = newmc
+            self._add_case(gv_case, target_addr)
+        return targetbuilder
+
+    def _add_case(self, gv_case, target_addr):
         asm = self.asm
         assert isinstance(gv_case, IntConst)
         asm.load_word(rSCRATCH, gv_case.value)
@@ -611,7 +632,6 @@
         asm.bcctr(12, self.crf.number*4 + 2)
         if self.default_target_addr:
             self._write_default()
-        return targetbuilder
 
     def add_default(self):
         targetbuilder = self.rgenop.openbuilder()

Modified: pypy/dist/pypy/jit/codegen/test/rgenop_tests.py
==============================================================================
--- pypy/dist/pypy/jit/codegen/test/rgenop_tests.py	(original)
+++ pypy/dist/pypy/jit/codegen/test/rgenop_tests.py	Sat Nov 11 02:09:47 2006
@@ -212,7 +212,7 @@
         return res
     return if_runner
 
-def build_switch(rgenop):
+def make_switch(rgenop):
     """
     def f(v0, v1):
         if v0 == 0: # switch
@@ -222,9 +222,9 @@
         else:
             return v1
     """
-    signed_tok = rgenop.kindToken(lltype.Signed)
-    f2_token = rgenop.sigToken(FUNC2)
-    builder, graph, (gv0, gv1) = rgenop.newgraph(f2_token)
+    signed_kind = rgenop.kindToken(lltype.Signed)
+    sigtoken = rgenop.sigToken(FUNC2)
+    builder, entrypoint, [gv0, gv1] = rgenop.newgraph(sigtoken)
 
     flexswitch = builder.flexswitch(gv0)
     const21 = rgenop.genconst(21)
@@ -233,38 +233,98 @@
     const0 = rgenop.genconst(0)
     case_builder = flexswitch.add_case(const0)
     case_args_gv = [gv1]
-    case_builder.enter_next_block([signed_tok], case_args_gv)
+    case_builder.enter_next_block([signed_kind], case_args_gv)
     [gv1_case0] = case_args_gv
     gv_res_case0 = case_builder.genop2('int_mul', const21, gv1_case0)
-    case_builder.finish_and_return(f2_token, gv_res_case0)
+    case_builder.finish_and_return(sigtoken, gv_res_case0)
     # default
     default_builder = flexswitch.add_default()
     default_args_gv = [gv1]
-    default_builder.enter_next_block([signed_tok], default_args_gv)
+    default_builder.enter_next_block([signed_kind], default_args_gv)
     [gv1_default] = default_args_gv
-    default_builder.finish_and_return(f2_token, gv1_default)
+    default_builder.finish_and_return(sigtoken, gv1_default)
     # case == 1
     const1 = rgenop.genconst(1)
     case_builder = flexswitch.add_case(const1)
     case_args_gv = [gv1]
-    case_builder.enter_next_block([signed_tok], case_args_gv)
+    case_builder.enter_next_block([signed_kind], case_args_gv)
     [gv1_case1] = case_args_gv
     gv_res_case1 = case_builder.genop2('int_add', const21, gv1_case1)
-    case_builder.finish_and_return(f2_token, gv_res_case1)
+    case_builder.finish_and_return(sigtoken, gv_res_case1)
 
-    gv_switch = rgenop.gencallableconst(f2_token, "switch", graph)
+    gv_switch = rgenop.gencallableconst(sigtoken, "switch", entrypoint)
     return gv_switch
 
 def get_switch_runner(RGenOp):
     def switch_runner(x, y):
         rgenop = RGenOp()
-        gv_switchfn = build_switch(rgenop)
+        gv_switchfn = make_switch(rgenop)
         switchfn = gv_switchfn.revealconst(lltype.Ptr(FUNC2))
         res = switchfn(x, y)
         keepalive_until_here(rgenop)    # to keep the code blocks alive
         return res
     return switch_runner
 
+def make_large_switch(rgenop):
+    """
+    def f(v0, v1):
+        if v0 == 0: # switch
+            return 21*v1
+        elif v0 == 1:
+            return 2+v1
+        elif v0 == 2:
+            return 4+v1
+        ...
+        elif v0 == 10:
+            return 2**10+v1
+        else:
+            return v1
+    """
+    signed_tok = rgenop.kindToken(lltype.Signed)
+    f2_token = rgenop.sigToken(FUNC2)
+    builder, graph, (gv0, gv1) = rgenop.newgraph(f2_token)
+
+    flexswitch = builder.flexswitch(gv0)
+    const21 = rgenop.genconst(21)
+
+    # case == 0
+    const0 = rgenop.genconst(0)
+    case_builder = flexswitch.add_case(const0)
+    case_args_gv = [gv1]
+    case_builder.enter_next_block([signed_tok], case_args_gv)
+    [gv1_case0] = case_args_gv
+    gv_res_case0 = case_builder.genop2('int_mul', const21, gv1_case0)
+    case_builder.finish_and_return(f2_token, gv_res_case0)
+    # default
+    default_builder = flexswitch.add_default()
+    default_args_gv = [gv1]
+    default_builder.enter_next_block([signed_tok], default_args_gv)
+    [gv1_default] = default_args_gv
+    default_builder.finish_and_return(f2_token, gv1_default)
+    # case == x
+    for x in range(1,11):
+         constx = rgenop.genconst(x)
+         case_builder = flexswitch.add_case(constx)
+         case_args_gv = [gv1]
+         case_builder.enter_next_block([signed_tok], case_args_gv)
+         [gv1_casex] = case_args_gv
+         const2px= rgenop.genconst(1<<x)
+         gv_res_casex = case_builder.genop2('int_add', const2px, gv1_casex)
+         case_builder.finish_and_return(f2_token, gv_res_casex)
+
+    gv_switch = rgenop.gencallableconst(f2_token, "large_switch", graph)
+    return gv_switch
+
+def get_large_switch_runner(RGenOp):
+    def large_switch_runner(x, y):
+        rgenop = RGenOp()
+        gv_large_switchfn = make_large_switch(rgenop)
+        largeswitchfn = gv_large_switchfn.revealconst(lltype.Ptr(FUNC2))
+        res = largeswitchfn(x, y)
+        keepalive_until_here(rgenop)    # to keep the code blocks alive
+        return res
+    return large_switch_runner
+
 class AbstractRGenOpTests(test_boehm.AbstractGCTestClass):
     RGenOp = None
 
@@ -348,14 +408,47 @@
         res = fn(3, 0)
         assert res == 6
 
-##     def test_switch_direct(self):
-##         rgenop = self.RGenOp()
-##         gv_switchfn = build_switch(rgenop)
-##         print gv_switchfn.value
-##         fnptr = cast(c_void_p(gv_switchfn.value), CFUNCTYPE(c_int, c_int, c_int))
-##         res = fnptr(0, 2)
-##         assert res == 42
-##         res = fnptr(1, 16)
-##         assert res == 37
-##         res = fnptr(42, 16)
-##         assert res == 16
+    def test_switch_direct(self):
+        rgenop = self.RGenOp()
+        gv_switchfn = make_switch(rgenop)
+        print gv_switchfn.value
+        import os
+        fnptr = cast(c_void_p(gv_switchfn.value), CFUNCTYPE(c_int, c_int))
+        res = fnptr(0, 2)
+        assert res == 42
+        res = fnptr(1, 16)
+        assert res == 37
+        res = fnptr(42, 16)
+        assert res == 16
+
+    def test_switch_compile(self):
+        fn = self.compile(get_switch_runner(self.RGenOp), [int, int])
+        res = fn(0, 2)
+        assert res == 42
+        res = fn(1, 17)
+        assert res == 38
+        res = fn(42, 18)
+        assert res == 18
+
+    def test_large_switch_direct(self):
+        rgenop = self.RGenOp()
+        gv_switchfn = make_large_switch(rgenop)
+        print gv_switchfn.value
+        fnptr = cast(c_void_p(gv_switchfn.value), CFUNCTYPE(c_int, c_int, c_int))
+        res = fnptr(0, 2)
+        assert res == 42
+        for x in range(1,11):
+            res = fnptr(x, 5)
+            assert res == 2**x+5
+        res = fnptr(42, 16)
+        assert res == 16
+
+    def test_large_switch_compile(self):
+        fn = self.compile(get_large_switch_runner(self.RGenOp), [int, int])
+        res = fn(0, 2)
+        assert res == 42
+        for x in range(1,11):
+            res = fn(x, 7)
+            assert res == 2**x+7 
+        res = fn(42, 18)
+        assert res == 18



More information about the Pypy-commit mailing list