Author: Carl Friedrich Bolz <[email protected]>
Branch: guard-compatible
Changeset: r84508:81d72bf4ea82
Date: 2016-05-17 18:22 +0200
http://bitbucket.org/pypy/pypy/changeset/81d72bf4ea82/

Log:    hacky version of how I imagine things might work in the future

        (I really need a different interface to the backend, to be
        discussed)

diff --git a/rpython/jit/backend/llgraph/runner.py 
b/rpython/jit/backend/llgraph/runner.py
--- a/rpython/jit/backend/llgraph/runner.py
+++ b/rpython/jit/backend/llgraph/runner.py
@@ -80,6 +80,7 @@
 
 class Jump(Exception):
     def __init__(self, jump_target, args):
+        assert isinstance(jump_target[0], LLTrace)
         self.jump_target = jump_target
         self.args = args
 
@@ -470,11 +471,18 @@
         assert deadframe._saved_data is not None
         return deadframe._saved_data
 
-    def grow_guard_compatible_switch(self, compiled_loop_token, descr, ref):
+    def grow_guard_compatible_switch(self, compiled_loop_token, descr, ref, 
faildescr_prev=None):
+        assert descr.is_first
         assert isinstance(compiled_loop_token, model.CompiledLoopToken)
         if not hasattr(descr, '_guard_compatible_llgraph_lst'):
             descr._guard_compatible_llgraph_lst = []
-        descr._guard_compatible_llgraph_lst.append(ref)
+        if faildescr_prev is None:
+            target = None
+        else:
+            target = faildescr_prev._llgraph_bridge
+        assert target is None or isinstance(target, LLTrace)
+        descr._guard_compatible_llgraph_lst.append((ref, target))
+        descr._guard_compatible_llgraph_lst.sort()
 
 
     # ------------------------------------------------------------
@@ -1146,18 +1154,22 @@
             values[i] = value
             info = info.next()
 
-    def fail_guard(self, descr, saved_data=None, extra_value=None,
-                   propagate_exception=False):
-        if not propagate_exception:
-            assert self.last_exception is None
+    def _collect_failarg_values(self, descr, current_op):
         values = []
-        for box in self.current_op.getfailargs():
+        for box in current_op.getfailargs():
             if box is not None:
                 value = self.env[box]
             else:
                 value = None
             values.append(value)
