Author: Hakan Ardo <ha...@debian.org> Branch: jit-targets Changeset: r48763:9ef690e84b21 Date: 2011-11-04 21:14 +0100 http://bitbucket.org/pypy/pypy/changeset/9ef690e84b21/
Log: refactor unrolling to use the new target resop 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 @@ -766,10 +766,10 @@ self.compiled_loop_token.cpu.dump_loop_token(self) class TargetToken(AbstractDescr): - pass + def __init__(self): + self.exported_state = None class TreeLoop(object): - inputargs = None operations = None token = None call_pure_results = None @@ -778,11 +778,24 @@ def __init__(self, name): self.name = name - # self.inputargs = list of distinct Boxes # self.operations = list of ResOperations # ops of the kind 'guard_xxx' contain a further list of operations, # which may itself contain 'guard_xxx' and so on, making a tree. + _inputargs = None + + def get_inputargs(self): + "NOT_RPYTHON" + if self._inputargs is not None: + return self._inputargs + assert self.operations[0].getopnum() == rop.TARGET + return self.operations[0].getarglist() + + def set_inputargs(self, inputargs): + self._inputargs = inputargs + + inputargs = property(get_inputargs, set_inputargs) + def _all_operations(self, omit_finish=False): "NOT_RPYTHON" result = [] @@ -801,7 +814,7 @@ return self.operations def get_display_text(self): # for graphpage.py - return self.name + '\n' + repr(self.inputargs) + return self.name def show(self, errmsg=None): "NOT_RPYTHON" @@ -810,15 +823,13 @@ def check_consistency(self): # for testing "NOT_RPYTHON" - self.check_consistency_of(self.inputargs, self.operations) + self.check_consistency_of(self.operations) @staticmethod - def check_consistency_of(inputargs, operations): - for box in inputargs: - assert isinstance(box, Box), "Loop.inputargs contains %r" % (box,) + def check_consistency_of(operations): + assert operations[0].getopnum() == rop.TARGET + inputargs = operations[0].getarglist() seen = dict.fromkeys(inputargs) - assert len(seen) == len(inputargs), ( - "duplicate Box in the Loop.inputargs") TreeLoop.check_consistency_of_branch(operations, seen) @staticmethod @@ -845,6 +856,14 @@ assert isinstance(box, Box) assert box not in seen seen[box] = True + if op.getopnum() == rop.TARGET: + inputargs = op.getarglist() + for box in inputargs: + assert isinstance(box, Box), "TARGET contains %r" % (box,) + seen = dict.fromkeys(inputargs) + assert len(seen) == len(inputargs), ( + "duplicate Box in the TARGET arguments") + assert operations[-1].is_final() if operations[-1].getopnum() == rop.JUMP: target = operations[-1].getdescr() @@ -853,7 +872,7 @@ def dump(self): # RPython-friendly - print '%r: inputargs =' % self, self._dump_args(self.inputargs) + print '%r: ' % self for op in self.operations: args = op.getarglist() print '\t', op.getopname(), self._dump_args(args), \ diff --git a/pypy/jit/metainterp/optimizeopt/__init__.py b/pypy/jit/metainterp/optimizeopt/__init__.py --- a/pypy/jit/metainterp/optimizeopt/__init__.py +++ b/pypy/jit/metainterp/optimizeopt/__init__.py @@ -80,3 +80,14 @@ if __name__ == '__main__': print ALL_OPTS_NAMES + +def optimize_trace(metainterp_sd, loop, enable_opts): + """Optimize loop.operations to remove internal overheadish operations. + """ + + optimizations, unroll = build_opt_chain(metainterp_sd, enable_opts, False, False) + if unroll: + optimize_unroll(metainterp_sd, loop, optimizations) + else: + optimizer = Optimizer(metainterp_sd, loop, optimizations, bridge) + optimizer.propagate_all_forward() diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py --- a/pypy/jit/metainterp/optimizeopt/optimizer.py +++ b/pypy/jit/metainterp/optimizeopt/optimizer.py @@ -497,9 +497,10 @@ else: return CVAL_ZERO - def propagate_all_forward(self): + def propagate_all_forward(self, clear=True): self.exception_might_have_happened = self.bridge - self.clear_newoperations() + if clear: + self.clear_newoperations() for op in self.loop.operations: self.first_optimization.propagate_forward(op) self.loop.operations = self.get_newoperations() @@ -556,6 +557,7 @@ def store_final_boxes_in_guard(self, op): descr = op.getdescr() + print 'HHHHHHHHHHHH', descr, id(descr) assert isinstance(descr, compile.ResumeGuardDescr) modifier = resume.ResumeDataVirtualAdder(descr, self.resumedata_memo) newboxes = modifier.finish(self.values, self.pendingfields) diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -7,7 +7,7 @@ from pypy.jit.metainterp.optimizeopt import optimize_loop_1, ALL_OPTS_DICT, build_opt_chain from pypy.jit.metainterp.optimize import InvalidLoop from pypy.jit.metainterp.history import AbstractDescr, ConstInt, BoxInt -from pypy.jit.metainterp.history import TreeLoop, LoopToken +from pypy.jit.metainterp.history import TreeLoop, LoopToken, TargetToken from pypy.jit.metainterp.jitprof import EmptyProfiler from pypy.jit.metainterp import executor, compile, resume, history from pypy.jit.metainterp.resoperation import rop, opname, ResOperation @@ -15,7 +15,7 @@ from pypy.jit.metainterp.optimizeopt.util import args_dict from pypy.jit.metainterp.optimizeopt.test.test_optimizebasic import FakeMetaInterpStaticData from pypy.config.pypyoption import get_pypy_config - +from pypy.jit.metainterp.optimizeopt.unroll import Inliner def test_build_opt_chain(): def check(chain, expected_names): @@ -79,43 +79,83 @@ expected_preamble = self.parse(expected_preamble) if expected_short: expected_short = self.parse(expected_short) - loop.preamble = TreeLoop('preamble') - loop.preamble.inputargs = loop.inputargs - loop.preamble.token = LoopToken() - loop.preamble.start_resumedescr = FakeDescr() - # + operations = loop.operations + cloned_operations = [op.clone() for op in operations] + + preamble = TreeLoop('preamble') + #loop.preamble.inputargs = loop.inputargs + #loop.preamble.token = LoopToken() + preamble.start_resumedescr = FakeDescr() + assert operations[-1].getopnum() == rop.JUMP + inputargs = loop.inputargs + jump_args = operations[-1].getarglist() + targettoken = TargetToken() + operations[-1].setdescr(targettoken) + cloned_operations[-1].setdescr(targettoken) + preamble.operations = [ResOperation(rop.TARGET, inputargs, None, descr=TargetToken())] + \ + operations[:-1] + \ + [ResOperation(rop.TARGET, jump_args, None, descr=targettoken)] + self._do_optimize_loop(preamble, call_pure_results) + + jump_args = preamble.operations[-1].getdescr().exported_state.jump_args # FIXME!! + inliner = Inliner(inputargs, jump_args) + loop.inputargs = None + loop.start_resumedescr = preamble.start_resumedescr + loop.operations = [preamble.operations[-1]] + \ + [inliner.inline_op(op, clone=False) for op in cloned_operations] self._do_optimize_loop(loop, call_pure_results) + extra_same_as = [] + while loop.operations[0].getopnum() != rop.TARGET: + extra_same_as.append(loop.operations[0]) + del loop.operations[0] + + # Hack to prevent random order of same_as ops + extra_same_as.sort(key=lambda op: str(preamble.operations).find(str(op.getarg(0)))) + + for op in extra_same_as: + preamble.operations.insert(-1, op) + # print print "Preamble:" - print loop.preamble.inputargs - if loop.preamble.operations: - print '\n'.join([str(o) for o in loop.preamble.operations]) + if preamble.operations: + print '\n'.join([str(o) for o in preamble.operations]) else: print 'Failed!' print print "Loop:" - print loop.inputargs print '\n'.join([str(o) for o in loop.operations]) print if expected_short: print "Short Preamble:" - short = loop.preamble.token.short_preamble[0] + short = loop.token.short_preamble[0] print short.inputargs print '\n'.join([str(o) for o in short.operations]) print assert expected != "crash!", "should have raised an exception" - self.assert_equal(loop, expected) + self.assert_equal(loop, convert_old_style_to_targets(expected, jump=True)) + assert loop.operations[0].getdescr() == loop.operations[-1].getdescr() if expected_preamble: - self.assert_equal(loop.preamble, expected_preamble, + self.assert_equal(preamble, convert_old_style_to_targets(expected_preamble, jump=False), text_right='expected preamble') + assert preamble.operations[-1].getdescr() == loop.operations[0].getdescr() if expected_short: - self.assert_equal(short, expected_short, + self.assert_equal(short, convert_old_style_to_targets(expected_short, jump=True), text_right='expected short preamble') + assert short.operations[-1].getdescr() == loop.operations[0].getdescr() return loop +def convert_old_style_to_targets(loop, jump): + newloop = TreeLoop(loop.name) + newloop.operations = [ResOperation(rop.TARGET, loop.inputargs, None, descr=FakeDescr())] + \ + loop.operations + if not jump: + assert newloop.operations[-1].getopnum() == rop.JUMP + newloop.operations[-1] = ResOperation(rop.TARGET, newloop.operations[-1].getarglist(), None, descr=FakeDescr()) + return newloop + class OptimizeOptTest(BaseTestWithUnroll): def setup_method(self, meth=None): @@ -234,7 +274,7 @@ """ % expected_value self.optimize_loop(ops, expected) - def test_reverse_of_cast(self): + def test_reverse_of_cast_1(self): ops = """ [i0] p0 = cast_int_to_ptr(i0) @@ -246,6 +286,8 @@ jump(i0) """ self.optimize_loop(ops, expected) + + def test_reverse_of_cast_2(self): ops = """ [p0] i1 = cast_ptr_to_int(p0) @@ -1166,6 +1208,7 @@ i1 = getfield_gc(p0, descr=valuedescr) i2 = int_sub(i1, 1) i3 = int_add(i0, i1) + i4 = same_as(i2) # This same_as should be killed by backend jump(i3, i2, i1) """ expected = """ @@ -1233,6 +1276,7 @@ p30 = new_with_vtable(ConstClass(node_vtable)) setfield_gc(p30, i28, descr=nextdescr) setfield_gc(p3, p30, descr=valuedescr) + p46 = same_as(p30) # This same_as should be killed by backend jump(i29, p30, p3) """ expected = """ @@ -1240,8 +1284,8 @@ i28 = int_add(i0, 1) i29 = int_add(i28, 1) p30 = new_with_vtable(ConstClass(node_vtable)) + setfield_gc(p30, i28, descr=nextdescr) setfield_gc(p3, p30, descr=valuedescr) - setfield_gc(p30, i28, descr=nextdescr) jump(i29, p30, p3) """ self.optimize_loop(ops, expected, preamble) @@ -2034,7 +2078,9 @@ guard_true(i3) [] i4 = int_neg(i2) setfield_gc(p1, i2, descr=valuedescr) - jump(p1, i1, i2, i4, i4) + i7 = same_as(i2) # This same_as should be killed by backend + i6 = same_as(i4) + jump(p1, i1, i2, i4, i6) """ expected = """ [p1, i1, i2, i4, i5] @@ -2064,7 +2110,8 @@ i4 = int_neg(i2) setfield_gc(p1, NULL, descr=nextdescr) escape() - jump(p1, i2, i4, i4) + i5 = same_as(i4) + jump(p1, i2, i4, i5) """ expected = """ [p1, i2, i4, i5] @@ -2093,7 +2140,8 @@ i4 = int_neg(i2) setfield_gc(p1, NULL, descr=nextdescr) escape() - jump(p1, i2, i4, i4) + i5 = same_as(i4) + jump(p1, i2, i4, i5) """ expected = """ [p1, i2, i4, i5] @@ -2123,7 +2171,9 @@ guard_true(i5) [] i4 = int_neg(i2) setfield_gc(p1, i2, descr=valuedescr) - jump(p1, i1, i2, i4, i4) + i8 = same_as(i2) # This same_as should be killed by backend + i7 = same_as(i4) + jump(p1, i1, i2, i4, i7) """ expected = """ [p1, i1, i2, i4, i7] @@ -2349,7 +2399,8 @@ p2 = new_with_vtable(ConstClass(node_vtable)) setfield_gc(p2, p4, descr=nextdescr) setfield_gc(p1, p2, descr=nextdescr) - jump(p1, i2, i4, p4, i4) + i101 = same_as(i4) + jump(p1, i2, i4, p4, i101) """ expected = """ [p1, i2, i4, p4, i5] @@ -3192,7 +3243,15 @@ setfield_gc(p1, i3, descr=valuedescr) jump(p1, i4, i3) ''' - self.optimize_loop(ops, ops, ops) + preamble = ''' + [p1, i1, i4] + setfield_gc(p1, i1, descr=valuedescr) + i3 = call_assembler(i1, descr=asmdescr) + setfield_gc(p1, i3, descr=valuedescr) + i143 = same_as(i3) # Should be killed by backend + jump(p1, i4, i3) + ''' + self.optimize_loop(ops, ops, preamble) def test_call_assembler_invalidates_heap_knowledge(self): ops = ''' @@ -3223,7 +3282,9 @@ setfield_gc(p1, i1, descr=valuedescr) i3 = call(p1, descr=plaincalldescr) setfield_gc(p1, i3, descr=valuedescr) - jump(p1, i4, i3, i3) + i148 = same_as(i3) + i147 = same_as(i3) + jump(p1, i4, i3, i148) ''' self.optimize_loop(ops, expected, preamble) @@ -3246,7 +3307,8 @@ setfield_gc(p1, i1, descr=valuedescr) i3 = call(p1, descr=plaincalldescr) setfield_gc(p1, i1, descr=valuedescr) - jump(p1, i4, i3, i3) + i151 = same_as(i3) + jump(p1, i4, i3, i151) ''' self.optimize_loop(ops, expected, preamble) @@ -3266,7 +3328,8 @@ escape(i1) escape(i2) i4 = call(123456, 4, i0, 6, descr=plaincalldescr) - jump(i0, i4, i4) + i153 = same_as(i4) + jump(i0, i4, i153) ''' expected = ''' [i0, i4, i5] @@ -3296,7 +3359,8 @@ escape(i2) i4 = call(123456, 4, i0, 6, descr=plaincalldescr) guard_no_exception() [] - jump(i0, i4, i4) + i155 = same_as(i4) + jump(i0, i4, i155) ''' expected = ''' [i0, i2, i3] @@ -4114,6 +4178,7 @@ preamble = """ [p0] i0 = strlen(p0) + i3 = same_as(i0) # Should be killed by backend jump(p0) """ expected = """ @@ -5334,6 +5399,7 @@ [p0] p1 = getfield_gc(p0, descr=valuedescr) setfield_gc(p0, p0, descr=valuedescr) + p4450 = same_as(p0) # Should be killed by backend jump(p0) """ expected = """ @@ -5479,7 +5545,8 @@ p3 = newstr(i3) copystrcontent(p1, p3, 0, 0, i1) copystrcontent(p2, p3, 0, i1, i2) - jump(p2, p3, i2) + i7 = same_as(i2) + jump(p2, p3, i7) """ expected = """ [p1, p2, i1] @@ -5554,7 +5621,9 @@ copystrcontent(p1, p5, 0, 0, i1) copystrcontent(p2, p5, 0, i1, i2) copystrcontent(p3, p5, 0, i12, i3) - jump(p2, p3, p5, i2, i3) + i129 = same_as(i2) + i130 = same_as(i3) + jump(p2, p3, p5, i129, i130) """ expected = """ [p1, p2, p3, i1, i2] @@ -5614,7 +5683,8 @@ [p1, i1, i2, i3] escape(i3) i4 = int_sub(i2, i1) - jump(p1, i1, i2, i4, i4) + i5 = same_as(i4) + jump(p1, i1, i2, i4, i5) """ expected = """ [p1, i1, i2, i3, i4] @@ -5639,7 +5709,8 @@ escape(i5) i4 = int_sub(i2, i1) setfield_gc(p2, i4, descr=valuedescr) - jump(p1, i1, i2, p2, i4, i4) + i8 = same_as(i4) + jump(p1, i1, i2, p2, i8, i4) """ expected = """ [p1, i1, i2, p2, i5, i6] @@ -5765,7 +5836,8 @@ p4 = newstr(i5) copystrcontent(p1, p4, i1, 0, i3) copystrcontent(p2, p4, 0, i3, i4) - jump(p4, i1, i2, p2, i5, i3, i4) + i9 = same_as(i4) + jump(p4, i1, i2, p2, i5, i3, i9) """ expected = """ [p1, i1, i2, p2, i5, i3, i4] @@ -5887,7 +5959,9 @@ copystrcontent(p2, p4, 0, i1, i2) i0 = call(0, p3, p4, descr=strequaldescr) escape(i0) - jump(p1, p2, p3, i3, i1, i2) + i11 = same_as(i1) + i12 = same_as(i2) + jump(p1, p2, p3, i3, i11, i12) """ expected = """ [p1, p2, p3, i3, i1, i2] @@ -6107,6 +6181,7 @@ i1 = strlen(p1) i0 = int_eq(i1, 0) escape(i0) + i3 = same_as(i1) jump(p1, i0) """ self.optimize_strunicode_loop_extradescrs(ops, expected, preamble) @@ -6152,7 +6227,9 @@ copystrcontent(p2, p4, 0, i1, i2) i0 = call(0, s"hello world", p4, descr=streq_nonnull_descr) escape(i0) - jump(p1, p2, i3, i1, i2) + i11 = same_as(i1) + i12 = same_as(i2) + jump(p1, p2, i3, i11, i12) """ expected = """ [p1, p2, i3, i1, i2] @@ -6436,7 +6513,8 @@ p188 = getarrayitem_gc(p187, 42, descr=<GcPtrArrayDescr>) guard_value(p188, ConstPtr(myptr)) [] p25 = getfield_gc(ConstPtr(myptr), descr=otherdescr) - jump(p25, p187, i184, p25) + p26 = same_as(p25) + jump(p25, p187, i184, p26) """ short = """ [p1, p187, i184] @@ -6705,7 +6783,8 @@ [p9] i843 = strlen(p9) call(i843, descr=nonwritedescr) - jump(p9, i843) + i0 = same_as(i843) + jump(p9, i0) """ short = """ [p9] @@ -7397,7 +7476,8 @@ call(i2, descr=nonwritedescr) setfield_gc(p22, i1, descr=valuedescr) guard_nonnull_class(p18, ConstClass(node_vtable)) [] - jump(p22, p18, i1, i1) + i10 = same_as(i1) + jump(p22, p18, i1, i10) """ short = """ [p22, p18, i1] diff --git a/pypy/jit/metainterp/optimizeopt/test/test_util.py b/pypy/jit/metainterp/optimizeopt/test/test_util.py --- a/pypy/jit/metainterp/optimizeopt/test/test_util.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_util.py @@ -384,7 +384,7 @@ expected.operations, False, remap, text_right) def _do_optimize_loop(self, loop, call_pure_results): - from pypy.jit.metainterp.optimizeopt import optimize_loop_1 + from pypy.jit.metainterp.optimizeopt import optimize_trace from pypy.jit.metainterp.optimizeopt.util import args_dict self.loop = loop @@ -398,7 +398,7 @@ if hasattr(self, 'callinfocollection'): metainterp_sd.callinfocollection = self.callinfocollection # - optimize_loop_1(metainterp_sd, loop, self.enable_opts) + optimize_trace(metainterp_sd, loop, self.enable_opts) # ____________________________________________________________ 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 @@ -1,7 +1,7 @@ from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.metainterp.optimizeopt.virtualstate import VirtualStateAdder, ShortBoxes from pypy.jit.metainterp.compile import ResumeGuardDescr -from pypy.jit.metainterp.history import TreeLoop, LoopToken +from pypy.jit.metainterp.history import TreeLoop, LoopToken, TargetToken from pypy.jit.metainterp.jitexc import JitException from pypy.jit.metainterp.optimize import InvalidLoop, RetraceLoop from pypy.jit.metainterp.optimizeopt.optimizer import * @@ -103,12 +103,8 @@ def __init__(self, metainterp_sd, loop, optimizations): self.optimizer = UnrollableOptimizer(metainterp_sd, loop, optimizations) - self.cloned_operations = [] - for op in self.optimizer.loop.operations: - newop = op.clone() - self.cloned_operations.append(newop) - def fix_snapshot(self, loop, jump_args, snapshot): + def fix_snapshot(self, jump_args, snapshot): if snapshot is None: return None snapshot_args = snapshot.boxes @@ -116,233 +112,170 @@ for a in snapshot_args: a = self.getvalue(a).get_key_box() new_snapshot_args.append(a) - prev = self.fix_snapshot(loop, jump_args, snapshot.prev) + prev = self.fix_snapshot(jump_args, snapshot.prev) return Snapshot(prev, new_snapshot_args) def propagate_all_forward(self): loop = self.optimizer.loop - jumpop = loop.operations[-1] - if jumpop.getopnum() == rop.JUMP: + start_targetop = loop.operations[0] + assert start_targetop.getopnum() == rop.TARGET + loop.operations = loop.operations[1:] + self.optimizer.clear_newoperations() + self.optimizer.send_extra_operation(start_targetop) + + self.import_state(start_targetop) + + lastop = loop.operations[-1] + if lastop.getopnum() == rop.TARGET or lastop.getopnum() == rop.JUMP: loop.operations = loop.operations[:-1] - else: - loopop = None - - self.optimizer.propagate_all_forward() - - - if jumpop: - assert jumpop.getdescr() is loop.token - jump_args = jumpop.getarglist() - jumpop.initarglist([]) + #FIXME: FINISH + + self.optimizer.propagate_all_forward(clear=False) + + if lastop.getopnum() == rop.TARGET: self.optimizer.flush() - KillHugeIntBounds(self.optimizer).apply() - - loop.preamble.operations = self.optimizer.get_newoperations() - jump_args = [self.getvalue(a).get_key_box() for a in jump_args] - - start_resumedescr = loop.preamble.start_resumedescr.clone_if_mutable() - self.start_resumedescr = start_resumedescr - assert isinstance(start_resumedescr, ResumeGuardDescr) - start_resumedescr.rd_snapshot = self.fix_snapshot(loop, jump_args, - start_resumedescr.rd_snapshot) - - modifier = VirtualStateAdder(self.optimizer) - virtual_state = modifier.get_virtual_state(jump_args) - - values = [self.getvalue(arg) for arg in jump_args] - inputargs = virtual_state.make_inputargs(values, self.optimizer) - short_inputargs = virtual_state.make_inputargs(values, self.optimizer, - keyboxes=True) - - self.constant_inputargs = {} - for box in jump_args: - const = self.get_constant_box(box) - if const: - self.constant_inputargs[box] = const - - sb = ShortBoxes(self.optimizer, inputargs + self.constant_inputargs.keys()) - self.short_boxes = sb - preamble_optimizer = self.optimizer - loop.preamble.quasi_immutable_deps = ( - self.optimizer.quasi_immutable_deps) - self.optimizer = self.optimizer.new() - loop.quasi_immutable_deps = self.optimizer.quasi_immutable_deps - - logops = self.optimizer.loop.logops - if logops: - args = ", ".join([logops.repr_of_arg(arg) for arg in inputargs]) - debug_print('inputargs: ' + args) - args = ", ".join([logops.repr_of_arg(arg) for arg in short_inputargs]) - debug_print('short inputargs: ' + args) - self.short_boxes.debug_print(logops) - - - # Force virtuals amoung the jump_args of the preamble to get the - # operations needed to setup the proper state of those virtuals - # in the peeled loop - inputarg_setup_ops = [] - preamble_optimizer.clear_newoperations() - seen = {} - for box in inputargs: - if box in seen: - continue - seen[box] = True - preamble_value = preamble_optimizer.getvalue(box) - value = self.optimizer.getvalue(box) - value.import_from(preamble_value, self.optimizer) - for box in short_inputargs: - if box in seen: - continue - seen[box] = True - value = preamble_optimizer.getvalue(box) - value.force_box(preamble_optimizer) - inputarg_setup_ops += preamble_optimizer.get_newoperations() - - # Setup the state of the new optimizer by emiting the - # short preamble operations and discarding the result - self.optimizer.emitting_dissabled = True - for op in inputarg_setup_ops: - self.optimizer.send_extra_operation(op) - seen = {} - for op in self.short_boxes.operations(): - self.ensure_short_op_emitted(op, self.optimizer, seen) - if op and op.result: - preamble_value = preamble_optimizer.getvalue(op.result) - value = self.optimizer.getvalue(op.result) - if not value.is_virtual(): - imp = ValueImporter(self, preamble_value, op) - self.optimizer.importable_values[value] = imp - newresult = self.optimizer.getvalue(op.result).get_key_box() - if newresult is not op.result: - self.short_boxes.alias(newresult, op.result) - self.optimizer.flush() - self.optimizer.emitting_dissabled = False - - initial_inputargs_len = len(inputargs) - self.inliner = Inliner(loop.inputargs, jump_args) - - - short = self.inline(inputargs, self.cloned_operations, - loop.inputargs, short_inputargs, - virtual_state) - - loop.inputargs = inputargs - args = [preamble_optimizer.getvalue(self.short_boxes.original(a)).force_box(preamble_optimizer)\ - for a in inputargs] - jmp = ResOperation(rop.JUMP, args, None) - jmp.setdescr(loop.token) - loop.preamble.operations.append(jmp) loop.operations = self.optimizer.get_newoperations() - maxguards = self.optimizer.metainterp_sd.warmrunnerdesc.memory_manager.max_retrace_guards + self.export_state(lastop) + loop.operations.append(lastop) + elif lastop.getopnum() == rop.JUMP: + assert lastop.getdescr() is start_targetop.getdescr() + self.close_loop(lastop) + short_preamble_loop = self.produce_short_preamble(lastop) + assert isinstance(loop.token, LoopToken) + if loop.token.short_preamble: + loop.token.short_preamble.append(short_preamble_loop) # FIXME: ?? + else: + loop.token.short_preamble = [short_preamble_loop] + else: + loop.operations = self.optimizer.get_newoperations() + + def export_state(self, targetop): + jump_args = targetop.getarglist() + jump_args = [self.getvalue(a).get_key_box() for a in jump_args] + + start_resumedescr = self.optimizer.loop.start_resumedescr.clone_if_mutable() + assert isinstance(start_resumedescr, ResumeGuardDescr) + start_resumedescr.rd_snapshot = self.fix_snapshot(jump_args, start_resumedescr.rd_snapshot) + + modifier = VirtualStateAdder(self.optimizer) + virtual_state = modifier.get_virtual_state(jump_args) - if self.optimizer.emitted_guards > maxguards: - loop.preamble.token.retraced_count = sys.maxint + values = [self.getvalue(arg) for arg in jump_args] + inputargs = virtual_state.make_inputargs(values, self.optimizer) + short_inputargs = virtual_state.make_inputargs(values, self.optimizer, keyboxes=True) - if short: - assert short[-1].getopnum() == rop.JUMP - short[-1].setdescr(loop.token) + constant_inputargs = {} + for box in jump_args: + const = self.get_constant_box(box) + if const: + constant_inputargs[box] = const - # Turn guards into conditional jumps to the preamble - for i in range(len(short)): - op = short[i] - if op.is_guard(): - op = op.clone() - op.setfailargs(None) - descr = self.start_resumedescr.clone_if_mutable() - op.setdescr(descr) - short[i] = op + short_boxes = ShortBoxes(self.optimizer, inputargs + constant_inputargs.keys()) - short_loop = TreeLoop('short preamble') - short_loop.inputargs = short_inputargs - short_loop.operations = short + self.optimizer.clear_newoperations() + for box in short_inputargs: + value = self.getvalue(box) + if value.is_virtual(): + value.force_box(self.optimizer) + inputarg_setup_ops = self.optimizer.get_newoperations() - # Clone ops and boxes to get private versions and - boxmap = {} - newargs = [None] * len(short_loop.inputargs) - for i in range(len(short_loop.inputargs)): - a = short_loop.inputargs[i] - if a in boxmap: - newargs[i] = boxmap[a] - else: - newargs[i] = a.clonebox() - boxmap[a] = newargs[i] - inliner = Inliner(short_loop.inputargs, newargs) - for box, const in self.constant_inputargs.items(): - inliner.argmap[box] = const - short_loop.inputargs = newargs - ops = [inliner.inline_op(op) for op in short_loop.operations] - short_loop.operations = ops - descr = self.start_resumedescr.clone_if_mutable() - inliner.inline_descr_inplace(descr) - short_loop.start_resumedescr = descr + target_token = targetop.getdescr() + assert isinstance(target_token, TargetToken) + targetop.initarglist(inputargs) + target_token.exported_state = ExportedState(values, short_inputargs, + constant_inputargs, short_boxes, + inputarg_setup_ops, self.optimizer, + jump_args, virtual_state, + start_resumedescr) - assert isinstance(loop.preamble.token, LoopToken) - if loop.preamble.token.short_preamble: - loop.preamble.token.short_preamble.append(short_loop) - else: - loop.preamble.token.short_preamble = [short_loop] - short_loop.virtual_state = virtual_state + def import_state(self, targetop): + target_token = targetop.getdescr() + assert isinstance(target_token, TargetToken) + exported_state = target_token.exported_state + if not exported_state: + # FIXME: Set up some sort of empty state with no virtuals + return - # Forget the values to allow them to be freed - for box in short_loop.inputargs: - box.forget_value() - for op in short_loop.operations: - if op.result: - op.result.forget_value() + self.short = [] + self.short_seen = {} + self.short_boxes = exported_state.short_boxes + for box, const in exported_state.constant_inputargs.items(): + self.short_seen[box] = True + self.imported_state = exported_state + self.inputargs = targetop.getarglist() + self.start_resumedescr = exported_state.start_resumedescr - def inline(self, inputargs, loop_operations, loop_args, short_inputargs, virtual_state): - inliner = self.inliner + seen = {} + for box in self.inputargs: + if box in seen: + continue + seen[box] = True + preamble_value = exported_state.optimizer.getvalue(box) + value = self.optimizer.getvalue(box) + value.import_from(preamble_value, self.optimizer) + + # Setup the state of the new optimizer by emiting the + # short operations and discarding the result + self.optimizer.emitting_dissabled = True + for op in exported_state.inputarg_setup_ops: + self.optimizer.send_extra_operation(op) + seen = {} + for op in self.short_boxes.operations(): + self.ensure_short_op_emitted(op, self.optimizer, seen) + if op and op.result: + preamble_value = exported_state.optimizer.getvalue(op.result) + value = self.optimizer.getvalue(op.result) + if not value.is_virtual(): + imp = ValueImporter(self, preamble_value, op) + self.optimizer.importable_values[value] = imp + newvalue = self.optimizer.getvalue(op.result) + newresult = newvalue.get_key_box() + if newresult is not op.result and not newvalue.is_constant(): + self.short_boxes.alias(newresult, op.result) + op = ResOperation(rop.SAME_AS, [op.result], newresult) + self.optimizer._newoperations = [op] + self.optimizer._newoperations # XXX + #self.optimizer.getvalue(op.result).box = op.result # FIXME: HACK!!! + self.optimizer.flush() + self.optimizer.emitting_dissabled = False + def close_loop(self, jumpop): + assert jumpop + virtual_state = self.imported_state.virtual_state + short_inputargs = self.imported_state.short_inputargs + constant_inputargs = self.imported_state.constant_inputargs + inputargs = self.inputargs short_jumpargs = inputargs[:] - short = self.short = [] - short_seen = self.short_seen = {} - for box, const in self.constant_inputargs.items(): - short_seen[box] = True - - # This loop is equivalent to the main optimization loop in - # Optimizer.propagate_all_forward - jumpop = None - for newop in loop_operations: - newop = inliner.inline_op(newop, clone=False) - if newop.getopnum() == rop.JUMP: - jumpop = newop - break - - #self.optimizer.first_optimization.propagate_forward(newop) - self.optimizer.send_extra_operation(newop) - - self.boxes_created_this_iteration = {} - - assert jumpop + # Construct jumpargs from the virtual state original_jumpargs = jumpop.getarglist()[:] values = [self.getvalue(arg) for arg in jumpop.getarglist()] jumpargs = virtual_state.make_inputargs(values, self.optimizer) jumpop.initarglist(jumpargs) - jmp_to_short_args = virtual_state.make_inputargs(values, self.optimizer, - keyboxes=True) + + # Inline the short preamble at the end of the loop + jmp_to_short_args = virtual_state.make_inputargs(values, self.optimizer, keyboxes=True) self.short_inliner = Inliner(short_inputargs, jmp_to_short_args) - - for box, const in self.constant_inputargs.items(): + for box, const in constant_inputargs.items(): self.short_inliner.argmap[box] = const - - for op in short: + for op in self.short: newop = self.short_inliner.inline_op(op) self.optimizer.send_extra_operation(newop) - + + # Import boxes produced in the preamble but used in the loop newoperations = self.optimizer.get_newoperations() - + self.boxes_created_this_iteration = {} i = j = 0 + while newoperations[i].getopnum() != rop.TARGET: + i += 1 while i < len(newoperations) or j < len(jumpargs): if i == len(newoperations): while j < len(jumpargs): a = jumpargs[j] if self.optimizer.loop.logops: debug_print('J: ' + self.optimizer.loop.logops.repr_of_arg(a)) - self.import_box(a, inputargs, short, short_jumpargs, - jumpargs, short_seen) + self.import_box(a, inputargs, short_jumpargs, jumpargs) j += 1 else: op = newoperations[i] @@ -357,15 +290,16 @@ for a in args: if self.optimizer.loop.logops: debug_print('A: ' + self.optimizer.loop.logops.repr_of_arg(a)) - self.import_box(a, inputargs, short, short_jumpargs, - jumpargs, short_seen) + self.import_box(a, inputargs, short_jumpargs, jumpargs) i += 1 newoperations = self.optimizer.get_newoperations() jumpop.initarglist(jumpargs) self.optimizer.send_extra_operation(jumpop) - short.append(ResOperation(rop.JUMP, short_jumpargs, None)) + self.short.append(ResOperation(rop.JUMP, short_jumpargs, None, descr=jumpop.getdescr())) + # Verify that the virtual state at the end of the loop is one + # that is compatible with the virtual state at the start of the loop modifier = VirtualStateAdder(self.optimizer) final_virtual_state = modifier.get_virtual_state(original_jumpargs) debug_start('jit-log-virtualstate') @@ -382,8 +316,79 @@ debug_stop('jit-log-virtualstate') raise InvalidLoop debug_stop('jit-log-virtualstate') + + def produce_short_preamble(self, lastop): + short = self.short + assert short[-1].getopnum() == rop.JUMP + + # Turn guards into conditional jumps to the preamble + for i in range(len(short)): + op = short[i] + if op.is_guard(): + op = op.clone() + op.setfailargs(None) + descr = self.start_resumedescr.clone_if_mutable() + op.setdescr(descr) + short[i] = op + + short_loop = TreeLoop('short preamble') + short_inputargs = self.imported_state.short_inputargs + short_loop.operations = [ResOperation(rop.TARGET, short_inputargs, None)] + \ + short + + # Clone ops and boxes to get private versions and + boxmap = {} + newargs = [None] * len(short_inputargs) + for i in range(len(short_inputargs)): + a = short_inputargs[i] + if a in boxmap: + newargs[i] = boxmap[a] + else: + newargs[i] = a.clonebox() + boxmap[a] = newargs[i] + inliner = Inliner(short_inputargs, newargs) + for box, const in self.imported_state.constant_inputargs.items(): + inliner.argmap[box] = const + ops = [inliner.inline_op(op) for op in short_loop.operations] + short_loop.operations = ops + descr = self.start_resumedescr.clone_if_mutable() + inliner.inline_descr_inplace(descr) + short_loop.start_resumedescr = descr + + short_loop.virtual_state = self.imported_state.virtual_state + + # Forget the values to allow them to be freed + for box in short_loop.inputargs: + box.forget_value() + for op in short_loop.operations: + if op.result: + op.result.forget_value() + + return short_loop - return short + def FIXME_old_stuff(): + preamble_optimizer = self.optimizer + loop.preamble.quasi_immutable_deps = ( + self.optimizer.quasi_immutable_deps) + self.optimizer = self.optimizer.new() + loop.quasi_immutable_deps = self.optimizer.quasi_immutable_deps + + + loop.inputargs = inputargs + args = [preamble_optimizer.getvalue(self.short_boxes.original(a)).force_box(preamble_optimizer)\ + for a in inputargs] + jmp = ResOperation(rop.JUMP, args, None) + jmp.setdescr(loop.token) + loop.preamble.operations.append(jmp) + + loop.operations = self.optimizer.get_newoperations() + maxguards = self.optimizer.metainterp_sd.warmrunnerdesc.memory_manager.max_retrace_guards + + if self.optimizer.emitted_guards > maxguards: + loop.preamble.token.retraced_count = sys.maxint + + if short: + pass def ensure_short_op_emitted(self, op, optimizer, seen): if op is None: @@ -399,19 +404,18 @@ guard = ResOperation(rop.GUARD_NO_OVERFLOW, [], None) optimizer.send_extra_operation(guard) - def add_op_to_short(self, op, short, short_seen, emit=True, guards_needed=False): + def add_op_to_short(self, op, emit=True, guards_needed=False): if op is None: return None - if op.result is not None and op.result in short_seen: + if op.result is not None and op.result in self.short_seen: if emit: return self.short_inliner.inline_arg(op.result) else: return None for a in op.getarglist(): - if not isinstance(a, Const) and a not in short_seen: - self.add_op_to_short(self.short_boxes.producer(a), short, short_seen, - emit, guards_needed) + if not isinstance(a, Const) and a not in self.short_seen: + self.add_op_to_short(self.short_boxes.producer(a), emit, guards_needed) if op.is_guard(): descr = self.start_resumedescr.clone_if_mutable() op.setdescr(descr) @@ -421,8 +425,8 @@ else: value_guards = [] - short.append(op) - short_seen[op.result] = True + self.short.append(op) + self.short_seen[op.result] = True if emit: newop = self.short_inliner.inline_op(op) self.optimizer.send_extra_operation(newop) @@ -432,23 +436,22 @@ if op.is_ovf(): # FIXME: ensure that GUARD_OVERFLOW:ed ops not end up here guard = ResOperation(rop.GUARD_NO_OVERFLOW, [], None) - self.add_op_to_short(guard, short, short_seen, emit, guards_needed) + self.add_op_to_short(guard, emit, guards_needed) for guard in value_guards: - self.add_op_to_short(guard, short, short_seen, emit, guards_needed) + self.add_op_to_short(guard, emit, guards_needed) if newop: return newop.result return None - def import_box(self, box, inputargs, short, short_jumpargs, - jumpargs, short_seen): + def import_box(self, box, inputargs, short_jumpargs, jumpargs): if isinstance(box, Const) or box in inputargs: return if box in self.boxes_created_this_iteration: return short_op = self.short_boxes.producer(box) - newresult = self.add_op_to_short(short_op, short, short_seen) + newresult = self.add_op_to_short(short_op) short_jumpargs.append(short_op.result) inputargs.append(box) @@ -468,7 +471,7 @@ def propagate_forward(self, op): if op.getopnum() == rop.JUMP: loop_token = op.getdescr() - assert isinstance(loop_token, LoopToken) + assert isinstance(loop_token, TargetToken) short = loop_token.short_preamble if short: args = op.getarglist() @@ -557,5 +560,19 @@ def import_value(self, value): value.import_from(self.preamble_value, self.unroll.optimizer) - self.unroll.add_op_to_short(self.op, self.unroll.short, self.unroll.short_seen, False, True) + self.unroll.add_op_to_short(self.op, False, True) + +class ExportedState(object): + def __init__(self, values, short_inputargs, constant_inputargs, + short_boxes, inputarg_setup_ops, optimizer, jump_args, virtual_state, + start_resumedescr): + self.values = values + self.short_inputargs = short_inputargs + self.constant_inputargs = constant_inputargs + self.short_boxes = short_boxes + self.inputarg_setup_ops = inputarg_setup_ops + self.optimizer = optimizer + self.jump_args = jump_args + self.virtual_state = virtual_state + self.start_resumedescr = start_resumedescr diff --git a/pypy/jit/metainterp/optimizeopt/util.py b/pypy/jit/metainterp/optimizeopt/util.py --- a/pypy/jit/metainterp/optimizeopt/util.py +++ b/pypy/jit/metainterp/optimizeopt/util.py @@ -148,7 +148,7 @@ assert op1.result.same_box(remap[op2.result]) else: remap[op2.result] = op1.result - if op1.getopnum() != rop.JUMP: # xxx obscure + if op1.getopnum() not in (rop.JUMP, rop.TARGET): # xxx obscure assert op1.getdescr() == op2.getdescr() if op1.getfailargs() or op2.getfailargs(): assert len(op1.getfailargs()) == len(op2.getfailargs()) 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 @@ -598,6 +598,7 @@ newbox = newop.result = op.result.clonebox() self.short_boxes[newop.result] = newop value = self.optimizer.getvalue(box) + self.optimizer.emit_operation(ResOperation(rop.SAME_AS, [box], newbox)) self.optimizer.make_equal_to(newbox, value) else: self.short_boxes[box] = op _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit