[pypy-svn] r78248 - in pypy/branch/arm-backend/pypy/jit/backend/arm: . test

david at codespeak.net david at codespeak.net
Sun Oct 24 14:37:18 CEST 2010


Author: david
Date: Sun Oct 24 14:37:16 2010
New Revision: 78248

Modified:
   pypy/branch/arm-backend/pypy/jit/backend/arm/assembler.py
   pypy/branch/arm-backend/pypy/jit/backend/arm/codebuilder.py
   pypy/branch/arm-backend/pypy/jit/backend/arm/instructions.py
   pypy/branch/arm-backend/pypy/jit/backend/arm/runner.py
   pypy/branch/arm-backend/pypy/jit/backend/arm/test/support.py
   pypy/branch/arm-backend/pypy/jit/backend/arm/test/test_assembler.py
Log:
Refactor guards and finish res op to leave using common code.
Start implementig bridges based on refactored code.


Modified: pypy/branch/arm-backend/pypy/jit/backend/arm/assembler.py
==============================================================================
--- pypy/branch/arm-backend/pypy/jit/backend/arm/assembler.py	(original)
+++ pypy/branch/arm-backend/pypy/jit/backend/arm/assembler.py	Sun Oct 24 14:37:16 2010
@@ -1,11 +1,14 @@
-from pypy.jit.backend.arm.codebuilder import ARMv7Builder
-from pypy.jit.backend.arm import registers as r
 from pypy.jit.backend.arm import conditions as c
-from pypy.jit.backend.llsupport.regalloc import compute_vars_longevity
+from pypy.jit.backend.arm import registers as r
+from pypy.jit.backend.arm.arch import WORD, FUNC_ALIGN
+from pypy.jit.backend.arm.codebuilder import ARMv7Builder, ARMv7InMemoryBuilder
 from pypy.jit.backend.arm.regalloc import ARMRegisterManager
+from pypy.jit.backend.llsupport.regalloc import compute_vars_longevity
+from pypy.jit.metainterp.history import ConstInt, Box, BasicFailDescr
 from pypy.jit.metainterp.resoperation import rop
-from pypy.jit.metainterp.history import ConstInt, Box
-from pypy.rpython.lltypesystem import lltype
+from pypy.rlib import rgc
+from pypy.rpython.annlowlevel import llhelper
+from pypy.rpython.lltypesystem import lltype, rffi, llmemory
 # XXX Move to llsupport
 from pypy.jit.backend.x86.support import values_array
 
@@ -17,15 +20,132 @@
         self.cpu = cpu
         self.input_arg_boxes_int = values_array(lltype.Signed, failargs_limit) # merge with fail_boxes_int later
         self.fail_boxes_int = values_array(lltype.Signed, failargs_limit)
