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