[pypy-commit] pypy guard-compatible: Finish guard_compatible in the x86 backend (as far as test_runner goes)

arigo pypy.commits at gmail.com
Mon Mar 14 06:14:57 EDT 2016


Author: Armin Rigo <arigo at tunes.org>
Branch: guard-compatible
Changeset: r83030:a4934822ebc2
Date: 2016-03-14 11:14 +0100
http://bitbucket.org/pypy/pypy/changeset/a4934822ebc2/

Log:	Finish guard_compatible in the x86 backend (as far as test_runner
	goes)

diff --git a/rpython/jit/backend/llgraph/runner.py b/rpython/jit/backend/llgraph/runner.py
--- a/rpython/jit/backend/llgraph/runner.py
+++ b/rpython/jit/backend/llgraph/runner.py
@@ -470,7 +470,7 @@
         assert deadframe._saved_data is not None
         return deadframe._saved_data
 
-    def grow_guard_compatible_switch(self, descr, ref):
+    def grow_guard_compatible_switch(self, looptoken, descr, ref):
         if not hasattr(descr, '_guard_compatible_llgraph_lst'):
             descr._guard_compatible_llgraph_lst = []
         descr._guard_compatible_llgraph_lst.append(ref)
diff --git a/rpython/jit/backend/llsupport/assembler.py b/rpython/jit/backend/llsupport/assembler.py
--- a/rpython/jit/backend/llsupport/assembler.py
+++ b/rpython/jit/backend/llsupport/assembler.py
@@ -36,6 +36,9 @@
     def guard_not_invalidated(self):
         return self.guard_opnum == rop.GUARD_NOT_INVALIDATED
 
+    def guard_compatible(self):
+        return self.guard_opnum == rop.GUARD_COMPATIBLE
+
     def must_save_exception(self):
         guard_opnum = self.guard_opnum
         return (guard_opnum == rop.GUARD_EXCEPTION or
diff --git a/rpython/jit/backend/model.py b/rpython/jit/backend/model.py
--- a/rpython/jit/backend/model.py
+++ b/rpython/jit/backend/model.py
@@ -158,7 +158,7 @@
         """
         pass
 
-    def grow_guard_compatible_switch(self, guarddescr, gcref):
+    def grow_guard_compatible_switch(self, looptoken, guarddescr, gcref):
         """ This method is called to add another case to a guard_compatible.
         guard_compatible starts like a guard_value, but can grow to check more
         cases. The guard should only fail if the argument is unequal to all the
diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py
--- a/rpython/jit/backend/test/runner_test.py
+++ b/rpython/jit/backend/test/runner_test.py
@@ -214,7 +214,8 @@
         fail = self.cpu.get_latest_descr(deadframe)
         assert fail.identifier == 1
 
-        self.cpu.grow_guard_compatible_switch(faildescr1, t2_box._resref)
+        self.cpu.grow_guard_compatible_switch(looptoken, faildescr1,
+                                              t2_box._resref)
         for retry in range(2):
             deadframe = self.cpu.execute_token(looptoken,
                                                t2_box._resref)
diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py
--- a/rpython/jit/backend/x86/assembler.py
+++ b/rpython/jit/backend/x86/assembler.py
@@ -687,6 +687,8 @@
                 mc = codebuf.MachineCodeBlockWrapper()
                 mc.writeimm32(relative_target)
                 mc.copy_to_raw_memory(addr)
+                if tok.guard_compatible():
+                    guard_compat.patch_guard_compatible(rawstart, tok)
             else:
                 # GUARD_NOT_INVALIDATED, record an entry in
                 # clt.invalidate_positions of the form:
@@ -772,7 +774,8 @@
         mc.writeimm32(allocated_depth)
         mc.copy_to_raw_memory(adr)
 
-    def get_asmmemmgr_blocks(self, looptoken):
+    @staticmethod
+    def get_asmmemmgr_blocks(looptoken):
         clt = looptoken.compiled_loop_token
         if clt.asmmemmgr_blocks is None:
             clt.asmmemmgr_blocks = []
diff --git a/rpython/jit/backend/x86/guard_compat.py b/rpython/jit/backend/x86/guard_compat.py
--- a/rpython/jit/backend/x86/guard_compat.py
+++ b/rpython/jit/backend/x86/guard_compat.py
@@ -1,11 +1,18 @@
-from rpython.rtyper.lltypesystem import rffi
+from rpython.rlib import rgc
+from rpython.rlib.objectmodel import we_are_translated
+from rpython.rtyper.lltypesystem import lltype, rffi
 from rpython.jit.backend.x86.arch import WORD
 from rpython.jit.backend.x86 import rx86, codebuf
 from rpython.jit.backend.x86.regloc import X86_64_SCRATCH_REG, imm
+from rpython.jit.backend.llsupport.asmmemmgr import MachineDataBlockWrapper
+from rpython.jit.metainterp.compile import GuardCompatibleDescr
+from rpython.jit.metainterp.history import BasicFailDescr
+
 
 # uses the raw structure COMPATINFO, which is informally defined like this:
-# it is an array containing all the expected values that should pass the
-# guard, terminated with a small_ofs value ( < 128, see in code).
+# it starts with a negative 'small_ofs' value (see in the code)
+# then there is an array containing all the expected values that should pass
+# the guard, ending in -1.
 
 
 def generate_guard_compatible(assembler, guard_token, loc_reg, initial_value):
@@ -22,18 +29,19 @@
 
     # initialize 'compatinfo' with only 'initial_value' in it
     compatinfoaddr = assembler.datablockwrapper.malloc_aligned(
-        2 * WORD, alignment=WORD)
+        3 * WORD, alignment=WORD)
     compatinfo = rffi.cast(rffi.SIGNEDP, compatinfoaddr)