+        self._debug_asm = True
+
+        self._gen_exit_path()
+        self.align()
+        self.mc._start_addr = self.mc.curraddr()
+
+
+    def setup_failure_recovery(self):
+
+        @rgc.no_collect
+        def failure_recovery_func(mem_loc, stackloc):
+            """mem_loc is a structure in memory describing where the values for
+            the failargs are stored. stacklock is the address of the stack
+            section where the registers were saved."""
+            enc = rffi.cast(rffi.CCHARP, mem_loc)
+            stack = rffi.cast(rffi.CCHARP, stackloc)
+            return self.decode_registers_and_descr(enc, stack)
+
+        self.failure_recovery_func = failure_recovery_func
+
+    @rgc.no_collect
+    def decode_registers_and_descr(self, enc, stack):
+        """Decode locations encoded in memory at enc and write the values to
+        the failboxes.
+        Registers are saved on the stack
+        XXX Rest to follow"""
+        i = -1
+        while(True):
+            i += 1
+            r = enc[i]
+            if r == '\xFF':
+                break
+            reg = ord(enc[i])
+            self.fail_boxes_int.setitem(i, self.decode32(stack, reg*WORD))
+        assert enc[i] == '\xFF'
+        descr = self.decode32(enc, i+1)
+        return descr
+
+    def decode32(self, mem, index):
+        highval = ord(mem[index+3])
+        if highval >= 128:
+            highval -= 256
+        return (ord(mem[index])
+                | ord(mem[index+1]) << 8
+                | ord(mem[index+2]) << 16
+                | highval << 24)
+
+    def encode32(self, mem, i, n):
+        mem[i] = chr(n & 0xFF)
+        mem[i+1] = chr((n >> 8) & 0xFF)
+        mem[i+2] = chr((n >> 16) & 0xFF)
+        mem[i+3] = chr((n >> 24) & 0xFF)
+
+    def _gen_exit_path(self):
+        self.setup_failure_recovery()
+        functype = lltype.Ptr(lltype.FuncType([lltype.Signed, lltype.Signed], lltype.Signed))
+        decode_registers_addr = llhelper(functype, self.failure_recovery_func)
+        self.mc.PUSH(range(12))     # registers r0 .. r11
+        self.mc.MOV_rr(r.r0, r.lr)  # move mem block address, to r0 to pass as
+                                    # parameter to next procedure call
+        self.mc.MOV_rr(r.r1, r.sp)  # pass the current stack pointer as second param
+        self.mc.gen_load_int(r.r2, rffi.cast(lltype.Signed, decode_registers_addr))
+        self.mc.gen_load_int(r.lr, self.mc.curraddr()+self.mc.size_of_gen_load_int+WORD)
+        self.mc.MOV_rr(r.pc, r.r2)
+        self.mc.MOV_rr(r.ip, r.r0)
+        self.mc.LDM(r.sp, range(12), w=1) # XXX Replace with POP instr. someday
+
+        self.mc.MOV_rr(r.r0, r.ip)
+
+        self.gen_func_epilog()
+
+    def _gen_path_to_exit_path(self, op, args, regalloc, fcond=c.AL):
+        box = Box()
+        reg = regalloc.try_allocate_reg(box)
+        # XXX free this memory
+        mem = lltype.malloc(rffi.CArray(lltype.Char), len(args)+5, flavor='raw')
+        for i in range(len(args)):
+            curreg = regalloc.try_allocate_reg(args[i])
+            mem[i] = chr(curreg)
+        i = len(args)
+        mem[i] = chr(0xFF)
+        memaddr = rffi.cast(lltype.Signed, mem)
+
+
+        n = self.cpu.get_fail_descr_number(op.getdescr())
+        self.encode32(mem, i+1, n)
+        self.mc.gen_load_int(r.lr, memaddr, cond=fcond)
+        self.mc.gen_load_int(reg, self.mc.baseaddr(), cond=fcond)
+        self.mc.MOV_rr(r.pc, reg, cond=fcond)
+
+        op.getdescr()._arm_guard_reg = reg
+        return memaddr
+
+    def align(self):
+        while(self.mc.curraddr() % FUNC_ALIGN != 0):
+            self.mc.writechar(chr(0))
+
+    def gen_func_epilog(self,cond=c.AL):
+        self.mc.LDM(r.sp, r.callee_restored_registers, cond=cond, w=1)
+
+    def gen_func_prolog(self):
+        self.mc.PUSH(r.callee_saved_registers)
+
+    def gen_bootstrap_code(self, inputargs, regalloc):
+        for i in range(len(inputargs)):
+            reg = regalloc.try_allocate_reg(inputargs[i])
+            addr = self.fail_boxes_int.get_addr_for_num(i)
+            self.mc.gen_load_int(reg, addr)
+            self.mc.LDR_ri(reg, reg)
+
+    def gen_bridge_bootstrap_code(self, inputargs, regalloc):
+        for i in range(len(inputargs)):
+            reg = regalloc.try_allocate_reg(inputargs[i])
+            addr = self.fail_boxes_int.get_addr_for_num(i)
+            self.mc.gen_load_int(reg, addr)
+            self.mc.LDR_ri(reg, reg)
 
+    # cpu interface
     def assemble_loop(self, inputargs, operations, looptoken):
-        assert len(inputargs) == 1
         longevity = compute_vars_longevity(inputargs, operations)
         regalloc = ARMRegisterManager(longevity, assembler=self.mc)
