Commits

Remi Meier committed 195b15f

revert changes to assembler.py and start support of transaction breaks in optimizeopt

Comments (0)

Files changed (9)

rpython/jit/backend/x86/assembler.py

             return     # tests only
 
         mc = self.mc
+        # if stm_should_break_transaction()
+        fn = stmtlocal.stm_should_break_transaction_fn
+        mc.CALL(imm(self.cpu.cast_ptr_to_int(fn)))
+        mc.TEST8(eax.lowest8bits(), eax.lowest8bits())
+        mc.J_il(rx86.Conditions['Z'], 0xfffff)    # patched later
+        jz_location2 = mc.get_relative_pos()
         #
         # call stm_transaction_break() with the address of the
         # STM_RESUME_BUF and the custom longjmp function
         self.push_gcmap(mc, gcmap, mov=True)
         #
+        # save all registers
+        base_ofs = self.cpu.get_baseofs_of_frame_field()
+        for gpr in self._regalloc.rm.reg_bindings.values():
+            v = gpr_reg_mgr_cls.all_reg_indexes[gpr.value]
+            mc.MOV_br(v * WORD + base_ofs, gpr.value)
+        if IS_X86_64:
+            coeff = 1
+        else:
+            coeff = 2
+        ofs = len(gpr_reg_mgr_cls.all_regs)
+        for xr in self._regalloc.xrm.reg_bindings.values():
+            mc.MOVSD_bx((ofs + xr.value * coeff) * WORD + base_ofs, xr.value)
+        #
         # CALL break function
         fn = self.stm_transaction_break_path
         mc.CALL(imm(fn))
         # ** HERE ** is the place an aborted transaction retries
         # ebp/frame reloaded by longjmp callback
         #
+        # restore regs
+        base_ofs = self.cpu.get_baseofs_of_frame_field()
+        for gpr in self._regalloc.rm.reg_bindings.values():
+            v = gpr_reg_mgr_cls.all_reg_indexes[gpr.value]
+            mc.MOV_rb(gpr.value, v * WORD + base_ofs)
+        if IS_X86_64:
+            coeff = 1
+        else:
+            coeff = 2
+        ofs = len(gpr_reg_mgr_cls.all_regs)
+        for xr in self._regalloc.xrm.reg_bindings.values():
+            mc.MOVSD_xb(xr.value, (ofs + xr.value * coeff) * WORD + base_ofs)
+        #
+        # patch the JZ above
+        offset = mc.get_relative_pos() - jz_location2
+        mc.overwrite32(jz_location2-4, offset)
 
 
 

rpython/jit/backend/x86/regalloc.py

     def consider_stm_transaction_break(self, op):
         #
         # only save regs for the should_break_transaction call
-        self.xrm.before_call(save_all_regs=1)
-        self.rm.before_call(save_all_regs=1)
+        self.xrm.before_call()
+        self.rm.before_call()
         gcmap = self.get_gcmap() # allocate the gcmap *before*
         #
         self.assembler.stm_transaction_break(gcmap)

rpython/jit/codewriter/jtransform.py

         arg = int(op.args[0].value)
         c_arg = Constant(arg, lltype.Signed)
 
-        return SpaceOperation('stm_should_break_transaction',
-                              [c_arg], op.result)
+        return [SpaceOperation('stm_should_break_transaction',
+                               [c_arg], op.result),
+                SpaceOperation('-live-', [], None),]
 
     def rewrite_op_jit_stm_transaction_break_point(self, op):
-        return SpaceOperation('stm_transaction_break', [], op.result)
+        return [SpaceOperation('stm_transaction_break', [], op.result),
+                SpaceOperation('-live-', [], None),]
     
     def rewrite_op_jit_marker(self, op):
         key = op.args[0].value

rpython/jit/metainterp/optimizeopt/__init__.py

 from rpython.jit.metainterp.optimizeopt.simplify import OptSimplify
 from rpython.jit.metainterp.optimizeopt.pure import OptPure
 from rpython.jit.metainterp.optimizeopt.earlyforce import OptEarlyForce
+from rpython.jit.metainterp.optimizeopt.stm import OptSTM
 from rpython.rlib.jit import PARAMETERS, ENABLE_ALL_OPTS
 from rpython.rlib.unroll import unrolling_iterable
 from rpython.rlib.debug import debug_start, debug_stop, debug_print
     config = metainterp_sd.config
     optimizations = []
     unroll = 'unroll' in enable_opts    # 'enable_opts' is normally a dict
+    if config.translation.stm:
+        optimizations.append(OptSTM())
+        
     for name, opt in unroll_all_opts:
         if name in enable_opts:
             if opt is not None:

rpython/jit/metainterp/optimizeopt/stm.py

+from rpython.jit.metainterp.history import (Const, ConstInt, BoxInt, BoxFloat,
+    BoxPtr, make_hashable_int)
+from rpython.jit.metainterp.optimizeopt.optimizer import (Optimization, REMOVED,
+    CONST_0, CONST_1)
+from rpython.jit.metainterp.optimizeopt.util import make_dispatcher_method
+from rpython.jit.metainterp.resoperation import (opboolinvers, opboolreflex, rop,
+    ResOperation)
+
+
+class OptSTM(Optimization):
+    """
+    For now only changes some guarded transaction breaks
+    to unconditional ones.
+    """
+    def __init__(self):
+        pass
+    
+    def new(self):
+        return OptSTM()
+
+    def propagate_forward(self, op):
+        dispatch_opt(self, op)
+        
+    def optimize_CALL(self, op):
+        self.emit_operation(op)
+
+    def optimize_STM_TRANSACTION_BREAK(self, op):
+        self.emit_operation(op)
+
+dispatch_opt = make_dispatcher_method(OptSTM, 'optimize_',
+                                      default=OptSTM.emit_operation)
+
+
+
+
+

