[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