+        loop_start=self.mc.curraddr()
         self.gen_func_prolog()
         self.gen_bootstrap_code(inputargs, regalloc)
         loop_head=self.mc.curraddr()
-        looptoken._arm_bootstrap_code = self.mc.baseaddr()
+        looptoken._arm_bootstrap_code = loop_start
         looptoken._arm_loop_code = loop_head
         looptoken._temp_inputargs = inputargs#XXX remove
         fcond=c.AL
@@ -33,12 +153,42 @@
             opnum = op.getopnum()
             fcond = self.operations[opnum](self, op, regalloc, fcond)
         self.gen_func_epilog()
-        f = open('loop.asm', 'wb')
-        for i in range(self.mc._pos):
-            f.write(self.mc._data[i])
-        f.close()
+        if self._debug_asm:
+            self._dump_trace('loop.asm')
         print 'Done assembling'
 
+    def assemble_bridge(self, faildescr, inputargs, operations):
+        # XXX need to restore args here
+        longevity = compute_vars_longevity(inputargs, operations)
+        regalloc = ARMRegisterManager(longevity, assembler=self.mc)
+        bridge_head = self.mc.curraddr()
+        self.gen_bridge_bootstrap_code(inputargs, regalloc)
+        fcond = c.AL
+        for op in operations:
+            opnum = op.getopnum()
+            fcond = self.operations[opnum](self, op, regalloc, fcond)
+        self.gen_func_epilog()
+        print 'Done building bridges'
+        self.patch_trace(faildescr, bridge_head)
+        print 'Done patching trace'
+        if self._debug_asm:
+            self._dump_trace('bridge.asm')
+
+
+    def _dump_trace(self, name):
+        self.mc._dump_trace(name)
+
+    def patch_trace(self, faildescr, bridge_addr):
+        # XXX make sure there is enough space at patch target
+        fcond = faildescr._arm_guard_cond
+        b = ARMv7InMemoryBuilder(faildescr._arm_guard_code, faildescr._arm_guard_code+100)
+        reg = faildescr._arm_guard_reg
+        b.gen_load_int(reg, bridge_addr, fcond)
+        b.MOV_rr(r.pc, reg, cond=fcond)
+
+
+    # Resoperations
+
     def emit_op_jump(self, op, regalloc, fcond):
         tmp = Box()
         tmpreg = regalloc.try_allocate_reg(tmp)
@@ -49,13 +199,13 @@
             # XXX only if every value is in a register
             self.mc.MOV_rr(inpreg, reg)
         loop_code = op.getdescr()._arm_loop_code
-        self.gen_load_int(tmpreg, loop_code)
+        self.mc.gen_load_int(tmpreg, loop_code)
         self.mc.MOV_rr(r.pc, tmpreg)
         regalloc.possibly_free_var(tmpreg)
         return fcond
 
     def emit_op_finish(self, op, regalloc, fcond):
-        self.gen_write_back(op, op.getarglist(), regalloc, fcond)
+        self._gen_path_to_exit_path(op, op.getarglist(), regalloc, fcond)
         return fcond
 
     def emit_op_int_le(self, op, regalloc, fcond):
@@ -74,46 +224,14 @@
 
     def emit_op_guard_true(self, op, regalloc, fcond):
         assert fcond == c.GT
-        self.gen_write_back(op, op.getfailargs(), regalloc, fcond)
-        self.gen_func_epilog(cond=fcond)
+        descr = op.getdescr()
+        assert isinstance(descr, BasicFailDescr)
+        memaddr = self._gen_path_to_exit_path(op, op.getfailargs(), regalloc, fcond)
+        descr._failure_recovery_code = memaddr
+        descr._arm_guard_code = self.mc.curraddr()
+        descr._arm_guard_cond = fcond
         return c.AL
 
