Author: Armin Rigo <ar...@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 +@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(): _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit