[pypy-svn] r71557 - in pypy/trunk/pypy/jit: backend backend/llgraph backend/llsupport backend/llsupport/test backend/test backend/x86 metainterp

arigo at codespeak.net arigo at codespeak.net
Sun Feb 28 14:15:38 CET 2010


Author: arigo
Date: Sun Feb 28 14:15:36 2010
New Revision: 71557

Modified:
   pypy/trunk/pypy/jit/backend/llgraph/llimpl.py
   pypy/trunk/pypy/jit/backend/llsupport/gc.py
   pypy/trunk/pypy/jit/backend/llsupport/test/test_gc.py
   pypy/trunk/pypy/jit/backend/model.py
   pypy/trunk/pypy/jit/backend/test/runner_test.py
   pypy/trunk/pypy/jit/backend/x86/assembler.py
   pypy/trunk/pypy/jit/backend/x86/regalloc.py
   pypy/trunk/pypy/jit/backend/x86/ri386setup.py
   pypy/trunk/pypy/jit/metainterp/resoperation.py
Log:
Change COND_CALL_GC_WB: it now only takes the two arguments that
are passed to the write barrier, and does the checking explicitly.
This lets the x86 backend generate a bit more compact code, not
needing a register just to load the 'tid'.


Modified: pypy/trunk/pypy/jit/backend/llgraph/llimpl.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/llgraph/llimpl.py	(original)
+++ pypy/trunk/pypy/jit/backend/llgraph/llimpl.py	Sun Feb 28 14:15:36 2010
@@ -127,7 +127,7 @@
     'call'            : (('ref', 'varargs'), 'intorptr'),
     'call_assembler'  : (('ref', 'varargs'), 'intorptr'),
     'call_pure'       : (('ref', 'varargs'), 'intorptr'),
-    'cond_call_gc_wb' : (('int', 'int', 'ptr', 'varargs'), None),
+    'cond_call_gc_wb' : (('ptr', 'ptr'), None),
     'oosend'          : (('varargs',), 'intorptr'),
     'oosend_pure'     : (('varargs',), 'intorptr'),
     'guard_true'      : (('bool',), None),
@@ -788,9 +788,8 @@
 
     op_call_pure = op_call
 
-    def op_cond_call_gc_wb(self, calldescr, a, b, func, *args):
-        if a & b:
-            self.op_call(calldescr, func, *args)
+    def op_cond_call_gc_wb(self, descr, a, b):
+        py.test.skip("cond_call_gc_wb not supported")
 
     def op_oosend(self, descr, obj, *args):
         raise NotImplementedError("oosend for lltype backend??")

Modified: pypy/trunk/pypy/jit/backend/llsupport/gc.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/llsupport/gc.py	(original)
+++ pypy/trunk/pypy/jit/backend/llsupport/gc.py	Sun Feb 28 14:15:36 2010
@@ -6,6 +6,7 @@
 from pypy.rpython.annlowlevel import llhelper
 from pypy.translator.tool.cbuild import ExternalCompilationInfo
 from pypy.jit.metainterp.history import BoxInt, BoxPtr, ConstInt, ConstPtr
+from pypy.jit.metainterp.history import AbstractDescr
 from pypy.jit.metainterp.resoperation import ResOperation, rop
 from pypy.jit.backend.llsupport import symbolic
 from pypy.jit.backend.llsupport.symbolic import WORD
@@ -31,6 +32,8 @@
         pass
     def can_inline_malloc(self, descr):
         return False
+    def has_write_barrier_class(self):
+        return None
 
 # ____________________________________________________________
 
@@ -296,6 +299,30 @@
         return llmemory.cast_ptr_to_adr(compressed)
 
 
+class WriteBarrierDescr(AbstractDescr):
+    def __init__(self, gc_ll_descr):
+        self.llop1 = gc_ll_descr.llop1
+        self.WB_FUNCPTR = gc_ll_descr.WB_FUNCPTR
+        self.fielddescr_tid = get_field_descr(gc_ll_descr,
+                                              gc_ll_descr.GCClass.HDR, 'tid')
+        self.jit_wb_if_flag = gc_ll_descr.GCClass.JIT_WB_IF_FLAG
+        # if convenient for the backend, we also compute the info about
+        # the flag as (byte-offset, single-byte-flag).
+        import struct
+        value = struct.pack("i", self.jit_wb_if_flag)
+        assert value.count('\x00') == len(value) - 1    # only one byte is != 0
+        i = 0
+        while value[i] == '\x00': i += 1
+        self.jit_wb_if_flag_byteofs = i
+        self.jit_wb_if_flag_singlebyte = struct.unpack('b', value[i])[0]
+
+    def get_write_barrier_fn(self, cpu):
+        llop1 = self.llop1
+        funcptr = llop1.get_write_barrier_failing_case(self.WB_FUNCPTR)
+        funcaddr = llmemory.cast_ptr_to_adr(funcptr)
+        return cpu.cast_adr_to_int(funcaddr)
+
+
 class GcLLDescr_framework(GcLLDescription):
 
     def __init__(self, gcdescr, translator, llop1=llop):
@@ -337,11 +364,6 @@
         self.moving_gc = self.GCClass.moving_gc
         self.HDRPTR = lltype.Ptr(self.GCClass.HDR)
         self.gcheaderbuilder = GCHeaderBuilder(self.HDRPTR.TO)
-        self.fielddescr_tid = get_field_descr(self, self.GCClass.HDR, 'tid')
-        self.c_jit_wb_if_flag = ConstInt(self.GCClass.JIT_WB_IF_FLAG)
-        self.calldescr_jit_wb = get_call_descr(self, [llmemory.GCREF,
-                                                      llmemory.GCREF],
-                                               lltype.Void)
         (self.array_basesize, _, self.array_length_ofs) = \
              symbolic.get_array_token(lltype.GcArray(lltype.Signed), True)
         min_ns = self.GCClass.TRANSLATION_PARAMS['min_nursery_size']
@@ -367,6 +389,7 @@
             [lltype.Signed, lltype.Signed], llmemory.GCREF))
         self.WB_FUNCPTR = lltype.Ptr(lltype.FuncType(
             [llmemory.Address, llmemory.Address], lltype.Void))
+        self.write_barrier_descr = WriteBarrierDescr(self)
         #
         def malloc_array(itemsize, tid, num_elem):
             type_id = llop.extract_ushort(rffi.USHORT, tid)
@@ -539,7 +562,7 @@
                 v = op.args[1]
                 if isinstance(v, BoxPtr) or (isinstance(v, ConstPtr) and
                                              bool(v.value)): # store a non-NULL
-                    self._gen_write_barrier(cpu, newops, op.args[0], v)
+                    self._gen_write_barrier(newops, op.args[0], v)
                     op = ResOperation(rop.SETFIELD_RAW, op.args, None,
                                       descr=op.descr)
             # ---------- write barrier for SETARRAYITEM_GC ----------
@@ -547,7 +570,7 @@
                 v = op.args[2]
                 if isinstance(v, BoxPtr) or (isinstance(v, ConstPtr) and
                                              bool(v.value)): # store a non-NULL
-                    self._gen_write_barrier(cpu, newops, op.args[0], v)
+                    self._gen_write_barrier(newops, op.args[0], v)
                     op = ResOperation(rop.SETARRAYITEM_RAW, op.args, None,
                                       descr=op.descr)
             # ----------
@@ -555,17 +578,10 @@
         del operations[:]
         operations.extend(newops)
 
