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