[pypy-commit] pypy jit-usable_retrace_3: a third athempt at generalizing retraces enough to make them useable
hakanardo
noreply at buildbot.pypy.org
Wed Sep 5 17:06:41 CEST 2012
Author: Hakan Ardo <hakan at debian.org>
Branch: jit-usable_retrace_3
Changeset: r57147:120455cfb1d3
Date: 2012-09-05 17:04 +0200
http://bitbucket.org/pypy/pypy/changeset/120455cfb1d3/
Log: a third athempt at generalizing retraces enough to make them useable
diff --git a/pypy/jit/metainterp/compile.py b/pypy/jit/metainterp/compile.py
--- a/pypy/jit/metainterp/compile.py
+++ b/pypy/jit/metainterp/compile.py
@@ -192,50 +192,72 @@
loop_jitcell_token = metainterp.get_procedure_token(greenkey)
assert loop_jitcell_token
assert partial_trace.operations[-1].getopnum() == rop.LABEL
-
- part = create_empty_loop(metainterp)
- part.inputargs = inputargs[:]
- part.resume_at_jump_descr = resume_at_jump_descr
+ orignial_label = partial_trace.operations[-1].clone()
h_ops = history.operations
- part.operations = [partial_trace.operations[-1]] + \
- [h_ops[i].clone() for i in range(start, len(h_ops))] + \
- [ResOperation(rop.JUMP, jumpargs, None, descr=loop_jitcell_token)]
- label = part.operations[0]
- orignial_label = label.clone()
- assert label.getopnum() == rop.LABEL
+ preamble = create_empty_loop(metainterp)
+ loop = create_empty_loop(metainterp)
try:
- optimize_trace(metainterp_sd, part, jitdriver_sd.warmstate.enable_opts)
+ preamble.inputargs = inputargs[:]
+ preamble.resume_at_jump_descr = resume_at_jump_descr
+ preamble.operations = [partial_trace.operations[-1]] + \
+ [h_ops[i].clone() for i in range(start, len(h_ops))] + \
+ [ResOperation(rop.LABEL, jumpargs, None, descr=loop_jitcell_token)]
+ optimize_trace(metainterp_sd, preamble, jitdriver_sd.warmstate.enable_opts)
+
+ label = preamble.operations[-1]
+ assert label.getopnum() == rop.LABEL
+ label.getdescr().exported_state.generalize_virtual_state = \
+ preamble.operations[0].getdescr().virtual_state
+
+ loop.inputargs = inputargs[:]
+ loop.resume_at_jump_descr = resume_at_jump_descr
+ inliner = Inliner(inputargs, jumpargs)
+ loop.operations = [label] + \
+ [inliner.inline_op(h_ops[i]) for i in range(start, len(h_ops))] + \
+ [ResOperation(rop.JUMP, [inliner.inline_arg(a) for a in jumpargs],
+ None, descr=loop_jitcell_token)]
+ optimize_trace(metainterp_sd, loop, jitdriver_sd.warmstate.enable_opts)
+
+ preamble.operations = preamble.operations[:-1]
+
except InvalidLoop:
# Fall back on jumping to preamble
target_token = label.getdescr()
assert isinstance(target_token, TargetToken)
assert target_token.exported_state
- part.operations = [orignial_label] + \
- [ResOperation(rop.JUMP, inputargs[:],
- None, descr=loop_jitcell_token)]
+ target_token.exported_state.generalize_virtual_state = None
+ # FIXME: Test
+ preamble.operations = [orignial_label] + \
+ [ResOperation(rop.JUMP, inputargs[:],
+ None, descr=loop_jitcell_token)]
+ loop.operations = []
try:
- optimize_trace(metainterp_sd, part, jitdriver_sd.warmstate.enable_opts,
+ optimize_trace(metainterp_sd, preamble, jitdriver_sd.warmstate.enable_opts,
inline_short_preamble=False)
except InvalidLoop:
return None
- assert part.operations[-1].getopnum() != rop.LABEL
+
+ trace = partial_trace
+ trace.operations = partial_trace.operations[:-1] + preamble.operations + loop.operations
+ loop = trace # FIXME: rename
+
+ assert loop.operations[-1].getopnum() != rop.LABEL
target_token = label.getdescr()
assert isinstance(target_token, TargetToken)
assert loop_jitcell_token.target_tokens
- loop_jitcell_token.target_tokens.append(target_token)
+ loop_jitcell_token.target_tokens.append(target_token) # FIXME: register all labels
if target_token.short_preamble:
metainterp_sd.logger_ops.log_short_preamble([], target_token.short_preamble)
- loop = partial_trace
- loop.operations = loop.operations[:-1] + part.operations
quasi_immutable_deps = {}
if loop.quasi_immutable_deps:
quasi_immutable_deps.update(loop.quasi_immutable_deps)
- if part.quasi_immutable_deps:
- quasi_immutable_deps.update(part.quasi_immutable_deps)
+ # FIXME
+ #if part.quasi_immutable_deps:
+ # quasi_immutable_deps.update(part.quasi_immutable_deps)
if quasi_immutable_deps:
loop.quasi_immutable_deps = quasi_immutable_deps
diff --git a/pypy/jit/metainterp/history.py b/pypy/jit/metainterp/history.py
--- a/pypy/jit/metainterp/history.py
+++ b/pypy/jit/metainterp/history.py
@@ -1013,19 +1013,43 @@
loops = self.get_all_loops()
assert len(loops) == 1
loop = loops[0]
- jumpop = loop.operations[-1]
+ insns = self.sum_simple_loop(loop.operations, insns)
+ return self._check_insns(insns, expected, check)
+
+ def sum_simple_loop(self, operations, insns=None):
+ if insns is None:
+ insns = {}
+ jumpop = operations[-1]
assert jumpop.getopnum() == rop.JUMP
- labels = [op for op in loop.operations if op.getopnum() == rop.LABEL]
+ labels = [op for op in operations if op.getopnum() == rop.LABEL]
targets = [op._descr_wref() for op in labels]
assert None not in targets # TargetToken was freed, give up
target = jumpop._descr_wref()
assert target
assert targets.count(target) == 1
- i = loop.operations.index(labels[targets.index(target)])
- insns = {}
- for op in loop.operations[i:]:
+ i = operations.index(labels[targets.index(target)])
+ for op in operations[i:]:
opname = op.getopname()
insns[opname] = insns.get(opname, 0) + 1
+ return insns
+
+ def check_retraced_simple_loop(self, count, expected=None, **check):
+ """ Similar to check_simple_loop, but will also count ops found in retraces
+ located within the bridges found.
+ """
+ insns = {}
+ worklist = [loop.operations for loop in self.get_all_loops()]
+ simple_loops = 0
+ while worklist:
+ operations = worklist.pop()
+ if len([1 for op in operations if op.getopnum() == rop.LABEL]) > 0:
+ self.sum_simple_loop(operations, insns)
+ simple_loops += 1
+ for op in operations:
+ if op.is_guard() and op.getdescr():
+ if hasattr(op.getdescr(), '_debug_suboperations'):
+ worklist.append(op.getdescr()._debug_suboperations)
+ assert simple_loops == count
return self._check_insns(insns, expected, check)
def check_loops(self, expected=None, everywhere=False, **check):
diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py
--- a/pypy/jit/metainterp/optimizeopt/unroll.py
+++ b/pypy/jit/metainterp/optimizeopt/unroll.py
@@ -211,7 +211,7 @@
exported_values[box] = self.optimizer.getvalue(box)
target_token.exported_state = ExportedState(short_boxes, inputarg_setup_ops,
- exported_values)
+ exported_values, jump_args)
def import_state(self, targetop):
if not targetop: # Trace did not start with a label
@@ -279,6 +279,28 @@
self.optimizer.flush()
self.optimizer.emitting_dissabled = False
+ if exported_state.generalize_virtual_state:
+ # XXX: Hack
+ # FIXME: Rearange stuff to emit label after this (but prior to inputarg_setup_ops)?
+ assert self.optimizer._newoperations[0].getopnum() == rop.LABEL
+ del self.optimizer._newoperations[0]
+
+ virtual_state = self.initial_virtual_state
+ values = [self.getvalue(arg) for arg in exported_state.jump_args]
+ virtual_state = virtual_state.make_generalization_of(exported_state.generalize_virtual_state,
+ exported_state.jump_args,
+ self.optimizer)
+ values = [self.getvalue(arg) for arg in exported_state.jump_args]
+ self.initial_virtual_state = virtual_state
+ inputargs = virtual_state.make_inputargs(values, self.optimizer)
+ target_token.virtual_state = virtual_state
+ op = ResOperation(rop.LABEL, inputargs, None, descr=target_token)
+ self.optimizer._newoperations.append(op)
+ self.inputargs = inputargs
+ short_inputargs = virtual_state.make_inputargs(values, self.optimizer, keyboxes=True)
+ self.short[0] = ResOperation(rop.LABEL, short_inputargs, None)
+
+
def close_bridge(self, start_label):
inputargs = self.inputargs
short_jumpargs = inputargs[:]
@@ -625,7 +647,9 @@
self.unroll.add_op_to_short(self.op, False, True)
class ExportedState(object):
- def __init__(self, short_boxes, inputarg_setup_ops, exported_values):
+ def __init__(self, short_boxes, inputarg_setup_ops, exported_values, jump_args):
self.short_boxes = short_boxes
self.inputarg_setup_ops = inputarg_setup_ops
self.exported_values = exported_values
+ self.jump_args = jump_args
+ self.generalize_virtual_state = None
diff --git a/pypy/jit/metainterp/optimizeopt/virtualstate.py b/pypy/jit/metainterp/optimizeopt/virtualstate.py
--- a/pypy/jit/metainterp/optimizeopt/virtualstate.py
+++ b/pypy/jit/metainterp/optimizeopt/virtualstate.py
@@ -23,6 +23,9 @@
def generalization_of(self, other, renum, bad):
raise NotImplementedError
+ def make_generalization_of(self, other, value, optimizer):
+ pass
+
def generate_guards(self, other, box, cpu, extra_guards, renum):
if self.generalization_of(other, renum, {}):
return
@@ -106,6 +109,28 @@
return True
+ def make_generalization_of(self, other, value, optimizer):
+ if not self._generalization_of(other):
+ raise InvalidLoop
+ assert isinstance(other, AbstractVirtualStructStateInfo)
+ assert len(self.fielddescrs) == len(self.fieldstate)
+ assert len(other.fielddescrs) == len(other.fieldstate)
+ assert isinstance(value, virtualize.AbstractVirtualStructValue)
+ if len(self.fielddescrs) != len(other.fielddescrs):
+ raise InvalidLoop
+ for i in range(len(self.fielddescrs)):
+ if other.fielddescrs[i] is not self.fielddescrs[i]:
+ raise InvalidLoop
+ new_field_value = self.fieldstate[i].make_generalization_of(other.fieldstate[i],
+ value.getfield(self.fielddescrs[i], None),
+ optimizer)
+ if new_field_value:
+ value.setfield(self.fielddescrs[i], new_field_value)
+ #FIXME: default value of getfield
+
+
+
+
def _generalization_of(self, other):
raise NotImplementedError
@@ -349,6 +374,23 @@
return False
return True
+ def make_generalization_of(self, other, value, optimizer):
+ if not self.generalization_of(other, {}, {}):
+ box = value.get_key_box()
+ try:
+ self._generate_guards(other, box, optimizer.cpu, [])
+ return # It is enough if we can generate guards to make states compatibe, FIXME: rename method
+ except InvalidLoop:
+ pass
+ if value.is_constant():
+ op = ResOperation(rop.SAME_AS, [box], box.clonebox())
+ optimizer._newoperations.append(op)
+ return optimizer.getvalue(op.result)
+ else:
+ v = OptValue(box)
+ optimizer.make_equal_to(box, v, True)
+ return v
+
def _generate_guards(self, other, box, cpu, extra_guards):
if not isinstance(other, NotVirtualStateInfo):
raise InvalidLoop('The VirtualStates does not match as a ' +
@@ -476,6 +518,22 @@
return False
return True
+ def make_generalization_of(self, other, jumpargs, optimizer):
+ assert len(self.state) == len(other.state) == len(jumpargs)
+ values = [optimizer.getvalue(arg) for arg in jumpargs]
+ for i in range(len(self.state)):
+ new_value = self.state[i].make_generalization_of(other.state[i], values[i], optimizer)
+ if new_value:
+ optimizer.make_equal_to(jumpargs[i], new_value, True)
+
+ modifier = VirtualStateAdder(optimizer)
+ virtual_state = modifier.get_virtual_state(jumpargs)
+
+ # Only a few cases currently implemenetd, so we need to check if we succeeded
+ virtual_state.generate_guards(other, jumpargs, optimizer.cpu, []) # Will raise if not possible
+ virtual_state.generate_guards(self, jumpargs, optimizer.cpu, []) # Will raise if not possible
+ return virtual_state
+
def generate_guards(self, other, args, cpu, extra_guards):
assert len(self.state) == len(other.state) == len(args)
renum = {}
diff --git a/pypy/jit/metainterp/test/support.py b/pypy/jit/metainterp/test/support.py
--- a/pypy/jit/metainterp/test/support.py
+++ b/pypy/jit/metainterp/test/support.py
@@ -159,6 +159,9 @@
get_stats().check_resops(expected=expected, **check)
def check_simple_loop(self, expected=None, **check):
get_stats().check_simple_loop(expected=expected, **check)
+ def check_retraced_simple_loop(self, count, expected=None, **check):
+ get_stats().check_retraced_simple_loop(count, expected=expected, **check)
+
diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py
--- a/pypy/jit/metainterp/test/test_ajit.py
+++ b/pypy/jit/metainterp/test/test_ajit.py
@@ -3022,6 +3022,50 @@
res = self.meta_interp(f, [32])
assert res == f(32)
+ def test_nested_loops(self):
+ class Int(object):
+ def __init__(self, val):
+ self.val = val
+ bytecode = "iajb+JI"
+ def get_printable_location(i):
+ return "%d: %s" % (i, bytecode[i])
+ myjitdriver = JitDriver(greens = ['pc'], reds = ['n', 'sa', 'c', 'i', 'j'],
+ get_printable_location=get_printable_location)
+ def f(n):
+ pc = sa = 0
+ i = j = Int(0)
+ c = Int(n)
+ while pc < len(bytecode):
+ myjitdriver.jit_merge_point(pc=pc, n=n, sa=sa, i=i, j=j, c=c)
+ op = bytecode[pc]
+ if op == 'i':
+ i = Int(1)
+ elif op == 'j':
+ j = Int(1) # FIXME: test with 0 aswell
+ elif op == '+':
+ sa += 3 * i.val + j.val + 5 * c.val
+ elif op == 'a':
+ i = Int(i.val + 1)
+ elif op == 'b':
+ j = Int(j.val + 1)
+ elif op == 'J':
+ if j.val < n:
+ pc -= 2
+ myjitdriver.can_enter_jit(pc=pc, n=n, sa=sa, i=i, j=j, c=c)
+ continue
+ elif op == 'I':
+ if i.val < n:
+ pc -= 5
+ myjitdriver.can_enter_jit(pc=pc, n=n, sa=sa, i=i, j=j, c=c)
+ continue
+ pc += 1
+ return sa
+ res = self.meta_interp(f, [10])
+ assert res == f(10)
+ self.check_resops(new_with_vtable=0)
+ self.check_retraced_simple_loop(2, getfield_gc=0)
+
+
class TestOOtype(BasicTests, OOJitMixin):
More information about the pypy-commit
mailing list