-    def _gen_write_barrier(self, cpu, newops, v_base, v_value):
-        v_tid = BoxInt()
-        newops.append(ResOperation(rop.GETFIELD_RAW, [v_base], v_tid,
-                                   descr=self.fielddescr_tid))
-        llop1 = self.llop1
-        funcptr = llop1.get_write_barrier_failing_case(self.WB_FUNCPTR)
-        funcaddr = llmemory.cast_ptr_to_adr(funcptr)
-        c_func = ConstInt(cpu.cast_adr_to_int(funcaddr))
-        args = [v_tid, self.c_jit_wb_if_flag, c_func, v_base, v_value]
+    def _gen_write_barrier(self, newops, v_base, v_value):
+        args = [v_base, v_value]
         newops.append(ResOperation(rop.COND_CALL_GC_WB, args, None,
-                                   descr=self.calldescr_jit_wb))
+                                   descr=self.write_barrier_descr))
 
     def can_inline_malloc(self, descr):
         assert isinstance(descr, BaseSizeDescr)
@@ -576,6 +592,9 @@
             return True
         return False
 
+    def has_write_barrier_class(self):
+        return WriteBarrierDescr
+
 # ____________________________________________________________
 
 def get_ll_description(gcdescr, translator=None):

Modified: pypy/trunk/pypy/jit/backend/llsupport/test/test_gc.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/llsupport/test/test_gc.py	(original)
+++ pypy/trunk/pypy/jit/backend/llsupport/test/test_gc.py	Sun Feb 28 14:15:36 2010
@@ -250,21 +250,17 @@
         newops = []
         v_base = BoxPtr()
         v_value = BoxPtr()
-        gc_ll_descr._gen_write_barrier(self.fake_cpu, newops, v_base, v_value)
+        gc_ll_descr._gen_write_barrier(newops, v_base, v_value)
         assert llop1.record == []
-        assert len(newops) == 2
-        assert newops[0].opnum == rop.GETFIELD_RAW
-        assert newops[0].args == [v_base]
-        assert newops[0].descr == gc_ll_descr.fielddescr_tid
-        v_tid = newops[0].result
-        assert newops[1].opnum == rop.COND_CALL_GC_WB
-        assert newops[1].args[0] == v_tid
-        assert newops[1].args[1] ==ConstInt(gc_ll_descr.GCClass.JIT_WB_IF_FLAG)
-        assert newops[1].args[2] == ConstInt(42)     # func ptr
-        assert newops[1].args[3] == v_base
-        assert newops[1].args[4] == v_value
-        assert newops[1].descr == gc_ll_descr.calldescr_jit_wb
-        assert newops[1].result is None
+        assert len(newops) == 1
+        assert newops[0].opnum == rop.COND_CALL_GC_WB
+        assert newops[0].args[0] == v_base
+        assert newops[0].args[1] == v_value
+        assert newops[0].result is None
+        wbdescr = newops[0].descr
+        assert isinstance(wbdescr.jit_wb_if_flag, int)
+        assert isinstance(wbdescr.jit_wb_if_flag_byteofs, int)
+        assert isinstance(wbdescr.jit_wb_if_flag_singlebyte, int)
 
     def test_get_rid_of_debug_merge_point(self):
         operations = [
@@ -353,26 +349,16 @@
             ]
         gc_ll_descr = self.gc_ll_descr
         gc_ll_descr.rewrite_assembler(self.fake_cpu, operations)
-        assert len(operations) == 3
-        #
-        assert operations[0].opnum == rop.GETFIELD_RAW
-        assert operations[0].args == [v_base]
-        assert operations[0].descr == gc_ll_descr.fielddescr_tid
-        v_tid = operations[0].result
-        #
-        assert operations[1].opnum == rop.COND_CALL_GC_WB
-        assert operations[1].args[0] == v_tid
-        assert operations[1].args[1] == ConstInt(
-                                            gc_ll_descr.GCClass.JIT_WB_IF_FLAG)
-        assert operations[1].args[2] == ConstInt(42)     # func ptr
-        assert operations[1].args[3] == v_base
-        assert operations[1].args[4] == v_value
-        assert operations[1].descr == gc_ll_descr.calldescr_jit_wb
-        assert operations[1].result is None
+        assert len(operations) == 2
         #
