[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