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

arigo at codespeak.net arigo at codespeak.net
Thu Jan 25 22:17:59 CET 2007


Author: arigo
Date: Thu Jan 25 22:17:58 2007
New Revision: 37359

Modified:
   pypy/dist/pypy/jit/codegen/i386/operation.py
   pypy/dist/pypy/jit/codegen/i386/regalloc.py
   pypy/dist/pypy/jit/codegen/i386/rgenop.py
   pypy/dist/pypy/jit/codegen/i386/test/test_rgenop.py
   pypy/dist/pypy/jit/codegen/test/rgenop_tests.py
Log:
Reorganize the read_frame_var tests for being compilable.
Implement them for the i386 backend.

Lesson one is to first get things working and maybe 
later think about a super-advanced register allocator.



Modified: pypy/dist/pypy/jit/codegen/i386/operation.py
==============================================================================
--- pypy/dist/pypy/jit/codegen/i386/operation.py	(original)
+++ pypy/dist/pypy/jit/codegen/i386/operation.py	Thu Jan 25 22:17:58 2007
@@ -592,6 +592,7 @@
         return memSIB (base, opindex, indexshift, startoffset)
 
 class OpComputeSize(Operation):
+    clobbers_cc = False
     def __init__(self, varsizealloctoken, gv_length):
         self.varsizealloctoken = varsizealloctoken
         self.gv_length = gv_length
@@ -689,6 +690,7 @@
                 mc.MOV(opdst, ecx)
 
 class OpGetField(Operation):
+    clobbers_cc = False
     def __init__(self, fieldtoken, gv_ptr):
         self.fieldtoken = fieldtoken
         self.gv_ptr = gv_ptr
@@ -706,6 +708,7 @@
         hard_load(mc, dstop, opsource, fieldsize)
 
 class OpSetField(Operation):
+    clobbers_cc = False
     result_kind = RK_NO_RESULT
     def __init__(self, fieldtoken, gv_ptr, gv_value):
         self.fieldtoken = fieldtoken
@@ -785,6 +788,15 @@
             mc.LEA(ecx, opsource)
             mc.MOV(dstop, ecx)
 
+class OpGetFrameBase(Operation):
+    def generate(self, allocator):
+        try:
+            dstop = allocator.get_operand(self)
+        except KeyError:
+            return    # result not used
+        mc = allocator.mc
+        mc.MOV(dstop, ebp)
+
 # ____________________________________________________________
 
 def setup_opclasses(base):

Modified: pypy/dist/pypy/jit/codegen/i386/regalloc.py
==============================================================================
--- pypy/dist/pypy/jit/codegen/i386/regalloc.py	(original)
+++ pypy/dist/pypy/jit/codegen/i386/regalloc.py	Thu Jan 25 22:17:58 2007
@@ -44,12 +44,11 @@
         self.force_loc2operand = {}
         self.force_operand2loc = {}
         self.initial_moves = []
+        self.num_stack_locs = 0
 
     def set_final(self, final_vars_gv):
         for v in final_vars_gv:
-            if not v.is_const and v not in self.var2loc:
-                self.var2loc[v] = self.nextloc
-                self.nextloc += 1
+            self.using(v)
 
     def creating(self, v):
         try:
@@ -57,7 +56,8 @@
         except KeyError:
             pass
         else:
-            self.available_locs.append(loc)   # now available again for reuse
+            if loc >= self.num_stack_locs:
+                self.available_locs.append(loc) # now available again for reuse
 
     def using(self, v):
         if not v.is_const and v not in self.var2loc:
@@ -156,12 +156,16 @@
                 seen_stackn[stack_n_from_op(op)] = None
         i = 0
         stackn = 0
+        num_stack_locs = self.num_stack_locs
         for loc in range(self.nextloc):
             try:
                 operand = force_loc2operand[loc]
             except KeyError:
-                # grab the next free register
                 try:
+                    # try to grab the next free register,
+                    # unless this location is forced to go to the stack
+                    if loc < num_stack_locs:
+                        raise IndexError
                     while True:
                         operand = RegAllocator.AVAILABLE_REGS[i]
                         i += 1
@@ -229,3 +233,30 @@
                 except FailedToImplement:
                     mc.MOVZX(ecx, cl)
                     mc.MOV(dstop, ecx)
+
+    def force_stack_storage(self, lst):
+        # this is called at the very beginning, so the 'loc' numbers
+        # computed here are the smaller ones
+        N = 0
+        for v, place in lst:
+            self.using(v)
+            loc = self.var2loc[v]
+            if loc >= N:
+                N = loc + 1
+        self.num_stack_locs = N
+
+    def save_storage_places(self, lst):
+        for v, place in lst:
+            loc = self.var2loc[v]
+            operand = self.operands[loc]
+            place.offset = operand.ofs_relative_to_ebp()
+
+
+class StorageInStack(GenVar):
+    """Place of a variable that must live in the stack.  Its position is
+    choosen by the register allocator and put in the 'stackn' attribute."""
+    offset = 0
+
+    def get_offset(self):
+        assert self.offset != 0     # otherwise, RegAllocator bug
+        return self.offset

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	Thu Jan 25 22:17:58 2007
@@ -5,7 +5,7 @@
 from pypy.jit.codegen.model import GenVar, GenConst, CodeGenSwitch
 from pypy.jit.codegen.i386.codebuf import CodeBlockOverflow
 from pypy.jit.codegen.i386.operation import *
-from pypy.jit.codegen.i386.regalloc import RegAllocator
+from pypy.jit.codegen.i386.regalloc import RegAllocator, StorageInStack
 from pypy.jit.codegen import conftest
 from pypy.rpython.annlowlevel import llhelper
 
@@ -20,12 +20,7 @@
 
     @specialize.arg(1)
     def revealconst(self, T):
-        if isinstance(T, lltype.Ptr):
-            return lltype.cast_int_to_ptr(T, self.value)
-        elif T is llmemory.Address:
-            return llmemory.cast_int_to_adr(self.value)
-        else:
-            return lltype.cast_primitive(T, self.value)
+        return cast_int_to_whatever(T, self.value)
 
     def __repr__(self):
         "NOT_RPYTHON"
@@ -44,14 +39,7 @@
 
     @specialize.arg(1)
     def revealconst(self, T):
-        if T is llmemory.Address:
-            return self.addr
-        elif isinstance(T, lltype.Ptr):
-            return llmemory.cast_adr_to_ptr(self.addr, T)
-        elif T is lltype.Signed:
-            return llmemory.cast_adr_to_int(self.addr)
-        else:
-            assert 0, "XXX not implemented"
+        return cast_adr_to_whatever(T, self.addr)
 
     def __repr__(self):
         "NOT_RPYTHON"
@@ -60,6 +48,26 @@
     def repr(self):
         return "const=<0x%x>" % (llmemory.cast_adr_to_int(self.addr),)
 
+ at specialize.arg(0)
+def cast_int_to_whatever(T, value):
+    if isinstance(T, lltype.Ptr):
+        return lltype.cast_int_to_ptr(T, value)
+    elif T is llmemory.Address:
+        return llmemory.cast_int_to_adr(value)
+    else:
+        return lltype.cast_primitive(T, value)
+
+ at specialize.arg(0)
+def cast_adr_to_whatever(T, addr):
+    if T is llmemory.Address:
+        return addr
+    elif isinstance(T, lltype.Ptr):
+        return llmemory.cast_adr_to_ptr(addr, T)
+    elif T is lltype.Signed:
+        return llmemory.cast_adr_to_int(addr)
+    else:
+        assert 0, "XXX not implemented"
+
 # ____________________________________________________________
 
 class FlexSwitch(CodeGenSwitch):
@@ -160,12 +168,24 @@
             GC_malloc = boehmlib.GC_malloc
             return cast(GC_malloc, c_void_p).value
 
+def peek_word_at(addr):
+    # now the Very Obscure Bit: when translated, 'addr' is an
+    # address.  When not, it's an integer.  It just happens to
+    # make the test pass, but that's probably going to change.
+    if we_are_translated():
+        return addr.signed[0]
+    else:
+        from ctypes import cast, c_void_p, c_int, POINTER
+        p = cast(c_void_p(addr), POINTER(c_int))
+        return p.contents.value
+
 # ____________________________________________________________
 
 class Builder(GenBuilder):
     coming_from = 0
     operations = None
     update_defaultcaseaddr_of = None
+    force_in_stack = None
 
     def __init__(self, rgenop, inputargs_gv, inputoperands):
         self.rgenop = rgenop
@@ -181,6 +201,8 @@
                                                  renaming=True,
                                                  minimal_stack_depth=0):
         allocator = RegAllocator()
+        if self.force_in_stack is not None:
+            allocator.force_stack_storage(self.force_in_stack)
         allocator.set_final(final_vars_gv)
         if not renaming:
             final_vars_gv = allocator.var2loc.keys()  # unique final vars
@@ -196,6 +218,9 @@
         allocator.mc = mc
         allocator.generate_initial_moves()
         allocator.generate_operations()
+        if self.force_in_stack is not None:
+            allocator.save_storage_places(self.force_in_stack)
+            self.force_in_stack = None
         self.operations = None
         if renaming:
             self.inputargs_gv = [GenVar() for v in final_vars_gv]
@@ -409,6 +434,23 @@
         pass  # self.mc.log(msg)
         # XXX re-do this somehow...
 
+    def genop_get_frame_base(self):
+        op = OpGetFrameBase()
+        self.operations.append(op)
+        return op
+
+    def get_frame_info(self, vars_gv):
+        if self.force_in_stack is None:
+            self.force_in_stack = []
+        result = []
+        for v in vars_gv:
+            if not v.is_const:
+                place = StorageInStack()
+                self.force_in_stack.append((v, place))
+                v = place
+            result.append(v)
+        return result
+
 
 class Label(GenLabel):
     targetaddr = 0
@@ -501,6 +543,12 @@
     def show_incremental_progress(self):
         pass
 
+    def genop_get_frame_base(self):
+        return dummy_var
+
+    def get_frame_info(self, vars_gv):
+        return None
+
 # ____________________________________________________________
 
 class RI386GenOp(AbstractRGenOp):
@@ -648,6 +696,23 @@
         else:
             assert 0, "XXX not implemented"
 
+    @staticmethod
+    @specialize.arg(0)
+    def read_frame_var(T, base, info, index):
+        # XXX assumes sizeof(T) == WORD
+        v = info[index]
+        if isinstance(v, StorageInStack):
+            value = peek_word_at(base + v.get_offset())
+            return cast_int_to_whatever(T, value)
+        else:
+            assert isinstance(v, GenConst)
+            return v.revealconst(T)
+
+    @staticmethod
+    @specialize.arg(0)
+    def write_frame_var(T, base, info, index, value):
+        raise NotImplementedError
+
 global_rgenop = RI386GenOp()
 RI386GenOp.constPrebuiltGlobal = global_rgenop.genconst
 

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	Thu Jan 25 22:17:58 2007
@@ -51,7 +51,7 @@
         res = fnptr(21, -21, 0)
         assert res == 42
 
-    def test_read_frame_var_direct(self):   py.test.skip("in-progress")
-    def test_read_frame_var_compile(self):  py.test.skip("in-progress")
+    #def test_read_frame_var_direct(self):   py.test.skip("in-progress")
+    #def test_read_frame_var_compile(self):  py.test.skip("in-progress")
     def test_write_frame_var_direct(self):  py.test.skip("in-progress")
     def test_write_frame_var_compile(self): py.test.skip("in-progress")

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	Thu Jan 25 22:17:58 2007
@@ -617,19 +617,33 @@
 
     return gv_callable
 
-FRAME_VAR_READER = lltype.Ptr(lltype.FuncType([llmemory.Address,
-                                               llmemory.GCREF],
-                                              lltype.Signed))
-FRAME_VAR_WRITER = lltype.Ptr(lltype.FuncType([llmemory.Address,
-                                               llmemory.GCREF,
-                                               lltype.Signed],
-                                              lltype.Void))
+class FrameVarReader:
+    FUNC = lltype.Ptr(lltype.FuncType([llmemory.Address], lltype.Signed))
+    def __init__(self, RGenOp):
+        def reader(base):
+            return RGenOp.read_frame_var(lltype.Signed, base,
+                                         self.frameinfo, 0)
+        self.reader = reader
+    def get_reader(self, info):
+        self.frameinfo = info
+        return llhelper(self.FUNC, self.reader)
+
+class FrameVarWriter:
+    FUNC = lltype.Ptr(lltype.FuncType([llmemory.Address, lltype.Signed],
+                                      lltype.Void))
+    def __init__(self, RGenOp):
+        def writer(base, value):
+            return RGenOp.write_frame_var(lltype.Signed, base,
+                                          self.frameinfo, 0, value)
+        self.writer = writer
+    def get_writer(self, info):
+        self.frameinfo = info
+        return llhelper(self.FUNC, self.writer)
 
-def make_read_frame_var(rgenop, reader_ptr):
+def make_read_frame_var(rgenop, get_reader):
     signed_kind = rgenop.kindToken(lltype.Signed)
     sigtoken = rgenop.sigToken(FUNC)
-    gv_reader = rgenop.constPrebuiltGlobal(reader_ptr)
-    readertoken = rgenop.sigToken(FRAME_VAR_READER.TO)
+    readertoken = rgenop.sigToken(FrameVarReader.FUNC.TO)
 
     builder, gv_f, [gv_x] = rgenop.newgraph(sigtoken, "f")
     builder.start_writing()
@@ -637,31 +651,29 @@
     gv_y = builder.genop2("int_mul", gv_x, rgenop.genconst(2))
     gv_base = builder.genop_get_frame_base()
     info = builder.get_frame_info([gv_y])
-    gv_info = rgenop.genconst(info)
-    gv_z = builder.genop_call(readertoken, gv_reader, [gv_base, gv_info])
+    gv_reader = rgenop.constPrebuiltGlobal(get_reader(info))
+    gv_z = builder.genop_call(readertoken, gv_reader, [gv_base])
     builder.finish_and_return(sigtoken, gv_z)
     builder.end()
 
     return gv_f
 
 def get_read_frame_var_runner(RGenOp):
-    def reader(base, info):
-        return RGenOp.read_frame_var(lltype.Signed, base, info, 0) + 2
+    fvr = FrameVarReader(RGenOp)
 
     def read_frame_var_runner(x):
         rgenop = RGenOp()
-        gv_f = make_read_frame_var(rgenop, llhelper(FRAME_VAR_READER, reader))
+        gv_f = make_read_frame_var(rgenop, fvr.get_reader)
         fn = gv_f.revealconst(lltype.Ptr(FUNC))
         res = fn(x)
         keepalive_until_here(rgenop)    # to keep the code blocks alive
         return res
     return read_frame_var_runner
 
-def make_write_frame_var(rgenop, writer_ptr):
+def make_write_frame_var(rgenop, get_writer):
     signed_kind = rgenop.kindToken(lltype.Signed)
     sigtoken = rgenop.sigToken(FUNC)
-    gv_writer = rgenop.constPrebuiltGlobal(writer_ptr)
-    writertoken = rgenop.sigToken(FRAME_VAR_WRITER.TO)
+    writertoken = rgenop.sigToken(FrameVarWriter.FUNC.TO)
 
     builder, gv_f, [gv_x] = rgenop.newgraph(sigtoken, "f")
     builder.start_writing()
@@ -669,21 +681,20 @@
     gv_y = builder.genop_same_as(signed_kind, rgenop.genconst(0))
     gv_base = builder.genop_get_frame_base()
     info = builder.get_frame_info([gv_y])
-    gv_info = rgenop.constPrebuiltGlobal(info)
     gv_42 = rgenop.genconst(42)
-    builder.genop_call(writertoken, gv_writer, [gv_base, gv_info, gv_42])
+    gv_writer = rgenop.constPrebuiltGlobal(get_writer(info))
+    builder.genop_call(writertoken, gv_writer, [gv_base, gv_42])
     builder.finish_and_return(sigtoken, gv_y)
     builder.end()
 
     return gv_f
 
 def get_write_frame_var_runner(RGenOp):
-    def writer(base, info, value):
-        RGenOp.write_frame_var(lltype.Signed, base, info, 0, value)
+    fvw = FrameVarWriter(RGenOp)
 
     def write_frame_var_runner(x):
         rgenop = RGenOp()
-        gv_f = make_write_frame_var(rgenop, llhelper(FRAME_VAR_WRITER, writer))
+        gv_f = make_write_frame_var(rgenop, fvw.get_writer)
         fn = gv_f.revealconst(lltype.Ptr(FUNC))
         res = fn(x)
         keepalive_until_here(rgenop)    # to keep the code blocks alive
@@ -1229,32 +1240,32 @@
         assert res == 111
 
     def test_read_frame_var_direct(self):
-        RGenOp = self.RGenOp
-
-        def reader(base, info):
-            return RGenOp.read_frame_var(lltype.Signed, base, info, 0) + 2
-        reader_ptr = self.directtesthelper(FRAME_VAR_READER, reader)
+        def get_reader(info):
+            fvr = FrameVarReader(self.RGenOp)
+            fvr.frameinfo = info
+            reader_ptr = self.directtesthelper(fvr.FUNC, fvr.reader)
+            return reader_ptr
 
         rgenop = self.RGenOp()
-        gv_callable = make_read_frame_var(rgenop, reader_ptr)
+        gv_callable = make_read_frame_var(rgenop, get_reader)
         fnptr = self.cast(gv_callable, 1)
         res = fnptr(20)
-        assert res == 42
+        assert res == 40
 
     def test_read_frame_var_compile(self):
         fn = self.compile(get_read_frame_var_runner(self.RGenOp), [int])
         res = fn(30)
-        assert res == 62
+        assert res == 60
 
     def test_write_frame_var_direct(self):
-        RGenOp = self.RGenOp
-
-        def writer(base, info, value):
-            RGenOp.write_frame_var(lltype.Signed, base, info, 0, value)
-        writer_ptr = self.directtesthelper(FRAME_VAR_WRITER, writer)
+        def get_writer(info):
+            fvw = FrameVarWriter(self.RGenOp)
+            fvw.frameinfo = info
+            writer_ptr = self.directtesthelper(fvw.FUNC, fvw.writer)
+            return writer_ptr
 
         rgenop = self.RGenOp()
-        gv_callable = make_write_frame_var(rgenop, writer_ptr)
+        gv_callable = make_write_frame_var(rgenop, get_writer)
         fnptr = self.cast(gv_callable, 1)
         res = fnptr(-0xfada)
         assert res == 42



More information about the Pypy-commit mailing list