-        assert operations[2].opnum == rop.SETFIELD_RAW
-        assert operations[2].args == [v_base, v_value]
-        assert operations[2].descr == field_descr
+        assert operations[0].opnum == rop.COND_CALL_GC_WB
+        assert operations[0].args[0] == v_base
+        assert operations[0].args[1] == v_value
+        assert operations[0].result is None
+        #
+        assert operations[1].opnum == rop.SETFIELD_RAW
+        assert operations[1].args == [v_base, v_value]
+        assert operations[1].descr == field_descr
 
     def test_rewrite_assembler_3(self):
         # check write barriers before SETARRAYITEM_GC
@@ -386,23 +372,13 @@
             ]
         gc_ll_descr = self.gc_ll_descr
         gc_ll_descr.rewrite_assembler(self.fake_cpu, operations)
-        assert len(operations) == 3
-        #
-        assert operations[0].opnum == rop.GETFIELD_RAW
-        assert operations[0].args == [v_base]
-        assert operations[0].descr == gc_ll_descr.fielddescr_tid
-        v_tid = operations[0].result
-        #
-        assert operations[1].opnum == rop.COND_CALL_GC_WB
-        assert operations[1].args[0] == v_tid
-        assert operations[1].args[1] == ConstInt(
-                                            gc_ll_descr.GCClass.JIT_WB_IF_FLAG)
-        assert operations[1].args[2] == ConstInt(42)     # func ptr
-        assert operations[1].args[3] == v_base
-        assert operations[1].args[4] == v_value
-        assert operations[1].descr == gc_ll_descr.calldescr_jit_wb
-        assert operations[1].result is None
+        assert len(operations) == 2
         #
-        assert operations[2].opnum == rop.SETARRAYITEM_RAW
-        assert operations[2].args == [v_base, v_index, v_value]
-        assert operations[2].descr == array_descr
+        assert operations[0].opnum == rop.COND_CALL_GC_WB
+        assert operations[0].args[0] == v_base
+        assert operations[0].args[1] == v_value
+        assert operations[0].result is None
+        #
+        assert operations[1].opnum == rop.SETARRAYITEM_RAW
+        assert operations[1].args == [v_base, v_index, v_value]
+        assert operations[1].descr == array_descr

Modified: pypy/trunk/pypy/jit/backend/model.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/model.py	(original)
+++ pypy/trunk/pypy/jit/backend/model.py	Sun Feb 28 14:15:36 2010
@@ -225,8 +225,7 @@
         return self.do_call(args, calldescr)
 
     def do_cond_call_gc_wb(self, args, calldescr):
-        if args[0].getint() & args[1].getint():
-            self.do_call(args[2:], calldescr)
+        raise NotImplementedError
 
     def do_cast_ptr_to_int(self, ptrbox):
         raise NotImplementedError

Modified: pypy/trunk/pypy/jit/backend/test/runner_test.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/test/runner_test.py	(original)
+++ pypy/trunk/pypy/jit/backend/test/runner_test.py	Sun Feb 28 14:15:36 2010
@@ -1,5 +1,5 @@
 
-import py, sys, random, os
+import py, sys, random, os, struct
 from pypy.jit.metainterp.history import (AbstractFailDescr,
                                          BasicFailDescr,
                                          BoxInt, Box, BoxPtr,
@@ -1271,23 +1271,32 @@
             record.append((a, b))
         record = []
         #
-        FUNC = self.FuncType([lltype.Signed, lltype.Signed], lltype.Void)
+        S = lltype.GcStruct('S', ('tid', lltype.Signed))
+        FUNC = self.FuncType([lltype.Ptr(S), lltype.Signed], lltype.Void)
         func_ptr = llhelper(lltype.Ptr(FUNC), func_void)
         funcbox = self.get_funcbox(self.cpu, func_ptr)
-        calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT)
+        class WriteBarrierDescr:
+            jit_wb_if_flag = 4096
+            jit_wb_if_flag_byteofs = struct.pack("i", 4096).index('\x10')
+            jit_wb_if_flag_singlebyte = 0x10
+            def get_write_barrier_fn(self, cpu):
+                return funcbox.getint()
+        #
         for cond in [False, True]:
             value = random.randrange(-sys.maxint, sys.maxint)
             if cond:
                 value |= 4096
             else:
                 value &= ~4096
