[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