Author: Armin Rigo <[email protected]>
Branch: guard-compatible
Changeset: r84661:3228234de60c
Date: 2016-05-24 18:32 +0200
http://bitbucket.org/pypy/pypy/changeset/3228234de60c/

Log:    ppc support for guard_compatible (in-progress)

diff --git a/rpython/jit/backend/ppc/guard_compat.py 
b/rpython/jit/backend/ppc/guard_compat.py
new file mode 100644
--- /dev/null
+++ b/rpython/jit/backend/ppc/guard_compat.py
@@ -0,0 +1,144 @@
+from rpython.rtyper.annlowlevel import llhelper
+import rpython.jit.backend.ppc.register as r
+from rpython.jit.backend.ppc.arch import WORD, PARAM_SAVE_AREA_OFFSET
+from rpython.jit.backend.ppc.codebuilder import PPCBuilder, OverwritingBuilder
+
+from rpython.jit.backend.llsupport.guard_compat import *
+from rpython.jit.backend.llsupport.guard_compat import _real_number
+
+
+# See comments in ../x86/guard_compat.py.
+
+
+MANAGED_REGS_WITHOUT_R7_AND_R10 = list(r.MANAGED_REGS)
+MANAGED_REGS_WITHOUT_R7_AND_R10.remove(r.r7)
+MANAGED_REGS_WITHOUT_R7_AND_R10.remove(r.r10)
+
+
+def build_once(assembler):
+    """Generate the 'search_tree' block of code"""
+    # called with r2 containing the BACKEND_CHOICES object,
+    # and r0 containing the actual value of the guard
+
+    mc = PPCBuilder()
+    r7 = r.r7
+    r10 = r.r10
+
+    # save the values of r7 and r10 in the jitframe
+    assembler._push_core_regs_to_jitframe(mc, [r7, r10])
+
+    # save the original value of r2 for later
+    mc.std(r2.value, r.SP.value, PARAM_SAVE_AREA_OFFSET)
+
+    ofs1 = _real_number(BCLIST + BCLISTLENGTHOFS)
+    ofs2 = _real_number(BCLIST + BCLISTITEMSOFS)
+    mc.ld(r10.value, r2.value, ofs1)        # ld  r10, [r2 + bc_list.length]
+    mc.addi(r2.value, r2.value, ofs2 - 8)   # add r2, r2, $bc_list.items - 8
+    mc.sldi(r10.value, r10.value, 3)        # sldi r10, r10, 3
+    b_location = mc.get_relative_pos()
+    mc.trap()                               # b loop
+
+    right_label = mc.get_relative_pos()
+    mc.add(r2.value, r2.value, r10.value)   # add r2, r2, r10
+    mc.addi(r2.value, r2.value, WORD)       # addi r2, r2, 8
+    left_label = mc.get_relative_pos()
+    mc.srdi(r10.value, r10.value, 1)        # srdi r10, r10, 1
+    mc.cmp_op(0, r10.value, 8, imm=True)    # cmp r10, 8
+    blt_location = mc.get_relative_pos()
+    mc.trap()                               # beq not_found
+    #                                     loop:
+    pmc = OverwritingBuilder(mc, b_location, 1)
+    pmc.b(mc.currpos() - b_location)        # jump here unconditionally
+    pmc.overwrite()
+    mc.ldx(r7.value, r2.value, r10.value)   # ldx r7, [r2 + r10]
+    mc.cmp_op(0, r0.value, r7.value,
+              signed=False)                 # cmp r0, r7
+    mc.bgt(right_label - mc.currpos())      # bgt right_label
+    mc.bne(left_label - mc.currpos())       # bne left_label
+
+    #                                     found:
+    mc.add(r2.value, r2.value, r10.value)   # add r2, r2, r10
+    mc.ld(r10.value, r2.value, 8)           # ld r10, [r2 + 8]
+
+    # restore the value of r2 from the stack
+    mc.ld(r2.value, r.SP.value, PARAM_SAVE_AREA_OFFSET)    # ld r2, [sp + ..]
+
+    ofs = _real_number(BCMOSTRECENT)
+    mc.std(r0.value, r2.value, ofs)         # std r0, [r2 + bc_most_recent]
+    mc.std(r10.value, r2.value, ofs + WORD) # std r0, [r2 + bc_most_recent + 8]
+    mc.mtctr(r10.value)
+
+    # restore the values of r7 and r10 from the jitframe
+    assembler._pop_core_regs_from_jitframe(mc, [r7, r10])
+
+    mc.bctr()                               # jump to the old r10
+
+    # ----------
+
+    #                                     not_found:
+    pmc = OverwritingBuilder(mc, blt_location, 1)
+    pmc.blt(mc.currpos() - blt_location)    # jump here if r10 < 8
+    pmc.overwrite()
+
+    # save all other registers to the jitframe SPP, in addition to
+    # r7 and r10 which have already been saved
+    assembler._push_core_regs_to_jitframe(mc, MANAGED_REGS_WITHOUT_R7_AND_R10)
+    assembler._push_fp_regs_to_jitframe(mc)
+
+    # arg #1 (r3): the BACKEND_CHOICES objects, from the original value of r2
+    # arg #2 (r4): the actual value of the guard, from r0
+    # arg #3 (r5): the jitframe
+    mc.ld(r3.value, r.SP.value, PARAM_SAVE_AREA_OFFSET)    # ld r3, [sp + ..]
+    mc.mr(r4.value, r0.value)
+    mc.mr(r5.value, r.SPP.value)
+
+    invoke_find_compatible = make_invoke_find_compatible(assembler.cpu)
+    llfunc = llhelper(INVOKE_FIND_COMPATIBLE_FUNC, invoke_find_compatible)
+    llfunc = assembler.cpu.cast_ptr_to_int(llfunc)
+    assembler.load_imm(mc.RAW_CALL_REG, llfunc)
+    mc.raw_call()                           # mtctr / bctrl
+    assembler._reload_frame_if_necessary(mc)
+    mc.mtctr(r3.value)                      # mtctr r3
+
+    # restore the registers that the CALL has clobbered, plus the ones
+    # containing GC pointers that may have moved.  That means we just
+    # restore them all.
+    assembler._pop_core_regs_from_jitframe(mc)
+    assembler._pop_fp_regs_to_jitframe(mc)
+
+    mc.bctr()                               # jump to the old r3
+
+    assembler.guard_compat_search_tree = mc.materialize(assembler.cpu, [])
+
+
+def generate_guard_compatible(assembler, token, l0, bindex):
+    mc = assembler.mc
+    r0 = r.SCRATCH
+    r2 = r.SCRATCH2
+
+    assembler._load_from_gc_table(r2, r2, bindex)  # ld r2, [gc tbl at bindex]
+
+    ofs = _real_number(BCMOSTRECENT)
+    mc.ld(r0.value, r2.value, ofs)          # ld r0, [r2 + bc_most_recent]
+    mc.cmp_op(0, l0.value, r0.value)        # cmp l0, r0
+
+    bne_location = mc.get_relative_pos()
+    mc.trap()                               # patched later to a 'bc'
+
+    mc.ld(r2.value, r2.value, ofs + WORD)   # ld r2, [r2 + bc_most_recent + 8]
+    mc.mtctr(r2.value)
+    mc.bctr()                               # jump to r2
+
+    #                                     slowpath:
+    pmc = OverwritingBuilder(mc, bne_location, 1)
+    pmc.bne(mc.currpos() - bne_location)    # jump here if l0 != r0
+    pmc.overwrite()
+
+    assembler.load_imm(r0, assembler.guard_compat_search_tree)
+    mc.mtctr(r0.value)
+    mc.mr(r0.value, l0.value)
+    mc.bctr()
+
+    # abuse this field to store the 'sequel' relative offset
+    guard_token.pos_jump_offset = mc.get_relative_pos()
+    guard_token.guard_compat_bindex = bindex
diff --git a/rpython/jit/backend/ppc/opassembler.py 
b/rpython/jit/backend/ppc/opassembler.py
--- a/rpython/jit/backend/ppc/opassembler.py
+++ b/rpython/jit/backend/ppc/opassembler.py
@@ -273,8 +273,9 @@
 
     _mixin_ = True
 