rpython/jit/metainterp/optimizeopt/test/test_stm.py

+from rpython.jit.metainterp.optimizeopt.test.test_optimizebasic import (
+    BaseTestBasic,)
+from rpython.jit.metainterp.optimizeopt.test.test_util import LLtypeMixin
+
+
+
+
+class BaseTestSTM(BaseTestBasic):
+    stm = True
+    
+    def test_simple(self):
+        ops = """
+        []
+        stm_transaction_break()
+        guard_not_forced() []
+        jump()
+        """
+        expected = ops
+        self.optimize_loop(ops, expected)
+
+
+
+class TestLLtype(BaseTestSTM, LLtypeMixin):
+    pass
+
+

rpython/jit/metainterp/optimizeopt/test/test_util.py

             metainterp_sd.virtualref_info = self.vrefinfo
         if hasattr(self, 'callinfocollection'):
             metainterp_sd.callinfocollection = self.callinfocollection
+        if hasattr(self, 'stm'):
+            metainterp_sd.config.translation.stm = self.stm
         #
         optimize_trace(metainterp_sd, loop, self.enable_opts)
 

rpython/jit/metainterp/pyjitpl.py

             raise AssertionError("bad result box type")
 
     # ------------------------------
+    def _record_stm_transaction_break(self):
+        # records an unconditional stm_transaction_break
+        mi = self.metainterp
+        mi.vable_and_vrefs_before_residual_call()
+        mi._record_helper_nonpure_varargs(
+            rop.STM_TRANSACTION_BREAK, None, None, [])
+        mi.vrefs_after_residual_call()
+        mi.vable_after_residual_call()
+        mi.generate_guard(rop.GUARD_NOT_FORCED, None)
+        
+    
     @arguments("int")
     def opimpl_stm_should_break_transaction(self, if_there_is_no_other):
         val = bool(if_there_is_no_other)
         mi = self.metainterp
-        if (mi.stm_break_wanted or (val and not mi.stm_break_done)):
-            mi.stm_break_done = True
+        if mi.stm_break_wanted:
+            # after call_release_gil and similar we want to have
+            # stm_transaction_break that may disable optimizations,
+            # but they would have been disabled anyways by the call
+            self._record_stm_transaction_break()
             mi.stm_break_wanted = False
-            # insert a CALL
+            return ConstInt(0)
+        elif val:
+            # Never ignore these. As long as we don't track the info
+            # if we are atomic, this could be the only possible
+            # transaction break in the loop (they are the most
+            # likely ones):
+            # loop: stmts -> inc_atomic -> stmts -> dec_atomic ->
+            #       transaction_break -> loop_end
+            #
+            # we insert:
+            #   i0 = call(should_break_transaction)
+            #     stm_transaction_break()
+            #     guard_not_forced()
+            #   guard_false(i0)
+            #
+            # the stm_transaction_break() and its guard,
+            #   OR
+            # the call(should_break_transaction) and its guard,
+            # or both are going to be removed by optimizeopt
             resbox = history.BoxInt(0)
             funcptr = mi.staticdata.stm_should_break_transaction
             funcdescr = mi.staticdata.stm_should_break_transaction_descr
             mi._record_helper_nonpure_varargs(
                 rop.CALL, resbox, funcdescr,
                 [ConstInt(heaptracker.adr2int(funcaddr)),])
+            #
+            # ALSO generate an stm_transaction_break
+            # This is needed to be able to transform the guard
+            # into an unconditional TB during optimizeopt
+            # if wanted...
+            self._record_stm_transaction_break()
+            #
             return resbox
         else:
+            # we ignore this one.
             return ConstInt(0)
 
     @arguments()
     def opimpl_stm_transaction_break(self):
-        self.metainterp._record_helper_nonpure_varargs(
-            rop.STM_TRANSACTION_BREAK, None, None, [])
+        self._record_stm_transaction_break()
     
     for _opimpl in ['int_add', 'int_sub', 'int_mul', 'int_floordiv', 'int_mod',
                     'int_lt', 'int_le', 'int_eq',
 
         # for stm: placement of stm_break_point, used by MIFrame
         self.stm_break_wanted = False
-        self.stm_break_done = False
+        self.stm_insert_first_break = True
 
         
 

rpython/jit/metainterp/test/test_stm.py

             return rstm.jit_stm_should_break_transaction(False)
         res = self.interp_operations(g, [], translationoptions={"stm":True})
         assert res == False
-        self.check_operations_history(call=1, call_may_force=1)
+        self.check_operations_history(stm_transaction_break=1, call_may_force=1)
+
+    def test_not_removed2(self):
+        def g():
+            return rstm.jit_stm_should_break_transaction(True)
+        res = self.interp_operations(g, [], translationoptions={"stm":True})
+        assert res == False
+        self.check_operations_history(call=1, stm_transaction_break=1)
 
     def test_transaction_break(self):
         def g():
             rstm.jit_stm_transaction_break_point()
             return 42
         self.interp_operations(g, [], translationoptions={"stm":True})
-        self.check_operations_history({'stm_transaction_break':1})
+        self.check_operations_history({'stm_transaction_break':1,
+                                       'guard_not_forced':1})