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

arigo at codespeak.net arigo at codespeak.net
Wed Aug 23 11:44:01 CEST 2006


Author: arigo
Date: Wed Aug 23 11:43:59 2006
New Revision: 31516

Modified:
   pypy/dist/pypy/jit/codegen/i386/ri386.py
   pypy/dist/pypy/jit/codegen/i386/ri386genop.py
   pypy/dist/pypy/jit/codegen/i386/test/test_ri386genop.py
Log:
(pedronis, arigo)

Some link support.  Fun copying values from a "previous stack layout" to
a "new stack layout" overlapping it.



Modified: pypy/dist/pypy/jit/codegen/i386/ri386.py
==============================================================================
--- pypy/dist/pypy/jit/codegen/i386/ri386.py	(original)
+++ pypy/dist/pypy/jit/codegen/i386/ri386.py	Wed Aug 23 11:43:59 2006
@@ -84,6 +84,12 @@
 imm16 = IMM16
 rel32 = REL32
 
+def imm(value):
+    if single_byte(value):
+        return imm8(value)
+    else:
+        return imm32(value)
+
 def memregister(register):
     assert register.width == 4
     return MODRM(0xC0 | register.op, '')

Modified: pypy/dist/pypy/jit/codegen/i386/ri386genop.py
==============================================================================
--- pypy/dist/pypy/jit/codegen/i386/ri386genop.py	(original)
+++ pypy/dist/pypy/jit/codegen/i386/ri386genop.py	Wed Aug 23 11:43:59 2006
@@ -25,7 +25,7 @@
         self.stackpos = stackpos
 
     def operand(self, block):
-        return mem(esp, WORD * (block.stackdepth-1 - self.stackpos))
+        return block.stack_access(self.stackpos)
 
 
 class TypeConst(VarOrConst):
@@ -40,10 +40,7 @@
         self.value = value
 
     def operand(self, block):
-        if single_byte(self.value):
-            return IMM8(self.value)
-        else:
-            return IMM32(self.value)
+        return imm(self.value)
 
 
 class FnPtrConst(IntConst):
@@ -65,6 +62,9 @@
         self.stackdepth += 1
         return res
 
+    def stack_access(self, stackpos):
+        return mem(esp, WORD * (self.stackdepth-1 - stackpos))
+
     def push(self, reg):
         self.mc.PUSH(reg)
         res = Var(self.stackdepth)
@@ -76,25 +76,97 @@
         self.mc.ADD(eax, gv_y.operand(self))
         return self.push(eax)
 
+    def op_int_sub(self, (gv_x, gv_y), gv_RESTYPE):
+        self.mc.MOV(eax, gv_x.operand(self))
+        self.mc.SUB(eax, gv_y.operand(self))
+        return self.push(eax)
+
 
 class RI386GenOp(object):
     gv_IntWord = TypeConst('IntWord')
     gv_Void = TypeConst('Void')
 
     def __init__(self):
-        self.mc = MachineCodeBlock(65536)    # XXX!!!
+        self.mcs = []   # machine code blocks where no-one is currently writing
+
+    def open_mc(self):
+        if self.mcs:
+            # XXX think about inserting NOPS for alignment
+            return self.mcs.pop()
+        else:
+            return MachineCodeBlock(65536)   # XXX supposed infinite for now
+
+    def close_mc(self, mc):
+        self.mcs.append(mc)
 
     def newblock(self):
-        # XXX concurrently-open Blocks cannot use the same mc
-        return Block(self.mc)
+        return Block(self.open_mc())
 
     def closeblock1(self, block):
-        return block
+        return block   # NB. links and blocks are the same for us
 
     def closereturnlink(self, link, gv_result):
         link.mc.MOV(eax, gv_result.operand(link))
-        link.mc.ADD(esp, IMM32(WORD * link.stackdepth))
+        link.mc.ADD(esp, imm32(WORD * link.stackdepth))
         link.mc.RET()