-    def gen_write_back(self, op, args, regalloc, fcond):
-        temp = Box()
-        temp_reg = regalloc.try_allocate_reg(temp)
-        for i in range(len(args)):
-            reg = regalloc.try_allocate_reg(args[i])
-            addr = self.fail_boxes_int.get_addr_for_num(i)
-            self.gen_load_int(temp_reg, addr, cond=fcond)
-            self.mc.STR_ri(reg, temp_reg, cond=fcond)
-
-        regalloc.possibly_free_var(temp_reg)
-        n = self.cpu.get_fail_descr_number(op.getdescr())
-        self.mc.MOV_ri(r.r0, n, cond=fcond)
-
-    def gen_func_epilog(self,cond=c.AL):
-        self.mc.LDM(r.sp, r.callee_restored_registers, cond=cond)
-
-    def gen_func_prolog(self):
-        self.mc.PUSH(r.callee_saved_registers)
-
-    def gen_bootstrap_code(self, inputargs, regalloc):
-        for i in range(len(inputargs)):
-            reg = regalloc.try_allocate_reg(inputargs[i])
-            addr = self.input_arg_boxes_int.get_addr_for_num(i)
-            self.gen_load_int(reg, addr)
-            self.mc.LDR_ri(reg, reg)
-
-    def gen_load_int(self, reg, value, cond=c.AL):
-        assert reg != r.ip, 'ip is used to load int'
-        self.mc.MOV_ri(reg, (value & 0xFF), cond=cond)
-
-        for offset in range(8, 25, 8):
-            self.mc.MOV_ri(r.ip, (value >> offset) & 0xFF, cond=cond)
-            self.mc.ORR_rr(reg, reg, r.ip, offset, cond=cond)
-
-
-
 def make_operation_list():
     def notimplemented(self, op, regalloc, fcond):
         raise NotImplementedError

Modified: pypy/branch/arm-backend/pypy/jit/backend/arm/codebuilder.py
==============================================================================
--- pypy/branch/arm-backend/pypy/jit/backend/arm/codebuilder.py	(original)
+++ pypy/branch/arm-backend/pypy/jit/backend/arm/codebuilder.py	Sun Oct 24 14:37:16 2010
@@ -1,22 +1,29 @@
-import conditions as cond
-import registers as reg
-from pypy.rlib.rmmap import alloc
-from pypy.rpython.lltypesystem import lltype, rffi
+from pypy.jit.backend.arm import conditions as cond
+from pypy.jit.backend.arm import registers as reg
+from pypy.jit.backend.arm.arch import WORD
 from pypy.jit.backend.arm.instruction_builder import define_instructions
 
-class ARMv7Builder(object):
+from pypy.rlib.rmmap import alloc, PTR
+from pypy.rpython.lltypesystem import lltype, rffi
 
-    def __init__(self):
-        self._data = alloc(1024)
+class AbstractARMv7Builder(object):
+    def _init(self, data, map_size):
+        self._data = data
+        self._size = map_size
         self._pos = 0
 
+    def _dump_trace(self, name):
+        f = open('output/%s' % name, 'wb')
+        for i in range(self._pos):
+            f.write(self._data[i])
+        f.close()
+
     def PUSH(self, regs, cond=cond.AL):
         assert reg.sp not in regs
         instr = self._encode_reg_list(cond << 28 | 0x92D << 16, regs)
         self.write32(instr)
 
-    def LDM(self, rn, regs, cond=cond.AL):
-        w = 0
+    def LDM(self, rn, regs, w=0, cond=cond.AL):
         instr = cond << 28 | 0x89 << 20 | w << 21 | (rn & 0xFF) << 16
         instr = self._encode_reg_list(instr, regs)
         self.write32(instr)
@@ -58,4 +65,30 @@
     def curraddr(self):
         return self.baseaddr() + self._pos
 
-define_instructions(ARMv7Builder)
+    size_of_gen_load_int = 7 * WORD
+    def gen_load_int(self, r, value, cond=cond.AL):
+        assert r != reg.ip, 'ip is used to load int'
+        self.MOV_ri(r, (value & 0xFF), cond=cond)
+
+        for offset in range(8, 25, 8):
+            t = (value >> offset) & 0xFF
+            #if t == 0:
+            #    continue
+            self.MOV_ri(reg.ip, t, cond=cond)
+            self.ORR_rr(r, r, reg.ip, offset, cond=cond)
+
+class ARMv7InMemoryBuilder(AbstractARMv7Builder):
+    def __init__(self, start, end):
+        map_size = end - start
+        data = rffi.cast(PTR, start)
+        self._init(data, map_size)
+
+class ARMv7Builder(AbstractARMv7Builder):
+
+    def __init__(self):
+        map_size = 1024
+        data = alloc(1024)
+        self._pos = 0
+        self._init(data, map_size)
+
+define_instructions(AbstractARMv7Builder)

