Author: Carl Friedrich Bolz <cfb...@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) + _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit