[pypy-svn] r69473 - in pypy/branch/shorter-guard-path/pypy/jit/backend/x86: . test

arigo at codespeak.net arigo at codespeak.net
Fri Nov 20 17:23:52 CET 2009


Author: arigo
Date: Fri Nov 20 17:23:51 2009
New Revision: 69473

Modified:
   pypy/branch/shorter-guard-path/pypy/jit/backend/x86/assembler.py
   pypy/branch/shorter-guard-path/pypy/jit/backend/x86/support.py
   pypy/branch/shorter-guard-path/pypy/jit/backend/x86/test/test_assembler.py
Log:
Phew.  The failure_recovery code.


Modified: pypy/branch/shorter-guard-path/pypy/jit/backend/x86/assembler.py
==============================================================================
--- pypy/branch/shorter-guard-path/pypy/jit/backend/x86/assembler.py	(original)
+++ pypy/branch/shorter-guard-path/pypy/jit/backend/x86/assembler.py	Fri Nov 20 17:23:51 2009
@@ -125,6 +125,9 @@
             self.mc2 = MachineCodeBlockWrapper()
             self._build_failure_recovery(False)
             self._build_failure_recovery(True)
+            if self.cpu.supports_floats:
+                self._build_failure_recovery(False, withfloats=True)
+                self._build_failure_recovery(True, withfloats=True)
 
     def assemble_loop(self, inputargs, operations, looptoken):
         """adds the following attributes to looptoken:
@@ -773,7 +776,12 @@
             self.mc2.make_new_mc()
         mc = self.mc2._mc
         addr = mc.tell()
-        mc.CALL(rel32(self.failure_recovery_code[exc]))
+        withfloats = False
+        for box in failargs:
+            if box.type == FLOAT:
+                withfloats = True
+                break
+        mc.CALL(rel32(self.failure_recovery_code[exc + 2 * withfloats]))
         # write tight data that describes the failure recovery
         self.write_failure_recovery_description(mc, failargs, fail_locs)
         # write the fail_index too
@@ -811,19 +819,84 @@
                 n >>= 7
             mc.writechr(n)
         mc.writechr(self.DESCR_STOP)
+        # preallocate the fail_boxes
+        i = len(failargs) - 1
+        if i >= 0:
+            self.fail_boxes_int.get_addr_for_num(i)
+            self.fail_boxes_ptr.get_addr_for_num(i)
+            if self.cpu.supports_floats:
+                self.fail_boxes_float.get_addr_for_num(i)
 
     def setup_failure_recovery(self):
 
         def failure_recovery_func(registers):
-            pass  #...
+            # no malloc allowed here!!
+            stack_at_ebp = registers[ebp.op]
+            bytecode = rffi.cast(rffi.UCHARP, registers[8])
+            num = 0
+            value_hi = 0
+            while 1:
+                # decode the next instruction from the bytecode
+                code = rffi.cast(lltype.Signed, bytecode[0])
+                bytecode = rffi.ptradd(bytecode, 1)
+                if code >= 4*self.DESCR_FROMSTACK:
+                    if code > 0x7F:
+                        shift = 7
+                        code &= 0x7F
+                        while True:
+                            nextcode = rffi.cast(lltype.Signed, bytecode[0])
+                            bytecode = rffi.ptradd(bytecode, 1)
+                            code |= (nextcode & 0x7F) << shift
+                            shift += 7
+                            if nextcode <= 0x7F:
+                                break
+                    # load the value from the stack
+                    kind = code & 3
+                    code = (code >> 2) - self.DESCR_FROMSTACK
+                    stackloc = stack_at_ebp + get_ebp_ofs(code)
+                    value = rffi.cast(rffi.LONGP, stackloc)[0]
+                    if kind == self.DESCR_FLOAT:
+                        value_hi = value
+                        stackloc -= 4
+                        value = rffi.cast(rffi.LONGP, stackloc)[0]
+                elif code == self.DESCR_STOP:
+                    break
+                else:
+                    # 'code' identifies a register: load its value
+                    kind = code & 3
+                    code >>= 2
+                    if kind == self.DESCR_FLOAT:
+                        xmmregisters = rffi.ptradd(registers, -16)
+                        value = xmmregisters[2*code]
+                        value_hi = xmmregisters[2*code + 1]
+                    else:
+                        value = registers[code]
+
+                # store the loaded value into fail_boxes_<type>
+                if kind == self.DESCR_INT:
+                    tgt = self.fail_boxes_int.get_addr_for_num(num)
+                elif kind == self.DESCR_REF:
+                    tgt = self.fail_boxes_ptr.get_addr_for_num(num)
+                elif kind == self.DESCR_FLOAT:
+                    tgt = self.fail_boxes_float.get_addr_for_num(num)
+                    rffi.cast(rffi.LONGP, tgt)[1] = value_hi
+                else:
+                    assert 0, "bogus kind"
+                rffi.cast(rffi.LONGP, tgt)[0] = value
+                num += 1
+            #
+            if not we_are_translated():
+                assert bytecode[4] == 0xCC
+            fail_index = rffi.cast(rffi.LONGP, bytecode)[0]
+            return fail_index
 
         self.failure_recovery_func = failure_recovery_func
-        self.failure_recovery_code = [0, 0]
+        self.failure_recovery_code = [0, 0, 0, 0]
 
     _FAILURE_RECOVERY_FUNC = lltype.Ptr(lltype.FuncType([rffi.LONGP],
                                                         lltype.Signed))
 
-    def _build_failure_recovery(self, exc):
+    def _build_failure_recovery(self, exc, withfloats=False):
         failure_recovery_func = llhelper(self._FAILURE_RECOVERY_FUNC,
                                          self.failure_recovery_func)
         failure_recovery_func = rffi.cast(lltype.Signed,
@@ -841,8 +914,13 @@
         mc.PUSH(ecx)
         mc.PUSH(eax)
         mc.MOV(eax, esp)
+        if withfloats:
+            mc.SUB(esp, imm(8*8))
+            for i in range(8):
+                mc.MOVSD(mem(esp, 8*i), xmm_registers[i])
         mc.PUSH(eax)
         mc.CALL(rel32(failure_recovery_func))
+        # returns in eax the fail_index
 
         # we call a provided function that will
         # - call our on_leave_jitted_hook which will mark
@@ -850,9 +928,9 @@
         #   avoid unwarranted freeing
         # - optionally save exception depending on the flag
         addr = self.cpu.get_on_leave_jitted_int(save_exception=exc)
-        mc.PUSH(eax)
+        mc.MOV(edi, eax)
         mc.CALL(rel32(addr))
-        mc.POP(eax)
+        mc.MOV(eax, edi)
 
         # now we return from the complete frame, which starts from
         # _assemble_bootstrap_code().  The LEA below throws away most
@@ -863,7 +941,7 @@
         mc.POP(ebx)
         mc.POP(ebp)
         mc.RET()
-        self.failure_recovery_code[exc] = addr
+        self.failure_recovery_code[exc + 2 * withfloats] = addr
 
     def generate_failure(self, mc, fail_index, locs, exc, locs_are_ref):
         for i in range(len(locs)):

Modified: pypy/branch/shorter-guard-path/pypy/jit/backend/x86/support.py
==============================================================================
--- pypy/branch/shorter-guard-path/pypy/jit/backend/x86/support.py	(original)
+++ pypy/branch/shorter-guard-path/pypy/jit/backend/x86/support.py	Fri Nov 20 17:23:51 2009
@@ -3,7 +3,8 @@
 from pypy.rlib import rgc
 from pypy.rlib.objectmodel import we_are_translated
 
-CHUNK_SIZE = 1000
+CHUNK_SIZE_BITS = 8
+CHUNK_SIZE = 1 << CHUNK_SIZE_BITS
 
 def new_nonmovable_growable_array(TP):
     ATP = lltype.GcArray(TP)
@@ -34,7 +35,7 @@
         def _no_of(self, i):
             while i >= len(self.chunks) * CHUNK_SIZE:
                 self._grow()
-            return i / CHUNK_SIZE, i % CHUNK_SIZE
+            return i >> CHUNK_SIZE_BITS, i & (CHUNK_SIZE-1)
         _no_of._always_inline_ = True
 
         def setitem(self, i, v):

Modified: pypy/branch/shorter-guard-path/pypy/jit/backend/x86/test/test_assembler.py
==============================================================================
--- pypy/branch/shorter-guard-path/pypy/jit/backend/x86/test/test_assembler.py	(original)
+++ pypy/branch/shorter-guard-path/pypy/jit/backend/x86/test/test_assembler.py	Fri Nov 20 17:23:51 2009
@@ -1,6 +1,6 @@
 from pypy.jit.backend.x86.ri386 import *
 from pypy.jit.backend.x86.assembler import Assembler386
-from pypy.jit.backend.x86.regalloc import X86StackManager
+from pypy.jit.backend.x86.regalloc import X86StackManager, get_ebp_ofs
 from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat
 from pypy.rlib.rarithmetic import intmask
 from pypy.rpython.lltypesystem import lltype, llmemory, rffi
@@ -8,6 +8,7 @@
 
 class FakeCPU:
     rtyper = None
+    supports_floats = True
 
 class FakeMC:
     def __init__(self):
@@ -46,7 +47,13 @@
     assert mc.content == (nums[:3] + double_byte_nums + nums[6:] +
                           [assembler.DESCR_STOP])
 
-def test_failure_recovery_func():
+def test_failure_recovery_func_no_floats():
+    do_failure_recovery_func(withfloats=False)
+
+def test_failure_recovery_func_with_floats():
+    do_failure_recovery_func(withfloats=True)
+
+def do_failure_recovery_func(withfloats):
     import random
     S = lltype.GcStruct('S')
 
@@ -57,7 +64,12 @@
         return lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(S))
 
     def get_random_float():
-        return random.random() - 0.5
+        assert withfloats
+        value = random.random() - 0.5
+        # make sure it fits into 64 bits
+        tmp = lltype.malloc(rffi.LONGP.TO, 2, flavor='raw')
+        rffi.cast(rffi.DOUBLEP, tmp)[0] = value
+        return rffi.cast(rffi.DOUBLEP, tmp)[0], tmp[0], tmp[1]
 
     # memory locations: 30 integers, 30 pointers, 26 floats
     # main registers: half of them as signed and the other half as ptrs
@@ -73,37 +85,43 @@
     random.shuffle(locations)
     content = ([('int', locations.pop()) for _ in range(30)] +
                [('ptr', locations.pop()) for _ in range(30)] +
-               [('float', locations.pop()) for _ in range(26)] +
                [(['int', 'ptr'][random.randrange(0, 2)], reg)
-                         for reg in [eax, ecx, edx, ebx, esi, edi]] +
-               [('float', reg) for reg in [xmm0, xmm1, xmm2, xmm3,
-                                           xmm4, xmm5, xmm6, xmm7]])
-    assert len(content) == 100
+                         for reg in [eax, ecx, edx, ebx, esi, edi]])
+    if withfloats:
+        content += ([('float', locations.pop()) for _ in range(26)] +
+                    [('float', reg) for reg in [xmm0, xmm1, xmm2, xmm3,
+                                                xmm4, xmm5, xmm6, xmm7]])
     random.shuffle(content)
 
     # prepare the expected target arrays, the descr_bytecode,
     # the 'registers' and the 'stack' arrays according to 'content'
-    registers = lltype.malloc(rffi.LONGP.TO, 9, flavor='raw')
-    xmmregisters = [0.0] * 8
-    stacklen = baseloc + 3
+    xmmregisters = lltype.malloc(rffi.LONGP.TO, 16+9, flavor='raw')
+    registers = rffi.ptradd(xmmregisters, 16)
+    stacklen = baseloc + 10
     stack = lltype.malloc(rffi.LONGP.TO, stacklen, flavor='raw')
-    expected_ints = [0] * 100
-    expected_ptrs = [lltype.nullptr(llmemory.GCREF.TO)] * 100
-    expected_floats = [0.0] * 100
+    expected_ints = [0] * len(content)
+    expected_ptrs = [lltype.nullptr(llmemory.GCREF.TO)] * len(content)
+    expected_floats = [0.0] * len(content)
+
+    def write_in_stack(loc, value):
+        assert loc >= 0
+        ofs = get_ebp_ofs(loc)
+        assert ofs < 0
+        assert (ofs % 4) == 0
+        stack[stacklen + ofs//4] = value
 
     descr_bytecode = []
     for i, (kind, loc) in enumerate(content):
         if kind == 'float':
-            value = get_random_float()
+            value, lo, hi = get_random_float()
             expected_floats[i] = value
             kind = Assembler386.DESCR_FLOAT
             if isinstance(loc, REG):
-                xmmregisters[loc.op] = value
+                xmmregisters[2*loc.op] = lo
+                xmmregisters[2*loc.op+1] = hi
             else:
-                tmp = lltype.malloc(rffi.LONGP.TO, 2, flavor='raw')
-                rffi.cast(rffi.DOUBLEP, tmp)[0] = value
-                stack[stacklen - loc] = tmp[1]
-                stack[stacklen - (loc+1)] = tmp[0]
+                write_in_stack(loc, hi)
+                write_in_stack(loc+1, lo)
         else:
             if kind == 'int':
                 value = get_random_int()
@@ -119,7 +137,7 @@
             if isinstance(loc, REG):
                 registers[loc.op] = value
             else:
-                stack[stacklen - loc] = value
+                write_in_stack(loc, value)
 
         if isinstance(loc, REG):
             num = kind + 4*loc.op
@@ -142,14 +160,21 @@
         assert 0 <= descr_bytecode[i] <= 255
         descr_bytes[i] = rffi.cast(rffi.UCHAR, descr_bytecode[i])
     registers[8] = rffi.cast(rffi.LONG, descr_bytes)
+    registers[ebp.op] = rffi.cast(rffi.LONG, stack) + 4*stacklen
 
     # run!
     assembler = Assembler386(FakeCPU())
+    assembler.fail_boxes_int.get_addr_for_num(len(content)-1)   # preallocate
+    assembler.fail_boxes_ptr.get_addr_for_num(len(content)-1)
+    assembler.fail_boxes_float.get_addr_for_num(len(content)-1)
     res = assembler.failure_recovery_func(registers)
     assert res == 0x1C3
 
     # check the fail_boxes
-    for i in range(100):
+    for i in range(len(content)):
         assert assembler.fail_boxes_int.getitem(i) == expected_ints[i]
         assert assembler.fail_boxes_ptr.getitem(i) == expected_ptrs[i]
+        # note: we expect *exact* results below.  If you have only
+        # an approximate result, it might mean that only the first 32
+        # bits of the float were correctly saved and restored.
         assert assembler.fail_boxes_float.getitem(i) == expected_floats[i]



More information about the Pypy-commit mailing list