[pypy-svn] r33196 - in pypy/dist/pypy/jit/codegen/i386: . test

pedronis at codespeak.net pedronis at codespeak.net
Wed Oct 11 23:34:25 CEST 2006


Author: pedronis
Date: Wed Oct 11 23:34:22 2006
New Revision: 33196

Modified:
   pypy/dist/pypy/jit/codegen/i386/rgenop.py
   pypy/dist/pypy/jit/codegen/i386/test/test_genc_promotion.py
   pypy/dist/pypy/jit/codegen/i386/test/test_rgenop.py
Log:
support allocating new space and using it when a flexswitch runs out of allocated space for
its instructions.

all test_promotion tests now pass for the i386 backend!



Modified: pypy/dist/pypy/jit/codegen/i386/rgenop.py
==============================================================================
--- pypy/dist/pypy/jit/codegen/i386/rgenop.py	(original)
+++ pypy/dist/pypy/jit/codegen/i386/rgenop.py	Wed Oct 11 23:34:22 2006
@@ -2,7 +2,7 @@
 from pypy.rpython.objectmodel import specialize
 from pypy.rpython.lltypesystem import lltype, llmemory
 from pypy.jit.codegen.i386.ri386 import *
-from pypy.jit.codegen.i386.codebuf import InMemoryCodeBuilder
+from pypy.jit.codegen.i386.codebuf import InMemoryCodeBuilder, CodeBlockOverflow
 from pypy.jit.codegen.model import AbstractRGenOp, CodeGenBlock, CodeGenerator
 from pypy.jit.codegen.model import GenVar, GenConst, CodeGenSwitch
 from pypy.rpython import objectmodel
@@ -152,32 +152,58 @@
         self.default_case_addr = 0
 
     def initialize(self, builder, gv_exitswitch):
-        RESERVED = 11*8+5      # XXX quite a lot for now :-/
         mc = builder.mc
         mc.MOV(eax, gv_exitswitch.operand(builder))
         self.saved_state = builder._save_state()
+        self._reserve(mc)
+
+    def _reserve(self, mc):
+        RESERVED = 11*4+5      # XXX quite a lot for now :-/
         pos = mc.tell()
         mc.UD2()
         mc.write('\x00' * (RESERVED-1))
         self.nextfreepos = pos
         self.endfreepos = pos + RESERVED
 
+    def _reserve_more(self):
+        start = self.nextfreepos
+        end   = self.endfreepos
+        newmc = self.rgenop.open_mc()
+        self._reserve(newmc)
+        self.rgenop.close_mc(newmc)
+        fullmc = InMemoryCodeBuilder(start, end)
+        fullmc.JMP(rel32(self.nextfreepos))
+        fullmc.done()
+        
     def add_case(self, gv_case):
         rgenop = self.rgenop
         targetbuilder = Builder._new_from_state(rgenop, self.saved_state)
+        target_addr = targetbuilder.mc.tell()
+        try:
+            self._add_case(gv_case, target_addr)
+        except CodeBlockOverflow:
+            self._reserve_more()
+            self._add_case(gv_case, target_addr)
+        return targetbuilder
+    
+    def _add_case(self, gv_case, target_addr):
         start = self.nextfreepos
         end   = self.endfreepos
         mc = InMemoryCodeBuilder(start, end)
         mc.CMP(eax, gv_case.operand(None))
-        mc.JE(rel32(targetbuilder.mc.tell()))
+        mc.JE(rel32(target_addr))
         pos = mc.tell()
         if self.default_case_addr:
             mc.JMP(rel32(self.default_case_addr))
         else:
+            illegal_start = mc.tell()
+            mc.JMP(rel32(0))
+            ud2_addr = mc.tell()
             mc.UD2()
+            illegal_mc = InMemoryCodeBuilder(illegal_start, end)
+            illegal_mc.JMP(rel32(ud2_addr))
         mc.done()
         self.nextfreepos = pos
-        return targetbuilder
 
     def add_default(self):
         rgenop = self.rgenop
@@ -190,7 +216,6 @@
         mc.done()
         return targetbuilder
 
-
 class Builder(CodeGenerator):
 
     def __init__(self, rgenop, mc, stackdepth):

Modified: pypy/dist/pypy/jit/codegen/i386/test/test_genc_promotion.py
==============================================================================
--- pypy/dist/pypy/jit/codegen/i386/test/test_genc_promotion.py	(original)
+++ pypy/dist/pypy/jit/codegen/i386/test/test_genc_promotion.py	Wed Oct 11 23:34:22 2006
@@ -7,6 +7,4 @@
 
     # for the individual tests see
     # ====> ../../../timeshifter/test/test_promotion.py
-
-    def test_many_promotions(self):
-        py.test.skip("in-progress")
+    pass

Modified: pypy/dist/pypy/jit/codegen/i386/test/test_rgenop.py
==============================================================================
--- pypy/dist/pypy/jit/codegen/i386/test/test_rgenop.py	(original)
+++ pypy/dist/pypy/jit/codegen/i386/test/test_rgenop.py	Wed Oct 11 23:34:22 2006
@@ -390,3 +390,84 @@
     assert res == 38
     res = fn(42, 18)
     assert res == 18
+
+def build_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 large_switch_runner(x, y):
+    rgenop = RI386GenOp()
+    gv_switchfn = build_large_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
+
+def test_large_switch_direct():
+    rgenop = RI386GenOp()
+    gv_switchfn = build_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():
+    fn = compile(large_switch_runner, [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