Modified: pypy/branch/arm-backend/pypy/jit/backend/arm/instructions.py
==============================================================================
--- pypy/branch/arm-backend/pypy/jit/backend/arm/instructions.py	(original)
+++ pypy/branch/arm-backend/pypy/jit/backend/arm/instructions.py	Sun Oct 24 14:37:16 2010
@@ -56,3 +56,18 @@
 supervisor_and_coproc = {
     'MCR': {'op1': 0x20, 'op': 1, 'rn':0, 'coproc':0},
 }
+
+block_data = {
+    'STMDA': {'op': 0x0},
+    'LDMDA': {'op': 0x1},
+    'STMIA': {'op': 0x8},
+    'LDMDB': {'op': 0x11},
+    'STMIB': {'op': 0x18},
+    'LDMIB': {'op': 0x19},
+    'STM':   {'op': 0x4},
+    'LDM':   {'op': 0x5},
+}
+branch = {
+    'B':     {'op': 0x20},
+    'BL':    {'op': 0x30},
+}

Modified: pypy/branch/arm-backend/pypy/jit/backend/arm/runner.py
==============================================================================
--- pypy/branch/arm-backend/pypy/jit/backend/arm/runner.py	(original)
+++ pypy/branch/arm-backend/pypy/jit/backend/arm/runner.py	Sun Oct 24 14:37:16 2010
@@ -18,6 +18,9 @@
     def compile_loop(self, inputargs, operations, looptoken):
         self.assembler.assemble_loop(inputargs, operations, looptoken)
 
+    def compile_bridge(self, faildescr, inputargs, operations):
+        self.assembler.assemble_bridge(faildescr, inputargs, operations)
+
     def set_future_value_int(self, index, intvalue):
         self.assembler.input_arg_boxes_int.setitem(index, intvalue)
 

Modified: pypy/branch/arm-backend/pypy/jit/backend/arm/test/support.py
==============================================================================
--- pypy/branch/arm-backend/pypy/jit/backend/arm/test/support.py	(original)
+++ pypy/branch/arm-backend/pypy/jit/backend/arm/test/support.py	Sun Oct 24 14:37:16 2010
@@ -10,7 +10,7 @@
 
 def run_asm(asm):
     BOOTSTRAP_TP = lltype.FuncType([], lltype.Signed)
-    addr = asm.mc.baseaddr()
+    addr = asm.mc._start_addr
     assert addr % 8 == 0
     func = rffi.cast(lltype.Ptr(BOOTSTRAP_TP), addr)
     return func()

Modified: pypy/branch/arm-backend/pypy/jit/backend/arm/test/test_assembler.py
==============================================================================
--- pypy/branch/arm-backend/pypy/jit/backend/arm/test/test_assembler.py	(original)
+++ pypy/branch/arm-backend/pypy/jit/backend/arm/test/test_assembler.py	Sun Oct 24 14:37:16 2010
@@ -1,9 +1,14 @@
-from pypy.jit.backend.arm import registers as r
 from pypy.jit.backend.arm import conditions as c
+from pypy.jit.backend.arm import registers as r
+from pypy.jit.backend.arm.arch import WORD
 from pypy.jit.backend.arm.assembler import AssemblerARM
+from pypy.jit.backend.arm.codebuilder import ARMv7InMemoryBuilder
 from pypy.jit.backend.arm.test.support import skip_unless_arm, run_asm
 from pypy.jit.metainterp.resoperation import rop
 
+from pypy.rpython.annlowlevel import llhelper
+from pypy.rpython.lltypesystem import lltype, rffi, llmemory
+
 skip_unless_arm()
 
 class TestRunningAssembler():
@@ -16,19 +21,19 @@
 
     def test_load_small_int_to_reg(self):
         self.a.gen_func_prolog()
-        self.a.gen_load_int(r.r0, 123)
+        self.a.mc.gen_load_int(r.r0, 123)
         self.a.gen_func_epilog()
         assert run_asm(self.a) == 123
 
     def test_load_medium_int_to_reg(self):
         self.a.gen_func_prolog()
-        self.a.gen_load_int(r.r0, 0xBBD7)
+        self.a.mc.gen_load_int(r.r0, 0xBBD7)
         self.a.gen_func_epilog()
         assert run_asm(self.a) == 48087
 
     def test_load_int_to_reg(self):
         self.a.gen_func_prolog()
-        self.a.gen_load_int(r.r0, 0xFFFFFF85)
+        self.a.mc.gen_load_int(r.r0, 0xFFFFFF85)
         self.a.gen_func_epilog()
         assert run_asm(self.a) == -123
 
@@ -43,14 +48,14 @@
 
     def test_sub(self):
         self.a.gen_func_prolog()
-        self.a.gen_load_int(r.r1, 123456)
+        self.a.mc.gen_load_int(r.r1, 123456)
         self.a.mc.SUB_ri(r.r0, r.r1, 123)
         self.a.gen_func_epilog()
         assert run_asm(self.a) == 123333
 
     def test_cmp(self):
         self.a.gen_func_prolog()
-        self.a.gen_load_int(r.r1, 22)
+        self.a.mc.gen_load_int(r.r1, 22)
         self.a.mc.CMP(r.r1, 123)
         self.a.mc.MOV_ri(r.r0, 1, c.LE)
         self.a.mc.MOV_ri(r.r0, 0, c.GT)
@@ -59,7 +64,7 @@
 
     def test_int_le_false(self):
         self.a.gen_func_prolog()
-        self.a.gen_load_int(r.r1, 2222)
+        self.a.mc.gen_load_int(r.r1, 2222)
         self.a.mc.CMP(r.r1, 123)
         self.a.mc.MOV_ri(r.r0, 1, c.LE)
         self.a.mc.MOV_ri(r.r0, 0, c.GT)
@@ -73,7 +78,7 @@
         self.a.mc.CMP(r.r1, 0) # z=0, z=1
         self.a.mc.MOV_ri(r.r1, 0, cond=c.NE)
         self.a.mc.MOV_ri(r.r1, 7, cond=c.EQ)
-        self.a.gen_load_int(r.r4, loop_head, cond=c.NE)
+        self.a.mc.gen_load_int(r.r4, loop_head, cond=c.NE)
         self.a.mc.MOV_rr(r.pc, r.r4, cond=c.NE)
         self.a.mc.MOV_rr(r.r0, r.r1)
         self.a.gen_func_epilog()
@@ -85,10 +90,25 @@
         loop_head = self.a.mc.curraddr()
         self.a.mc.ADD_ri(r.r1, r.r1, 1)
         self.a.mc.CMP(r.r1, 9)
-        self.a.gen_load_int(r.r4, loop_head, cond=c.NE)
+        self.a.mc.gen_load_int(r.r4, loop_head, cond=c.NE)
         self.a.mc.MOV_rr(r.pc, r.r4, cond=c.NE)
         self.a.mc.MOV_rr(r.r0, r.r1)
         self.a.gen_func_epilog()
         assert run_asm(self.a) == 9
 
 
+    def test_call_python_func(self):
+        functype = lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Signed))
+        call_addr = rffi.cast(lltype.Signed, llhelper(functype, callme))
+        self.a.gen_func_prolog()
+        self.a.mc.MOV_ri(r.r0, 123)
+        self.a.mc.gen_load_int(r.r1, call_addr)
+        self.a.mc.gen_load_int(r.lr, self.a.mc.curraddr()+self.a.mc.size_of_gen_load_int+WORD)
+        self.a.mc.MOV_rr(r.pc, r.r1)
+        self.a.gen_func_epilog()
+        assert run_asm(self.a) == 133
+
+def callme(inp):
+    i = inp + 10
+    return i
+



More information about the Pypy-commit mailing list