[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