+            s = lltype.malloc(S)
+            s.tid = value
+            sgcref = lltype.cast_opaque_ptr(llmemory.GCREF, s)
             del record[:]
             self.execute_operation(rop.COND_CALL_GC_WB,
-                                   [BoxInt(value), ConstInt(4096),
-                                    funcbox, BoxInt(655360), BoxInt(-2121)],
-                                   'void', descr=calldescr)
+                                   [BoxPtr(sgcref), ConstInt(-2121)],
+                                   'void', descr=WriteBarrierDescr())
             if cond:
-                assert record == [(655360, -2121)]
+                assert record == [(s, -2121)]
             else:
                 assert record == []
 

Modified: pypy/trunk/pypy/jit/backend/x86/assembler.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/x86/assembler.py	(original)
+++ pypy/trunk/pypy/jit/backend/x86/assembler.py	Sun Feb 28 14:15:36 2010
@@ -1,11 +1,9 @@
-import sys, os
-import ctypes
+import sys
 from pypy.jit.backend.llsupport import symbolic
 from pypy.jit.metainterp.history import Const, Box, BoxInt, BoxPtr, BoxFloat
 from pypy.jit.metainterp.history import AbstractFailDescr, INT, REF, FLOAT,\
      LoopToken
-from pypy.rpython.lltypesystem import lltype, rffi, ll2ctypes, rstr, llmemory
-from pypy.rpython.lltypesystem.rclass import OBJECT
+from pypy.rpython.lltypesystem import lltype, rffi, rstr, llmemory
 from pypy.rpython.lltypesystem.lloperation import llop
 from pypy.rpython.annlowlevel import llhelper
 from pypy.tool.uid import fixid
@@ -13,7 +11,7 @@
      X86RegisterManager, X86XMMRegisterManager, get_ebp_ofs, FRAME_FIXED_SIZE,\
      FORCE_INDEX_OFS
 from pypy.rlib.objectmodel import we_are_translated, specialize
-from pypy.jit.backend.x86 import codebuf, oprofile
+from pypy.jit.backend.x86 import codebuf
 from pypy.jit.backend.x86.ri386 import *
 from pypy.jit.metainterp.resoperation import rop
 from pypy.jit.backend.x86.support import values_array
@@ -1378,20 +1376,22 @@
     def genop_discard_cond_call_gc_wb(self, op, arglocs):
         # use 'mc._mc' directly instead of 'mc', to avoid
         # bad surprizes if the code buffer is mostly full
-        loc_cond = arglocs[0]
-        loc_mask = arglocs[1]
+        descr = op.descr
+        if we_are_translated():
+            cls = self.cpu.gc_ll_descr.has_write_barrier_class()
+            assert cls is not None and isinstance(descr, cls)
+        loc_base = arglocs[0]
         mc = self._start_block()
-        mc.TEST(loc_cond, loc_mask)
+        mc.TEST(mem8(loc_base, descr.jit_wb_if_flag_byteofs),
+                imm8(descr.jit_wb_if_flag_singlebyte))
         mc.write(constlistofchars('\x74\x00'))             # JZ after_the_call
         jz_location = mc.get_relative_pos()
         # the following is supposed to be the slow path, so whenever possible
         # we choose the most compact encoding over the most efficient one.
