[pypy-commit] pypy guard-compatible: chain guard_compatibles to not produce superfluous extra bridges

cfbolz pypy.commits at gmail.com
Sun Mar 20 15:36:49 EDT 2016


Author: Carl Friedrich Bolz <cfbolz at gmx.de>
Branch: guard-compatible
Changeset: r83200:fcc0b6e9d829
Date: 2016-03-20 20:35 +0100
http://bitbucket.org/pypy/pypy/changeset/fcc0b6e9d829/

Log:	chain guard_compatibles to not produce superfluous extra bridges

diff --git a/rpython/jit/metainterp/compatible.py b/rpython/jit/metainterp/compatible.py
--- a/rpython/jit/metainterp/compatible.py
+++ b/rpython/jit/metainterp/compatible.py
@@ -126,7 +126,7 @@
         return True
 
     def same_cond(self, other, res):
-        if type(other) != PureCallCondition:
+        if type(other) is not PureCallCondition:
             return False
         if len(self.args) != len(other.args):
             return False
@@ -189,7 +189,7 @@
         return True
 
     def same_cond(self, other, res):
-        if type(other) != QuasiimmutGetfieldAndPureCallCondition:
+        if type(other) is not QuasiimmutGetfieldAndPureCallCondition:
             return False
         if len(self.args) != len(other.args):
             return False
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
@@ -1088,20 +1088,26 @@
     def __init__(self):
         # XXX think about what is being kept alive here
         self._compatibility_conditions = None
+        self.failarg_index = -1
+        self._prev_guard_compatible_descr = None
 
     def handle_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 self.is_compatible(metainterp_sd.cpu, refval):
-            from rpython.jit.metainterp.blackhole import resume_in_blackhole
-            metainterp_sd.cpu.grow_guard_compatible_switch(
-                self.rd_loop_token, self, refval)
-            resume_in_blackhole(metainterp_sd, jitdriver_sd, self, deadframe)
-        else:
-            # a real failure
-            return ResumeGuardDescr.handle_fail(self, deadframe, metainterp_sd, jitdriver_sd)
+        curr = self
+        while curr:
+            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
+            # try previous guards, maybe one of them would have matched
+            curr = curr._prev_guard_compatible_descr
+        # a real failure
+        return ResumeGuardDescr.handle_fail(self, deadframe, metainterp_sd, jitdriver_sd)
 
     def is_compatible(self, cpu, ref):
         const = history.newconst(ref)
@@ -1112,6 +1118,27 @@
             return False
         return True # no conditions, everything works
 
+    def compile_and_attach(self, metainterp, new_loop, orig_inputargs):
+        # if new_loop starts with another guard_compatible on the same argument
+        # (which is most of the time) we have to connect the new guard's descr
+        # to this descr
+        assert self.failarg_index != -1
+        arg = new_loop.inputargs[self.failarg_index]
+        firstop = new_loop.operations[0]
+        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._prev_guard_compatible_descr = self
+        ResumeGuardDescr.compile_and_attach(
+            self, metainterp, new_loop, orig_inputargs)
+
+    def make_a_counter_per_value(self, guard_value_op, index):
+        self.failarg_index = guard_value_op.getfailargs().index(
+                guard_value_op.getarg(0))
+        ResumeGuardDescr.make_a_counter_per_value(self, guard_value_op, index)
+
 # ____________________________________________________________
 
 memory_error = MemoryError()
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
@@ -42,7 +42,8 @@
         x = self.meta_interp(main, [])
 
         assert x < 25
-        # XXX check number of bridges
+        # trace, two bridges, a finish bridge
+        self.check_trace_count(4)
 
     def test_exception(self):
         S = lltype.GcStruct('S', ('x', lltype.Signed))
@@ -179,3 +180,45 @@
         assert res == 3
         self.check_operations_history(guard_compatible=1)
 
+
+    def test_too_many_bridges(self):
+        S = lltype.GcStruct('S', ('x', lltype.Signed))
+        p1 = lltype.malloc(S)
+        p1.x = 5
+
+        p2 = lltype.malloc(S)
+        p2.x = 5
+
+        p3 = lltype.malloc(S)
+        p3.x = 6
+        driver = jit.JitDriver(greens = [], reds = ['n', 'x'])
+
+        class A(object):
+            pass
+
+        c = A()
+        c.count = 0
+        @jit.elidable_compatible()
+        def g(s, ignored):
+            c.count += 1
+            return s.x
+
+        def f(n, x):
+            while n > 0:
+                driver.can_enter_jit(n=n, x=x)
+                driver.jit_merge_point(n=n, x=x)
+                n -= g(x, 7)
+
+        def main():
+            g(p1, 9) # make annotator not make argument constant
+            f(100, p1)
+            f(100, p3) # not compatible, so make a bridge
+            f(100, p2) # compatible with loop again, too bad
+            return c.count
+
+        x = self.meta_interp(main, [])
+
+        assert x < 30
+        # trace, two bridges, a finish bridge
+        self.check_trace_count(4)
+


More information about the pypy-commit mailing list