+        self.close_mc(link.mc)
+
+    def closelink(self, link, outputargs_gv, targetblock):
+        N = len(outputargs_gv)
+        if link.stackdepth < N:
+            link.mc.SUB(esp, imm(WORD * (N - link.stackdepth)))
+            link.stackdepth = N
+
+        pending_dests = N
+        srccount = [0] * N
+        for i in range(N):
+            gv = outputargs_gv[i]
+            if isinstance(gv, Var):
+                p = gv.stackpos
+                if 0 <= p < N:
+                    if p == i:
+                        srccount[p] = -N     # ignore 'v=v'
+                        pending_dests -= 1
+                    else:
+                        srccount[p] += 1
+
+        while pending_dests:
+            progress = False
+            for i in range(N):
+                if srccount[i] == 0:
+                    srccount[i] = -1
+                    pending_dests -= 1
+                    gv_src = outputargs_gv[i]
+                    link.mc.MOV(eax, gv_src.operand(link))
+                    link.mc.MOV(link.stack_access(i), eax)
+                    progress = True
+            if not progress:
+                # we are left with only pure disjoint cycles; break them
+                for i in range(N):
+                    if srccount[i] >= 0:
+                        dst = i
+                        link.mc.MOV(edx, link.stack_access(dst))
+                        while True:
+                            assert srccount[dst] == 1
+                            srccount[dst] = -1
+                            pending_dests -= 1
+                            gv_src = outputargs_gv[dst]
+                            assert isinstance(gv_src, Var)
+                            src = gv_src.stackpos
+                            assert 0 <= src < N
+                            if src == i:
+                                break
+                            link.mc.MOV(eax, link.stack_access(src))
+                            link.mc.MOV(link.stack_access(dst), eax)
+                            dst = src
+                        link.mc.MOV(link.stack_access(dst), edx)
+                assert pending_dests == 0
+
+        if link.stackdepth > N:
+            link.mc.ADD(esp, imm(WORD * (link.stackdepth - N)))
+            link.stackdepth = N
+        link.mc.JMP(rel32(targetblock.startaddr))
+        self.close_mc(link.mc)
 
     def geninputarg(self, block, gv_TYPE):
         return block.geninputarg(gv_TYPE)
@@ -122,10 +194,13 @@
     def gencallableconst(self, name, block, gv_FUNCTYPE):
         prologue = self.newblock()
         #prologue.mc.BREAKPOINT()
-        operand = mem(esp, WORD * block.argcount)
+        # re-push the arguments so that they are after the return value
+        # and in the correct order
         for i in range(block.argcount):
+            operand = mem(esp, WORD * (2*i+1))
             prologue.mc.PUSH(operand)
         prologue.mc.JMP(rel32(block.startaddr))
+        self.close_mc(prologue.mc)
         return FnPtrConst(prologue.startaddr, prologue.mc)
 
     def revealconst(T, gv_const):

Modified: pypy/dist/pypy/jit/codegen/i386/test/test_ri386genop.py
==============================================================================
--- pypy/dist/pypy/jit/codegen/i386/test/test_ri386genop.py	(original)
+++ pypy/dist/pypy/jit/codegen/i386/test/test_ri386genop.py	Wed Aug 23 11:43:59 2006
@@ -1,6 +1,5 @@
 from pypy.rpython.lltypesystem import lltype
-from pypy.rpython import llinterp
-from pypy.rpython.test.test_llinterp import interpret
+from pypy.rpython.llinterp import LLInterpreter
 from pypy.rpython.objectmodel import keepalive_until_here
 from pypy.translator.c.test.test_genc import compile
 from pypy.jit.codegen.i386.ri386genop import RI386GenOp
@@ -31,10 +30,16 @@
     gv_add_x = make_adder(rgenop, x)
     add_x = rgenop.revealconst(lltype.Ptr(FUNC), gv_add_x)
     res = add_x(y)
