[pypy-commit] pypy guard-compatible: test_guard_compatible_1 passes
arigo
pypy.commits at gmail.com
Sun May 22 15:54:20 EDT 2016
Author: Armin Rigo <arigo at tunes.org>
Branch: guard-compatible
Changeset: r84590:7e31edfc6cc7
Date: 2016-05-22 21:54 +0200
http://bitbucket.org/pypy/pypy/changeset/7e31edfc6cc7/
Log: test_guard_compatible_1 passes
diff --git a/rpython/jit/backend/llsupport/rewrite.py b/rpython/jit/backend/llsupport/rewrite.py
--- a/rpython/jit/backend/llsupport/rewrite.py
+++ b/rpython/jit/backend/llsupport/rewrite.py
@@ -371,6 +371,9 @@
if OpHelpers.is_call_assembler(op.getopnum()):
self.handle_call_assembler(op)
continue
+ if op.getopnum() == rop.GUARD_COMPATIBLE:
+ self.handle_guard_compatible(op)
+ continue
if op.getopnum() == rop.JUMP or op.getopnum() == rop.FINISH:
self.emit_pending_zeros()
#
@@ -985,3 +988,16 @@
self._newops.append(load_op)
self.gcrefs_recently_loaded[index] = load_op
return load_op
+
+ def handle_guard_compatible(self, op):
+ from rpython.jit.backend.x86 import guard_compat # XXX
+ c = op.getarg(1)
+ assert isinstance(c, ConstPtr)
+ descr = op.getdescr()
+ bchoices = guard_compat.initial_bchoices(descr, c.value)
+ bcindex = len(self.gcrefs_output_list)
+ gcref = lltype.cast_opaque_ptr(llmemory.GCREF, bchoices)
+ self.gcrefs_output_list.append(gcref)
+ new_op = op.copy_and_change(rop.GUARD_COMPATIBLE,
+ [op.getarg(0), ConstInt(bcindex)])
+ self.emit_op(new_op)
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
@@ -743,6 +743,10 @@
clt = self.current_clt
for tok in self.pending_guard_tokens:
addr = rawstart + tok.pos_jump_offset
+ if tok.guard_compatible():
+ guard_compat.patch_guard_compatible(tok, addr,
+ self.gc_table_addr)
+ continue
tok.faildescr.adr_jump_offset = addr
descr = tok.faildescr
if descr.loop_version():
@@ -754,8 +758,6 @@
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:
@@ -854,6 +856,9 @@
return res
def patch_jump_for_descr(self, faildescr, adr_new_target):
+ if isinstance(faildescr, guard_compat.GuardCompatibleDescr):
+ xxxxxxxxxx
+ return
adr_jump_offset = faildescr.adr_jump_offset
assert adr_jump_offset != 0
offset = adr_new_target - (adr_jump_offset + 4)
@@ -1433,14 +1438,24 @@
assert IS_X86_32
return self.gc_table_addr + index * WORD
+ def load_reg_from_gc_table(self, resvalue, index):
+ if IS_X86_64:
+ self.mc.MOV_rp(resvalue, 0) # %rip-relative
+ self._patch_load_from_gc_table(index)
+ elif IS_X86_32:
+ self.mc.MOV_rj(resvalue, self._addr_from_gc_table(index))
+
+ def push_from_gc_table(self, index):
+ if IS_X86_64:
+ self.mc.PUSH_p(0) # %rip-relative
+ self._patch_load_from_gc_table(index)
+ elif IS_X86_32:
+ self.mc.PUSH_j(self._addr_from_gc_table(index))
+
def genop_load_from_gc_table(self, op, arglocs, resloc):
index = op.getarg(0).getint()
assert isinstance(resloc, RegLoc)
- if IS_X86_64:
- self.mc.MOV_rp(resloc.value, 0) # %rip-relative
- self._patch_load_from_gc_table(index)
- elif IS_X86_32:
- self.mc.MOV_rj(resloc.value, self._addr_from_gc_table(index))
+ self._load_reg_from_gc_table(resloc.value, index)
def genop_int_force_ge_zero(self, op, arglocs, resloc):
self.mc.TEST(arglocs[0], arglocs[0])
@@ -1810,13 +1825,14 @@
self.implement_guard(guard_token)
def genop_guard_guard_compatible(self, guard_op, guard_token, locs, ign):
- assert guard_op.getarg(0).type == REF # only supported case for now
- assert guard_op.getarg(1).type == REF
- loc_reg, loc_imm = locs
+ loc_reg, loc_imm, loc_reg2 = locs
assert isinstance(loc_reg, RegLoc)
- assert isinstance(loc_imm, ImmedLoc)
+ assert isinstance(loc_imm, ImmedLoc) # index of 'backend_choices'
+ assert isinstance(loc_reg2, RegLoc)
+ self.load_reg_from_gc_table(loc_reg2.value, loc_imm.value)
guard_compat.generate_guard_compatible(self, guard_token,
- loc_reg, loc_imm.value)
+ loc_reg.value, loc_imm.value,
+ loc_reg2.value)
def _cmp_guard_class(self, locs):
loc_ptr = locs[0]
@@ -1947,11 +1963,7 @@
guardtok.faildescr, regalloc)
#
faildescrindex, target = self.store_info_on_descr(startpos, guardtok)
- if IS_X86_64:
- self.mc.PUSH_p(0) # %rip-relative
- self._patch_load_from_gc_table(faildescrindex)
- elif IS_X86_32:
- self.mc.PUSH_j(self._addr_from_gc_table(faildescrindex))
+ self.push_from_gc_table(faildescrindex)
self.push_gcmap(self.mc, guardtok.gcmap, push=True)
self.mc.JMP(imm(target))
return startpos
@@ -2066,11 +2078,7 @@
descr = op.getdescr()
faildescrindex = self.get_gcref_from_faildescr(descr)
- if IS_X86_64:
- self.mc.MOV_rp(eax.value, 0)
- self._patch_load_from_gc_table(faildescrindex)
- elif IS_X86_32:
- self.mc.MOV_rj(eax.value, self._addr_from_gc_table(faildescrindex))
+ self.load_reg_from_gc_table(eax.value, faildescrindex)
self.mov(eax, RawEbpLoc(ofs))
arglist = op.getarglist()
@@ -2145,12 +2153,12 @@
faildescrindex = self.get_gcref_from_faildescr(faildescr)
if IS_X86_64:
- self.mc.MOV_rp(X86_64_SCRATCH_REG.value, 0)
- self._patch_load_from_gc_table(faildescrindex)
+ self.load_reg_from_gc_table(X86_64_SCRATCH_REG.value,
+ faildescrindex)
self.mc.MOV(raw_stack(ofs), X86_64_SCRATCH_REG)
elif IS_X86_32:
# XXX need a scratch reg here for efficiency; be more clever
- self.mc.PUSH_j(self._addr_from_gc_table(faildescrindex))
+ self.push_from_gc_table(faildescrindex)
self.mc.POP(raw_stack(ofs))
def _find_nearby_operation(self, delta):
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,5 +1,5 @@
from rpython.rlib import rgc
-from rpython.rlib.objectmodel import specialize
+from rpython.rlib.objectmodel import specialize, we_are_translated
from rpython.rlib.rarithmetic import r_uint
from rpython.rtyper.lltypesystem import lltype, llmemory, rffi
from rpython.rtyper.lltypesystem.lloperation import llop
@@ -20,7 +20,7 @@
# following code, ofs(x) means the offset in the GC table of the
# pointer 'x':
#
-# MOV reg2, [RIP + ofs(_backend_choices)]
+# MOV reg2, [RIP + ofs(_backend_choices)] # LOAD_FROM_GC_TABLE
# CMP reg, [reg2 + bc_most_recent]
# JNE slow_case
# JMP *[reg2 + bc_most_recent + 8]
@@ -230,27 +230,33 @@
[lltype.Ptr(BACKEND_CHOICES), llmemory.GCREF],
lltype.Signed))
-def invoke_find_compatible(bchoices, new_gcref):
- descr = bchoices.bc_faildescr
- descr = cast_gcref_to_instance(GuardCompatibleDescr, descr)
- try:
- xxx # temp
- result = descr.find_compatible(cpu, new_gcref)
- if result == 0:
- result = descr._backend_failure_recovery
- else:
- if result == -1:
- result = descr._backend_sequel_label
- bchoices = add_in_tree(bchoices, new_gcref, result)
- descr._backend_choices_addr[0] = bchoices # GC table
- bchoices.bc_most_recent.gcref = new_gcref
- bchoices.bc_most_recent.asmaddr = result
- return result
- except: # oops!
- if not we_are_translated():
- import sys, pdb
- pdb.post_mortem(sys.exc_info()[2])
- return descr._backend_failure_recovery
+ at specialize.memo()
+def make_invoke_find_compatible(cpu):
+ def invoke_find_compatible(bchoices, new_gcref):
+ descr = bchoices.bc_faildescr
+ descr = cast_gcref_to_instance(GuardCompatibleDescr, descr)
+ try:
+ result = descr.find_compatible(cpu, new_gcref)
+ if result == 0:
+ result = descr._backend_failure_recovery
+ else:
+ if result == -1:
+ result = descr._backend_sequel_label
+ bchoices = add_in_tree(bchoices, new_gcref, result)
+ # ---no GC operation---
+ choices_addr = descr._backend_choices_addr # GC table
+ bchoices_int = rffi.cast(lltype.Signed, bchoices)
+ llop.raw_store(lltype.Void, choices_addr, 0, bchoices_int)
+ # ---no GC operation end---
+ bchoices.bc_most_recent.gcref = new_gcref
+ bchoices.bc_most_recent.asmaddr = result
+ return result
+ except: # oops!
+ if not we_are_translated():
+ import sys, pdb
+ pdb.post_mortem(sys.exc_info()[2])
+ return descr._backend_failure_recovery
+ return invoke_find_compatible
def add_in_tree(bchoices, new_gcref, new_asmaddr):
rgc.register_custom_trace_hook(BACKEND_CHOICES, lambda_bchoices_trace)
@@ -292,26 +298,38 @@
pairs_quicksort(addr, length)
return bchoices
-def initial_bchoices(guard_compat_descr, initial_gcref, gcmap):
+def initial_bchoices(guard_compat_descr, initial_gcref):
bchoices = lltype.malloc(BACKEND_CHOICES, 1)
- bchoices.bc_gcmap = gcmap
+ # bchoices.bc_gcmap: patch_guard_compatible()
bchoices.bc_faildescr = cast_instance_to_gcref(guard_compat_descr)
bchoices.bc_most_recent.gcref = initial_gcref
- # bchoices.bc_most_recent.asmaddr: later
+ # bchoices.bc_most_recent.asmaddr: patch_guard_compatible()
bchoices.bc_list[0].gcref = initial_gcref
- # bchoices.bc_list[0].asmaddr: later
+ # bchoices.bc_list[0].asmaddr: patch_guard_compatible()
return bchoices
-def finish_guard_compatible_descr(guard_compat_descr,
- choices_addr, # points to bchoices in the GC table
- sequel_label, # "sequel:" label above
- failure_recovery): # failure recovery address
+def patch_guard_compatible(guard_token, sequel_label, gc_table_addr):
+ # go to the address in the gctable, number 'bindex'
+ bindex = guard_token.guard_compat_bindex
+ choices_addr = gc_table_addr + WORD * bindex
+ failure_recovery = guard_token.pos_recovery_stub
+ gcmap = guard_token.gcmap
+ # choices_addr: points to bchoices in the GC table
+ # sequel_label: "sequel:" label above
+ # failure_recovery: failure recovery address
+ guard_compat_descr = guard_token.faildescr
+ assert isinstance(guard_compat_descr, GuardCompatibleDescr)
guard_compat_descr._backend_choices_addr = choices_addr
guard_compat_descr._backend_sequel_label = sequel_label
guard_compat_descr._backend_failure_recovery = failure_recovery
- bchoices = rffi.cast(lltype.Ptr(BACKEND_CHOICES), choices_addr[0])
+ # ---no GC operation---
+ bchoices = llop.raw_load(lltype.Signed, choices_addr, 0)
+ bchoices = rffi.cast(lltype.Ptr(BACKEND_CHOICES), bchoices)
+ # ---no GC operation end---
assert len(bchoices.bc_list) == 1
- assert bchoices.bc_faildescr == cast_instance_to_gcref(guard_compat_descr)
+ assert (cast_gcref_to_instance(GuardCompatibleDescr, bchoices.bc_faildescr)
+ is guard_compat_descr)
+ bchoices.bc_gcmap = gcmap
bchoices.bc_most_recent.asmaddr = sequel_label
bchoices.bc_list[0].asmaddr = sequel_label
@@ -392,6 +410,7 @@
mc.MOV_rr(regloc.esi.value, rax) # MOV RSI, RAX
mc.MOV_rm(r11, (rdi, bc_gcmap)) # MOV R11, [RDI + bc_gcmap]
mc.MOV_br(jf_gcmap, r11) # MOV [RBP + jf_gcmap], R11
+ 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)
mc.CALL(regloc.imm(llfunc)) # CALL invoke_find_compatible
@@ -408,3 +427,43 @@
mc.JMP_r(r11) # JMP *R11
assembler.guard_compat_search_tree = mc.materialize(assembler.cpu, [])
+
+
+def generate_guard_compatible(assembler, guard_token, reg, bindex, reg2):
+ mc = assembler.mc
+ rax = regloc.eax.value
+ rdx = regloc.edx.value
+ frame_size = DEFAULT_FRAME_BYTES
+
+ ofs = _real_number(BCMOSTRECENT)
+ mc.CMP_rm(reg, (reg2, ofs)) # CMP reg, [reg2 + bc_most_recent]
+ mc.J_il8(rx86.Conditions['NE'], 0) # JNE slow_case
+ jne_location = mc.get_relative_pos()
+
+ mc.JMP_m((reg2, ofs + WORD)) # JMP *[reg2 + bc_most_recent + 8]
+ mc.force_frame_size(frame_size)
+
+ _fix_forward_label(mc, jne_location) # slow_case:
+ mc.PUSH_r(rdx) # PUSH RDX
+ mc.PUSH_r(rax) # PUSH RAX
+ # manually move reg to RAX and reg2 to RDX
+ if reg2 == rax:
+ if reg == rdx:
+ mc.XCHG_rr(rax, rdx)
+ reg = rax
+ else:
+ mc.MOV_rr(rdx, rax)
+ reg2 = rdx
+ if reg != rax:
+ assert reg2 != rax
+ mc.MOV_rr(rax, reg)
+ if reg2 != rdx:
+ mc.MOV_rr(rdx, reg2)
+
+ mc.JMP(regloc.imm(assembler.guard_compat_search_tree))
+ mc.force_frame_size(frame_size)
+
+ # abuse this field to store the 'sequel' relative offset
+ guard_token.pos_jump_offset = mc.get_relative_pos()
+ guard_token.guard_compat_bindex = bindex
+ assembler.pending_guard_tokens.append(guard_token)
diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py
--- a/rpython/jit/backend/x86/regalloc.py
+++ b/rpython/jit/backend/x86/regalloc.py
@@ -472,21 +472,31 @@
consider_guard_not_forced = consider_guard_no_exception
def consider_guard_value(self, op):
- x = self.make_sure_var_in_reg(op.getarg(0))
+ x = self.make_sure_var_in_reg(op.getarg(0), [op.getarg(1)])
loc = self.assembler.cpu.all_reg_indexes[x.value]
op.getdescr().make_a_counter_per_value(op, loc)
y = self.loc(op.getarg(1))
self.perform_guard(op, [x, y], None)
+ def consider_guard_compatible(self, op):
+ args = op.getarglist()
+ assert args[0].type == REF # only supported case for now
+ assert isinstance(args[1], ConstInt) # by rewrite.py
+ tmp_box = TempVar()
+ x = self.rm.make_sure_var_in_reg(args[0])
+ y = self.loc(args[1])
+ z = self.rm.force_allocate_reg(tmp_box, args)
+ self.rm.possibly_free_var(tmp_box)
+ self.perform_guard(op, [x, y, z], None)
+
def consider_guard_class(self, op):
assert not isinstance(op.getarg(0), Const)
- x = self.rm.make_sure_var_in_reg(op.getarg(0))
+ x = self.rm.make_sure_var_in_reg(op.getarg(0), [op.getarg(1)])
y = self.loc(op.getarg(1))
self.perform_guard(op, [x, y], None)
consider_guard_nonnull_class = consider_guard_class
consider_guard_gc_type = consider_guard_class
- consider_guard_compatible = consider_guard_class
def consider_guard_is_object(self, op):
x = self.make_sure_var_in_reg(op.getarg(0))
diff --git a/rpython/jit/backend/x86/rx86.py b/rpython/jit/backend/x86/rx86.py
--- a/rpython/jit/backend/x86/rx86.py
+++ b/rpython/jit/backend/x86/rx86.py
@@ -670,6 +670,7 @@
JM1_l = insn('\xE9', relative(1))
JM1_r = insn(rex_nw, '\xFF', orbyte(4<<3), register(1), '\xC0')
+ JM1_m = insn(rex_nw, '\xFF', orbyte(4<<3), mem_reg_plus_const(1))
# FIXME: J_il8 and JMP_l8 assume the caller will do the appropriate
# calculation to find the displacement, but J_il does it for the caller.
# We need to be consistent.
@@ -687,6 +688,11 @@
if not we_are_translated():
self._frame_size = None
+ def JMP_m(self, mem):
+ self.JM1_m(mem)
+ if not we_are_translated():
+ self._frame_size = None
+
def JMP_l8(self, rel):
self.JM1_l8(rel)
if not we_are_translated():
More information about the pypy-commit
mailing list