-        self._accumulate(descr, self.current_op.getfailargs(), values)
+        self._accumulate(descr, current_op.getfailargs(), values)
+        return values
+
+    def fail_guard(self, descr, saved_data=None, extra_value=None,
+                   propagate_exception=False):
+        if not propagate_exception:
+            assert self.last_exception is None
+        values = self._collect_failarg_values(descr, self.current_op)
         if hasattr(descr, '_llgraph_bridge'):
             if propagate_exception:
                 assert (descr._llgraph_bridge.operations[0].opnum in
@@ -1289,13 +1301,28 @@
             self.fail_guard(descr)
 
     def execute_guard_compatible(self, descr, arg1, arg2):
+        # only need to execute the first operation, the others are checked
+        # implicitly and should never grow
+        # XXX this is a mess and should be done much more nicely
+        if not descr.is_first:
+            return
         if arg1 != arg2:
-            if hasattr(descr, '_guard_compatible_llgraph_lst'):
-                lst = descr._guard_compatible_llgraph_lst
-                for ref in lst:
+            for attempt in range(2):
+                # XXX binary search
+                lst = getattr(descr, '_guard_compatible_llgraph_lst', [])
+                for ref, target in lst:
                     if ref == arg1:
+                        if target:
+                            values = self._collect_failarg_values(descr, 
self.current_op)
+                            target = (target, -1)
+                            values = [value for value in values if value is 
not None]
+                            raise Jump(target, values)
                         return
-            self.fail_guard(descr, extra_value=arg1)
+                assert not attempt == 1
+                worked = descr._try_extend(arg1, self.cpu)
+                if not worked:
+                    return self.fail_guard(descr, extra_value=arg1)
+                # try the above again, it will now work
 
     def execute_int_add_ovf(self, _, x, y):
         try:
diff --git a/rpython/jit/metainterp/compile.py 
b/rpython/jit/metainterp/compile.py
--- a/rpython/jit/metainterp/compile.py
+++ b/rpython/jit/metainterp/compile.py
@@ -800,10 +800,10 @@
             self._debug_subinputargs = new_loop.inputargs
             self._debug_suboperations = new_loop.operations
         propagate_original_jitcell_token(new_loop)
-        send_bridge_to_backend(metainterp.jitdriver_sd, metainterp.staticdata,
-                               self, inputargs, new_loop.operations,
-                               new_loop.original_jitcell_token,
-                               metainterp.box_names_memo)
+        return send_bridge_to_backend(metainterp.jitdriver_sd, 
metainterp.staticdata,
+                                      self, inputargs, new_loop.operations,
+                                      new_loop.original_jitcell_token,
+                                      metainterp.box_names_memo)
 
     def make_a_counter_per_value(self, guard_value_op, index):
         assert guard_value_op.getopnum() in (rop.GUARD_VALUE, 
rop.GUARD_COMPATIBLE)
@@ -1087,23 +1087,32 @@
         # list of descrs about the same variable, potentially shared with
         # subsequent guards in bridges
         self.guard_descrs_list = [self]
+        self.is_first = True
 
-    def handle_fail(self, deadframe, metainterp_sd, jitdriver_sd):
+    def _try_extend(self, refval, cpu):
+        # need to do the checking oldest to newest, to check the most specific
+        # condition first
+        prev = None
+        # grow the switch on the first guard always
+        # all others are useless
+        assert self.is_first
+        for curr in self.guard_descrs_list:
+            if curr.is_compatible(cpu, refval):
+                from rpython.jit.metainterp.blackhole import 
resume_in_blackhole
+                # XXX explain the prev hack
+                cpu.grow_guard_compatible_switch(
+                    self.rd_loop_token, self, refval, prev)
+                return True
+            prev = curr
+        return False
+
+    def Xhandle_fail(self, deadframe, metainterp_sd, jitdriver_sd):
         index = intmask(self.status >> self.ST_SHIFT)
         typetag = intmask(self.status & self.ST_TYPE_MASK)
         assert typetag == self.TY_REF # for now
         refval = metainterp_sd.cpu.get_value_direct(deadframe, 'r', index)
         if not we_are_translated():
             assert self in self.guard_descrs_list
-        # need to do the checking oldest to newest, to check the most specific
-        # condition first
-        for curr in self.guard_descrs_list:
-            if curr.is_compatible(metainterp_sd.cpu, refval):
-                from rpython.jit.metainterp.blackhole import 
resume_in_blackhole
-                metainterp_sd.cpu.grow_guard_compatible_switch(
-                    curr.rd_loop_token, curr, refval)
-                resume_in_blackhole(metainterp_sd, jitdriver_sd, self, 
deadframe)
-                return
         # a real failure
         return ResumeGuardDescr.handle_fail(self, deadframe, metainterp_sd, 
jitdriver_sd)
 
@@ -1123,15 +1132,35 @@
         assert self.failarg_index != -1
         arg = new_loop.inputargs[self.failarg_index]
         firstop = new_loop.operations[0]
+        first = None
         if (firstop.getopnum() == rop.GUARD_COMPATIBLE and
                 firstop.getarg(0) is arg):
-            # a guard_compatible about the same box
-            newdescr = firstop.getdescr()
-            assert isinstance(newdescr, GuardCompatibleDescr)
-            newdescr.guard_descrs_list = self.guard_descrs_list
-            self.guard_descrs_list.append(newdescr)
-        ResumeGuardDescr.compile_and_attach(
+            if new_loop.inputargs != firstop.getfailargs():
+                # this should be true by construction, but let's be sure
+                import pdb; pdb.set_trace()
+            else:
+                # a guard_compatible about the same box
+                newdescr = firstop.getdescr()
+                assert isinstance(newdescr, GuardCompatibleDescr)
+                newdescr.is_first = False
+                # share the guard_descrs_list of the guard_compatibles that
+                # switch on the same object, starting from the same original 
guard
+                guard_descrs_list = newdescr.guard_descrs_list = 
self.guard_descrs_list
+                # this is slightly weird: we fish the last descr, which we
+                # conceptionally attach the trace to (otherwise all traces
+                # would be attached to the first one, which makes no sense)
+                self = guard_descrs_list[-1]
+                guard_descrs_list.append(newdescr)
+                first = self.guard_descrs_list[0]
+        result = ResumeGuardDescr.compile_and_attach(
             self, metainterp, new_loop, orig_inputargs)
+        if first:
+            refval = firstop.getarg(1).getref_base()
+            # grow the first guard to immediately jump to the new place
+            metainterp_sd = metainterp.staticdata
+            metainterp_sd.cpu.grow_guard_compatible_switch(
+                first.rd_loop_token, first, refval, self)
+        return result
 
     def make_a_counter_per_value(self, guard_value_op, index):
         self.failarg_index = guard_value_op.getfailargs().index(
diff --git a/rpython/jit/metainterp/test/test_compatible.py 
b/rpython/jit/metainterp/test/test_compatible.py
--- a/rpython/jit/metainterp/test/test_compatible.py
+++ b/rpython/jit/metainterp/test/test_compatible.py
@@ -14,6 +14,9 @@
 
         p3 = lltype.malloc(S)
         p3.x = 6
+
+        p4 = lltype.malloc(S)
+        p4.x = 6
         driver = jit.JitDriver(greens = [], reds = ['n', 'x'])
 
         class A(object):
@@ -37,13 +40,14 @@
             f(100, p1)
             f(100, p2)
             f(100, p3)
+            f(100, p4)
             return c.count
 
         x = self.meta_interp(main, [])
 
-        assert x < 25
-        # trace, two bridges, a finish bridge
-        self.check_trace_count(4)
+        assert x < 35
+        # trace, two bridges, two finish bridges
+        self.check_trace_count(5)
 
     def test_exception(self):
         S = lltype.GcStruct('S', ('x', lltype.Signed))
@@ -55,6 +59,9 @@
 
         p3 = lltype.malloc(S)
         p3.x = 6
+
+        p4 = lltype.malloc(S)
+        p4.x = 6
         driver = jit.JitDriver(greens = [], reds = ['n', 'x'])
         @jit.elidable_compatible()
         def g(s):
@@ -75,9 +82,11 @@
             f(100, p1)
             f(100, p2)
             f(100, p3)
+            f(100, p4)
 
         self.meta_interp(main, [])
-        # XXX check number of bridges
+        # trace, two bridges, two finish bridges
+        self.check_trace_count(5)
 
 
     def test_quasi_immutable(self):
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to