[pypy-svn] r37070 - in pypy/dist/pypy/jit/codegen: ppc test
mwh at codespeak.net
mwh at codespeak.net
Sat Jan 20 19:56:21 CET 2007
Author: mwh
Date: Sat Jan 20 19:56:17 2007
New Revision: 37070
Modified:
pypy/dist/pypy/jit/codegen/ppc/instruction.py
pypy/dist/pypy/jit/codegen/ppc/regalloc.py
pypy/dist/pypy/jit/codegen/ppc/rgenop.py
pypy/dist/pypy/jit/codegen/test/rgenop_tests.py
Log:
a slightly jumbled checkin, as might be expected after a long train ride of
hacking.
highlights:
* fix a nasty bug in pause_writing that failed to propagate stack sizes around
correctly (this lets me remove a "fix" that I always sort of knew was dodgy)
* fix a horrible, but thankfully shallow, bug in genop_call
* support for calling functions with more than 8 arguments
* rework the stack alignment code to not require a conditional jump in the
middle of it (there's still a conditional trap that checks i haven't goofed
for now)
* implement erasedType
* sundry tests and asserts
Modified: pypy/dist/pypy/jit/codegen/ppc/instruction.py
==============================================================================
--- pypy/dist/pypy/jit/codegen/ppc/instruction.py (original)
+++ pypy/dist/pypy/jit/codegen/ppc/instruction.py Sat Jan 20 19:56:17 2007
@@ -433,13 +433,24 @@
else:
self.loc = None
def emit(self, asm):
- targetreg = 3+self.argnumber
- if self.loc is None:
- self.arg.load_now(asm, gprs[targetreg])
- elif self.loc.is_register:
- asm.mr(targetreg, self.loc.number)
+ if self.argnumber < 8: # magic numbers 'r' us
+ targetreg = 3+self.argnumber
+ if self.loc is None:
+ self.arg.load_now(asm, gprs[targetreg])
+ elif self.loc.is_register:
+ asm.mr(targetreg, self.loc.number)
+ else:
+ asm.lwz(targetreg, rFP, self.loc.offset)
else:
- asm.lwz(targetreg, rFP, self.loc.offset)
+ targetoffset = 24+self.argnumber*4
+ if self.loc is None:
+ self.arg.load_now(asm, gprs[0])
+ asm.stw(r0, r1, targetoffset)
+ elif self.loc.is_register:
+ asm.stw(self.loc.number, r1, targetoffset)
+ else:
+ asm.lwz(r0, rFP, self.loc.offset)
+ asm.stw(r0, r1, targetoffset)
class CALL(Insn):
def __init__(self, result, target):
Modified: pypy/dist/pypy/jit/codegen/ppc/regalloc.py
==============================================================================
--- pypy/dist/pypy/jit/codegen/ppc/regalloc.py (original)
+++ pypy/dist/pypy/jit/codegen/ppc/regalloc.py Sat Jan 20 19:56:17 2007
@@ -33,9 +33,12 @@
# go through the initial mapping and initialize the data structures
for var, loc in initial_mapping.iteritems():
self.set(var, loc)
- if loc.is_register and loc.alloc in self.freeregs[loc.regclass]:
- self.freeregs[loc.regclass].remove(loc.alloc)
- self.lru.append(var)
+ if loc.is_register:
+ if loc.alloc in self.freeregs[loc.regclass]:
+ self.freeregs[loc.regclass].remove(loc.alloc)
+ self.lru.append(var)
+ else:
+ assert loc.offset >= self.spill_offset
self.labels_to_tell_spill_offset_to = []
self.builders_to_tell_spill_offset_to = []
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 Jan 20 19:56:17 2007
@@ -153,8 +153,6 @@
tar2loc[tloc] = tloc
tar2src[tloc] = src
else:
- if not tloc.is_register:
- allocator.spill_offset = min(tloc.offset, allocator.spill_offset)
insns.append(insn.Load(tloc, src))
gen = JumpPatchupGenerator(insns, allocator)
@@ -238,7 +236,7 @@
for i in range(len(args_gv)):
self.insns.append(insn.LoadArg(i, args_gv[i]))
gv_result = Var()
- self.max_param_space = len(args_gv)*4
+ self.max_param_space = max(self.max_param_space, len(args_gv)*4)
self.insns.append(insn.CALL(gv_result, gv_fnptr))
return gv_result
@@ -373,8 +371,11 @@
allocator = self.allocate(outputargs_gv)
prepare_for_jump(
self.insns, outputargs_gv, allocator.var2loc, target, allocator)
- allocator.spill_offset = min(allocator.spill_offset, target.min_stack_offset)
self.emit(allocator)
+ here_size = self._stack_size(allocator.spill_offset)
+ there_size = self._stack_size(target.min_stack_offset)
+ if here_size != there_size:
+ self.emit_stack_adjustment(there_size)
self.asm.load_word(rSCRATCH, target.startaddr)
self.asm.mtctr(rSCRATCH)
self.asm.bctr()
@@ -419,14 +420,18 @@
def maybe_patch_start_here(self):
if self.patch_start_here:
mc = self.asm.mc
- self.asm.mc = self.rgenop.ExistingCodeBlock(self.patch_start_here, self.patch_start_here+8)
+ self.asm.mc = self.rgenop.ExistingCodeBlock(
+ self.patch_start_here, self.patch_start_here+8)
self.asm.load_word(rSCRATCH, mc.tell())
self.asm.mc = mc
self.patch_start_here = 0
def pause_writing(self, args_gv):
- self.initial_var2loc = self.allocate_and_emit(args_gv).var2loc
+ allocator = self.allocate_and_emit(args_gv)
+ self.initial_var2loc = allocator.var2loc
+ self.initial_spill_offset = allocator.spill_offset
self.insns = []
+ self.max_param_space = -1
self.final_jump_addr = self.asm.mc.tell()
self.closed = True
self.asm.nop()
@@ -534,8 +539,11 @@
return allocator
def emit(self, allocator):
- if allocator.spill_offset < self.initial_spill_offset:
- self.emit_stack_adjustment(self._stack_size(allocator.spill_offset))
+ in_size = self._stack_size(self.initial_spill_offset)
+ our_size = self._stack_size(allocator.spill_offset)
+ if in_size != our_size:
+ assert our_size > in_size
+ self.emit_stack_adjustment(our_size)
for insn in self.insns:
insn.emit(self.asm)
for label in allocator.labels_to_tell_spill_offset_to:
@@ -551,20 +559,17 @@
# this code satisfies this, although there is a 1-instruction
# window where such walking would find a strange intermediate
# "frame"
- # as we emit these instructions waaay before doing the
- # 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)
- #print 'enlargening stack to', newsize
self.asm.addi(rSCRATCH, rFP, -newsize)
- self.asm.subx(rSCRATCH, rSCRATCH, rSP) # rSCRATCH should now be <= 0
- self.asm.beq(3) # if rSCRATCH == 0, there is no actual adjustment, so
- # don't end up with the situation where *(rSP) == rSP
+ self.asm.sub(rSCRATCH, rSCRATCH, rSP)
+
+ # this is a pure debugging check that we avoid the situation
+ # where *(r1) == r1 which would violates the ABI rules listed
+ # above. after a while it can be removed or maybe made
+ # conditional on some --option passed to py.test
+ self.asm.tweqi(rSCRATCH, 0)
+
self.asm.stwux(rSP, rSP, rSCRATCH)
self.asm.stw(rFP, rSP, 0)
- # branch to "here"
def _arg_op(self, gv_arg, opcode):
gv_result = Var()
@@ -964,8 +969,16 @@
## def replay(self, label, kinds):
-## @staticmethod
-## def erasedType(T):
+ @staticmethod
+ def erasedType(T):
+ if T is llmemory.Address:
+ return llmemory.Address
+ if isinstance(T, lltype.Primitive):
+ return lltype.Signed
+ elif isinstance(T, lltype.Ptr):
+ return llmemory.GCREF
+ else:
+ assert 0, "XXX not implemented"
@staticmethod
@specialize.memo()
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 Jan 20 19:56:17 2007
@@ -524,6 +524,83 @@
return res
return runner
+def make_something_a_bit_like_residual_red_call_with_exc(rgenop):
+ # def f(x, y):
+ # if x:
+ # z = 1
+ # w = 2
+ # else:
+ # z = y+1
+ # w = y
+ # return add1(z*w)
+ # but more obfuscated, more like:
+ # def f(x, y)
+ # c = x != 0
+ # jump_if_true c, [] ---> finish_and_goto([1, 2])
+ # y = add1(y) |
+ # [z, w] = enter_next_block([y, x]) <----'
+ # pause/resume here
+ # z2 = z * w
+ # u = add1(z2)
+ # v = u * z
+ # return add1(u)
+ gv_add1 = make_adder(rgenop, 1)
+ signed_kind = rgenop.kindToken(lltype.Signed)
+ sigtoken = rgenop.sigToken(FUNC2)
+ builder, gv_f, [gv_x, gv_y] = rgenop.newgraph(sigtoken, "f")
+
+ gv_c = builder.genop2("int_ne", gv_x, rgenop.genconst(0))
+
+ true_builder = builder.jump_if_true(gv_c, [])
+
+ gv_y2 = builder.genop_call(rgenop.sigToken(FUNC), gv_add1, [gv_y])
+
+ args_gv = [gv_y2, gv_y]
+ label = builder.enter_next_block([signed_kind], args_gv)
+ [gv_z, gv_w] = args_gv
+
+ builder = builder.pause_writing(args_gv)
+ builder.start_writing()
+
+ gv_z2 = builder.genop2("int_mul", gv_z, gv_w)
+
+ gv_u = builder.genop_call(rgenop.sigToken(FUNC), gv_add1, [gv_z2])
+
+ gv_v = builder.genop2("int_mul", gv_u, gv_z)
+
+ gv_result = builder.genop_call(rgenop.sigToken(FUNC), gv_add1, [gv_u])
+
+ builder.finish_and_return(sigtoken, gv_result)
+
+ true_builder.start_writing()
+ true_builder.finish_and_goto([rgenop.genconst(1), rgenop.genconst(2)], label)
+
+ builder.end()
+ return gv_f
+
+def make_call_functions_with_different_signatures(rgenop):
+ # this also tests calling functions with enormous numbers of
+ # parameters, something not tested yet.
+ # def f(x, y):
+ # z = largedummy(*((y,)*100))
+ # w = add1(x)
+ # return z+w
+ sig2token = rgenop.sigToken(FUNC2)
+ sig1token = rgenop.sigToken(FUNC)
+ sig100token = rgenop.sigToken(FUNC100)
+ builder, gv_callable, [gv_x, gv_y] = rgenop.newgraph(sig2token, "f")
+
+ gv_largedummy = make_largedummy(rgenop)
+ gv_add1 = make_adder(rgenop, 1)
+
+ gv_z = builder.genop_call(sig100token, gv_largedummy, [gv_y]*100)
+ gv_w = builder.genop_call(sig1token, gv_add1, [gv_x])
+ gv_result = builder.genop2("int_add", gv_z, gv_w)
+ builder.finish_and_return(sig2token, gv_result)
+ builder.end()
+
+ return gv_callable
+
class AbstractRGenOpTests(test_boehm.AbstractGCTestClass):
RGenOp = None
@@ -701,7 +778,7 @@
assert res == 42
for x in range(1,11):
res = fn(x, 7)
- assert res == 2**x+7
+ assert res == 2**x+7
res = fn(42, 18)
assert res == 18
@@ -985,6 +1062,28 @@
res = fn(3)
assert res == 8
+ def test_like_residual_red_call_with_exc_direct(self):
+ rgenop = self.RGenOp()
+ gv_callable = make_something_a_bit_like_residual_red_call_with_exc(rgenop)
+ fnptr = self.cast(gv_callable, 2)
+
+ res = fnptr(1, 3)
+ assert res == 4
+
+ res = fnptr(0, 3)
+ assert res == 14
+
+ def test_call_functions_with_different_signatures_direct(self):
+ rgenop = self.RGenOp()
+ gv_callable = make_call_functions_with_different_signatures(rgenop)
+ fnptr = self.cast(gv_callable, 2)
+
+ res = fnptr(1, 3)
+ assert res == 2
+
+ res = fnptr(0, 3)
+ assert res == 1
+
def test_defaultonly_switch(self):
rgenop = self.RGenOp()
signed_kind = rgenop.kindToken(lltype.Signed)
More information about the Pypy-commit
mailing list