-    compatinfo[0] = initial_value
+    compatinfo[1] = initial_value
+    compatinfo[2] = -1
 
     mc.MOV_ri64(X86_64_SCRATCH_REG.value, compatinfoaddr)  # patchable
+    guard_token.pos_compatinfo_offset = mc.get_relative_pos() - WORD
     mc.PUSH_r(X86_64_SCRATCH_REG.value)
     mc.CALL(imm(checker))
     mc.stack_frame_size_delta(-WORD)
 
-    small_ofs = mc.get_relative_pos() - rel_pos_compatible_imm
-    assert 0 <= small_ofs <= 127
-    compatinfo[1] = small_ofs
+    small_ofs = rel_pos_compatible_imm - mc.get_relative_pos()
+    compatinfo[0] = small_ofs
 
     assembler.guard_success_cc = rx86.Conditions['NZ']
     assembler.implement_guard(guard_token)
@@ -44,6 +52,54 @@
     mc.overwrite(je_location-1, chr(offset))
 
 
+def patch_guard_compatible(rawstart, tok):
+    descr = tok.faildescr
+    if not we_are_translated() and isinstance(descr, BasicFailDescr):
+        pass    # for tests
+    else:
+        assert isinstance(descr, GuardCompatibleDescr)
+    descr._backend_compatinfo = rawstart + tok.pos_compatinfo_offset
+
+
+def grow_switch(cpu, looptoken, guarddescr, gcref):
+    from rpython.jit.backend.x86.assembler import Assembler386
+
+    # XXX is it ok to force gcref to be non-movable?
+    if not rgc._make_sure_does_not_move(gcref):
+        raise AssertionError("oops")
+    new_value = rffi.cast(lltype.Signed, gcref)
+
+    if not we_are_translated() and isinstance(guarddescr, BasicFailDescr):
+        pass    # for tests
+    else:
+        assert isinstance(guarddescr, GuardCompatibleDescr)
+    compatinfop = rffi.cast(rffi.VOIDPP, guarddescr._backend_compatinfo)
+    compatinfo = rffi.cast(rffi.SIGNEDP, compatinfop[0])
+    length = 3
+    while compatinfo[length - 1] != -1:
+        length += 1
+
+    allblocks = Assembler386.get_asmmemmgr_blocks(looptoken)
+    datablockwrapper = MachineDataBlockWrapper(cpu.asmmemmgr, allblocks)
+    newcompatinfoaddr = datablockwrapper.malloc_aligned(
+        (length + 1) * WORD, alignment=WORD)
+    datablockwrapper.done()
+
+    newcompatinfo = rffi.cast(rffi.SIGNEDP, newcompatinfoaddr)
+    newcompatinfo[0] = compatinfo[0]
+    newcompatinfo[1] = new_value
+
+    for i in range(1, length):
+        newcompatinfo[i + 1] = compatinfo[i]
+
+    # the old 'compatinfo' is not used any more, but will only be freed
+    # when the looptoken is freed
+    compatinfop[0] = rffi.cast(rffi.VOIDP, newcompatinfo)
+
+    # the machine code is not updated here.  We leave it to the actual
+    # guard_compatible to update it if needed.
+
+
 def setup_once(assembler):
     nb_registers = WORD * 2
     assembler._guard_compat_checkers = [0] * nb_registers