-    keepalive_until_here(gv_add_x)    # to keep the 'add_x' fnptr alive
+    keepalive_until_here(rgenop)    # to keep the code blocks alive
     return res
 
-# ____________________________________________________________
+def test_adder_interpret():
+    from pypy.rpython import rgenop
+    gv_add_5 = make_adder(rgenop, 5)
+    add_5 = rgenop.revealconst(lltype.Ptr(FUNC), gv_add_5)
+    llinterp = LLInterpreter(None)
+    res = llinterp.eval_graph(add_5._obj.graph, [12])
+    assert res == 17
 
 def test_adder_direct():
     rgenop = RI386GenOp()
@@ -48,3 +53,63 @@
     fn = compile(runner, [int, int])
     res = fn(9080983, -9080941)
     assert res == 42
+
+# ____________________________________________________________
+
+FUNC2 = lltype.FuncType([lltype.Signed, lltype.Signed], lltype.Signed)
+
+def make_dummy(rgenop):
+    # 'return x - (y - (x-1))'
+    gv_SIGNED = rgenop.constTYPE(lltype.Signed)
+    block = rgenop.newblock()
+    gv_x = rgenop.geninputarg(block, gv_SIGNED)
+    gv_y = rgenop.geninputarg(block, gv_SIGNED)
+    args_gv = [gv_x, rgenop.genconst(1)]
+    gv_z = rgenop.genop(block, "int_sub", args_gv, gv_SIGNED)
+    link = rgenop.closeblock1(block)
+
+    block2 = rgenop.newblock()
+    gv_y2 = rgenop.geninputarg(block2, gv_SIGNED)
+    gv_z2 = rgenop.geninputarg(block2, gv_SIGNED)
+    gv_x2 = rgenop.geninputarg(block2, gv_SIGNED)
+    rgenop.closelink(link, [gv_y, gv_z, gv_x], block2)
+
+    args_gv = [gv_y2, gv_z2]
+    gv_s2 = rgenop.genop(block2, "int_sub", args_gv, gv_SIGNED)
+    args_gv = [gv_x2, gv_s2]
+    gv_t2 = rgenop.genop(block2, "int_sub", args_gv, gv_SIGNED)
+    link2 = rgenop.closeblock1(block2)
+
+    rgenop.closereturnlink(link2, gv_t2)
+    gv_FUNC2 = rgenop.constTYPE(FUNC2)
+    gv_dummyfn = rgenop.gencallableconst("dummy", block, gv_FUNC2)
+    return gv_dummyfn
+
+def dummy_runner(x, y):
+    rgenop = RI386GenOp()
+    gv_dummyfn = make_dummy(rgenop)
+    dummyfn = rgenop.revealconst(lltype.Ptr(FUNC2), gv_dummyfn)
+    res = dummyfn(x, y)
+    keepalive_until_here(rgenop)    # to keep the code blocks alive
+    return res
+
+def test_dummy_interpret():
+    from pypy.rpython import rgenop
+    gv_dummyfn = make_dummy(rgenop)
+    dummyfn = rgenop.revealconst(lltype.Ptr(FUNC2), gv_dummyfn)
+    llinterp = LLInterpreter(None)
+    res = llinterp.eval_graph(dummyfn._obj.graph, [30, 17])
+    assert res == 42
+
+def test_dummy_direct():
+    rgenop = RI386GenOp()
+    gv_dummyfn = make_dummy(rgenop)
+    print gv_dummyfn.value
+    fnptr = cast(c_void_p(gv_dummyfn.value), CFUNCTYPE(c_int, c_int, c_int))
+    res = fnptr(30, 17)    # <== the segfault is here
+    assert res == 42
+
+def test_dummy_compile():
+    fn = compile(dummy_runner, [int, int])
+    res = fn(40, 37)
+    assert res == 42



More information about the Pypy-commit mailing list