[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