-    def _emit_guard(self, op, arglocs, is_guard_not_invalidated=False):
-        if is_guard_not_invalidated:
+    def _emit_guard(self, op, arglocs, is_guard_not_invalidated=False,
+                    is_guard_compatible=False):
+        if is_guard_not_invalidated or is_guard_compatible:
             fcond = c.cond_none
         else:
             fcond = self.guard_success_cc
@@ -284,9 +285,11 @@
         token = self.build_guard_token(op, arglocs[0].value, arglocs[1:], 
fcond)
         token.pos_jump_offset = self.mc.currpos()
         assert token.guard_not_invalidated() == is_guard_not_invalidated
-        if not is_guard_not_invalidated:
+        assert token.guard_compatible() == is_guard_compatible
+        if not is_guard_compatible and not is_guard_not_invalidated:
             self.mc.trap()     # has to be patched later on
         self.pending_guard_tokens.append(token)
+        return token
 
     def build_guard_token(self, op, frame_depth, arglocs, fcond):
         descr = op.getdescr()
@@ -329,6 +332,13 @@
         self.guard_success_cc = c.EQ
         self._emit_guard(op, failargs)
 
+    def emit_guard_compatible(self, op, arglocs, regalloc):
+        l0 = arglocs[0]
+        assert l0.is_reg()
+        bindex = op.getarg(1).getint()
+        token = self._emit_guard(op, arglocs[1:], is_guard_compatible=True)
+        guard_compat.generate_guard_compatible(self, token, l0, bindex)
+
     emit_guard_nonnull = emit_guard_true
     emit_guard_isnull = emit_guard_false
 
@@ -588,9 +598,12 @@
         mc.store(r.SCRATCH.value, r.SCRATCH2.value, 0)
         mc.store(r.SCRATCH.value, r.SCRATCH2.value, diff)
 
+    def _addr_from_gc_table(self, index):
+        return self.gc_table_addr + index * WORD
+
     def _load_from_gc_table(self, rD, rT, index):
         # rT is a temporary, may be equal to rD, must be != r0
-        addr = self.gc_table_addr + index * WORD
+        addr = self._addr_from_gc_table(index)
         self.mc.load_from_addr(rD, rT, addr)
 
     def emit_load_from_gc_table(self, op, arglocs, regalloc):
diff --git a/rpython/jit/backend/ppc/ppc_assembler.py 
b/rpython/jit/backend/ppc/ppc_assembler.py
--- a/rpython/jit/backend/ppc/ppc_assembler.py
+++ b/rpython/jit/backend/ppc/ppc_assembler.py
@@ -15,6 +15,7 @@
 import rpython.jit.backend.ppc.register as r
 import rpython.jit.backend.ppc.condition as c
 from rpython.jit.backend.ppc.register import JITFRAME_FIXED_SIZE
+from rpython.jit.backend.ppc import guard_compat
 from rpython.jit.metainterp.history import AbstractFailDescr
 from rpython.jit.backend.llsupport import jitframe, rewrite
 from rpython.jit.backend.llsupport.asmmemmgr import MachineDataBlockWrapper
@@ -616,6 +617,9 @@
         self.propagate_exception_path = rawstart
         self.mc = None
 
+    def _build_guard_compat_slowpath(self):
+        guard_compat.build_once(self)
+
     def _call_header(self):
         if IS_PPC_64 and IS_BIG_ENDIAN:
             # Reserve space for a function descriptor, 3 words
@@ -889,6 +893,7 @@
         gcreftracers = self.get_asmmemmgr_gcreftracers(looptoken)
         gcreftracers.append(tracer)    # keepalive
         self.teardown_gcrefs_list()
+        self.gc_table_tracer = tracer
 
     def teardown(self):
         self.pending_guard_tokens = None
@@ -974,6 +979,12 @@
             # XXX see patch_jump_for_descr()
             tok.faildescr.adr_jump_offset = rawstart + tok.pos_recovery_stub
             #
+            if tok.guard_compatible():
+                guard_compat.patch_guard_compatible(tok, rawstart,
+                                                    self._addr_from_gc_table,
+                                                    self.gc_table_tracer)
+                continue
+            #
             relative_target = tok.pos_recovery_stub - tok.pos_jump_offset
             #
             if not tok.guard_not_invalidated():
@@ -996,6 +1007,9 @@
         # patch it inplace, and instead we patch the quick failure code
         # (which should be at least 6 instructions, so enough).
         # --- XXX for now we always use the second solution ---
+        if isinstance(faildescr, guard_compat.GuardCompatibleDescr):
+            guard_compat.invalidate_cache(faildescr)
+            return
         mc = PPCBuilder()
         mc.b_abs(adr_new_target)
         mc.copy_to_raw_memory(faildescr.adr_jump_offset)
diff --git a/rpython/jit/backend/ppc/regalloc.py 
b/rpython/jit/backend/ppc/regalloc.py
--- a/rpython/jit/backend/ppc/regalloc.py
+++ b/rpython/jit/backend/ppc/regalloc.py
@@ -605,9 +605,21 @@
     def prepare_guard_value(self, op):
         l0 = self.ensure_reg(op.getarg(0))
         l1 = self.ensure_reg_or_16bit_imm(op.getarg(1))
+        op.getdescr().make_a_counter_per_value(op,
+            self.cpu.all_reg_indexes[l0.value])
         arglocs = self._prepare_guard(op, [l0, l1])
         return arglocs
 
+    def prepare_guard_compatible(self, op):
+        op.getdescr().make_a_counter_per_value(op, -1)   # -1 not used here
+        args = op.getarglist()
+        assert args[0].type == REF             # only supported case for now
+        assert isinstance(args[1], ConstInt)   # by rewrite.py
+        x = self.ensure_reg(args[0])
+        y = self.loc(args[1])
+        arglocs = self._prepare_guard(op, [x, y])
+        return arglocs
+
     def prepare_guard_class(self, op):
         x = self.ensure_reg(op.getarg(0))
         y_val = force_int(op.getarg(1).getint())
diff --git a/rpython/jit/backend/ppc/test/test_compatible.py 
b/rpython/jit/backend/ppc/test/test_compatible.py
new file mode 100644
--- /dev/null
+++ b/rpython/jit/backend/ppc/test/test_compatible.py
@@ -0,0 +1,6 @@
+from rpython.jit.backend.ppc.test.support import JitPPCMixin
+from rpython.jit.metainterp.test import test_compatible
+
+
+class TestCompatible(JitPPCMixin, test_compatible.TestCompatible):
+    pass
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to