-        for i in range(len(arglocs)-1, 2, -1):
+        for i in range(len(arglocs)-1, -1, -1):
             mc.PUSH(arglocs[i])
-        mc.CALL(rel32(op.args[2].getint()))
-        mc.POP(eax)
-        mc.POP(eax)
-        for i in range(5, len(arglocs)):
+        mc.CALL(rel32(descr.get_write_barrier_fn(self.cpu)))
+        for i in range(len(arglocs)):
             loc = arglocs[i]
             assert isinstance(loc, REG)
             mc.POP(loc)

Modified: pypy/trunk/pypy/jit/backend/x86/regalloc.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/x86/regalloc.py	(original)
+++ pypy/trunk/pypy/jit/backend/x86/regalloc.py	Sun Feb 28 14:15:36 2010
@@ -8,7 +8,6 @@
 from pypy.jit.backend.x86.ri386 import *
 from pypy.rpython.lltypesystem import lltype, ll2ctypes, rffi, rstr
 from pypy.rlib.objectmodel import we_are_translated
-from pypy.rlib.unroll import unrolling_iterable
 from pypy.rlib import rgc
 from pypy.jit.backend.llsupport import symbolic
 from pypy.jit.backend.x86.jump import remap_frame_layout
@@ -656,7 +655,14 @@
         
     def consider_cond_call_gc_wb(self, op):
         assert op.result is None
-        arglocs = [self.loc(arg) for arg in op.args]
+        loc_base = self.rm.make_sure_var_in_reg(op.args[0], op.args,
+                                                imm_fine=False)
+        loc_newvalue = self.rm.make_sure_var_in_reg(op.args[1], op.args,
+                                                    imm_fine=False)
+        # ^^^ we also force loc_newvalue in a reg, because it will be needed
+        # anyway by the following setfield_gc.  It avoids loading it twice
+        # from the memory.
+        arglocs = [loc_base, loc_newvalue]
         # add eax, ecx and edx as extra "arguments" to ensure they are
         # saved and restored.  Fish in self.rm to know which of these
         # registers really need to be saved (a bit of a hack).  Moreover,

Modified: pypy/trunk/pypy/jit/backend/x86/ri386setup.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/x86/ri386setup.py	(original)
+++ pypy/trunk/pypy/jit/backend/x86/ri386setup.py	Sun Feb 28 14:15:36 2010
@@ -444,7 +444,7 @@
 TEST.mode2(EAX,   IMM32, ['\xA9', immediate(2)])
 TEST.mode2(MODRM, IMM32, ['\xF7', orbyte(0<<3), modrm(1), immediate(2)])
 TEST.mode2(AL,    IMM8,  ['\xA8', immediate(2,'b')])
-TEST.mode2(REG8,  IMM8,  ['\xF6', register(1,1,'b'), '\xC0', immediate(2,'b')])
+TEST.mode2(MODRM8,IMM8,  ['\xF6', orbyte(0<<3),modrm(1,'b'), immediate(2,'b')])
 
 INT = Instruction()
 INT.mode1(IMM8, ['\xCD', immediate(1, 'b')])

Modified: pypy/trunk/pypy/jit/metainterp/resoperation.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/resoperation.py	(original)
+++ pypy/trunk/pypy/jit/metainterp/resoperation.py	Sun Feb 28 14:15:36 2010
@@ -220,8 +220,7 @@
     'UNICODESETITEM/3',
     'NEWUNICODE/1',
     'RUNTIMENEW/1',     # ootype operation
-    'COND_CALL_GC_WB',      # [cond, imm_and, if_true_call, args_for_call...]
-                            #        => no result       (for the write barrier)
+    'COND_CALL_GC_WB',  # [objptr, newvalue]   (for the write barrier)
     'DEBUG_MERGE_POINT/1',      # debugging only
     'VIRTUAL_REF_FINISH/2',
 



More information about the Pypy-commit mailing list