@@ -62,15 +118,15 @@
     mc.MOV_rs(X86_64_SCRATCH_REG.value, WORD)
 
     pos = mc.get_relative_pos()
-    mc.CMP_mr((X86_64_SCRATCH_REG.value, 0), regnum)
+    mc.CMP_mr((X86_64_SCRATCH_REG.value, WORD), regnum)
     mc.J_il8(rx86.Conditions['E'], 0)    # patched below
     je_location = mc.get_relative_pos()
-    mc.ADD_ri(X86_64_SCRATCH_REG.value, WORD)
-    mc.CMP_mi((X86_64_SCRATCH_REG.value, 0), 127)
-    mc.J_il8(rx86.Conditions['NBE'], pos - (mc.get_relative_pos() + 2))
+    mc.CMP_mi((X86_64_SCRATCH_REG.value, WORD), -1)
+    mc.LEA_rm(X86_64_SCRATCH_REG.value, (X86_64_SCRATCH_REG.value, WORD))
+    mc.J_il8(rx86.Conditions['NE'], pos - (mc.get_relative_pos() + 2))
 
-    # not found!  Return the condition code 'Zero' to mean 'not found'.
-    mc.CMP_rr(regnum, regnum)
+    # not found!  The condition code is already 'Zero', which we return
+    # to mean 'not found'.
     mc.RET16_i(WORD)
 
     mc.force_frame_size(WORD)
@@ -83,7 +139,9 @@
     # found!  update the assembler by writing the value at 'small_ofs'
     # bytes before our return address.  This should overwrite the const in
     # 'MOV_ri64(r11, const)', first instruction of the guard_compatible.
-    mc.NEG_r(X86_64_SCRATCH_REG.value)
+    mc.INT3()
+    mc.MOV_rs(X86_64_SCRATCH_REG.value, WORD)
+    mc.MOV_rm(X86_64_SCRATCH_REG.value, (X86_64_SCRATCH_REG.value, 0))
     mc.ADD_rs(X86_64_SCRATCH_REG.value, 0)
     mc.MOV_mr((X86_64_SCRATCH_REG.value, -WORD), regnum)
 
diff --git a/rpython/jit/backend/x86/runner.py b/rpython/jit/backend/x86/runner.py
--- a/rpython/jit/backend/x86/runner.py
+++ b/rpython/jit/backend/x86/runner.py
@@ -6,7 +6,7 @@
 from rpython.jit.backend.x86.regalloc import gpr_reg_mgr_cls, xmm_reg_mgr_cls
 from rpython.jit.backend.x86.profagent import ProfileAgent
 from rpython.jit.backend.llsupport.llmodel import AbstractLLCPU
-from rpython.jit.backend.x86 import regloc
+from rpython.jit.backend.x86 import regloc, guard_compat
 
 import sys
 
@@ -122,8 +122,8 @@
             l[i].counter = ll_s.i
         return l
 
-    def grow_guard_compatible_switch(self, guarddescr, gcref):
-        pass#xxx
+    def grow_guard_compatible_switch(self, looptoken, guarddescr, gcref):
+        guard_compat.grow_switch(self, looptoken, guarddescr, gcref)
 
 
 class CPU386(AbstractX86CPU):


More information about the pypy-commit mailing list