Author: Maciej Fijalkowski <fij...@gmail.com> Branch: optresult-unroll Changeset: r78574:b7aec727abac Date: 2015-07-16 15:17 +0200 http://bitbucket.org/pypy/pypy/changeset/b7aec727abac/
Log: work some more on short preamble diff --git a/rpython/jit/metainterp/optimizeopt/heap.py b/rpython/jit/metainterp/optimizeopt/heap.py --- a/rpython/jit/metainterp/optimizeopt/heap.py +++ b/rpython/jit/metainterp/optimizeopt/heap.py @@ -9,7 +9,8 @@ from rpython.jit.metainterp.optimizeopt.util import make_dispatcher_method from rpython.jit.metainterp.optimizeopt.intutils import IntBound from rpython.jit.metainterp.optimize import InvalidLoop -from rpython.jit.metainterp.resoperation import rop, ResOperation, OpHelpers +from rpython.jit.metainterp.resoperation import rop, ResOperation, OpHelpers,\ + AbstractResOp from rpython.rlib.objectmodel import we_are_translated from rpython.jit.metainterp.optimizeopt import info @@ -53,12 +54,11 @@ descr): assert self._lazy_setfield is None for i, info in enumerate(self.cached_infos): - structbox = self.cached_structs[i] - op = info._fields[descr.get_index()] - op = optimizer.get_box_replacement(op) + structbox = optimizer.get_box_replacement(self.cached_structs[i]) + op = optimizer.get_box_replacement(info._fields[descr.get_index()]) opnum = OpHelpers.getfield_for_descr(descr) getfield_op = ResOperation(opnum, [structbox], descr=descr) - shortboxes.add_potential(op, getfield_op) + shortboxes.add_heap_op(op, getfield_op) return for structvalue in self._cached_fields_getfield_op.keys(): op = self._cached_fields_getfield_op[structvalue] diff --git a/rpython/jit/metainterp/optimizeopt/pure.py b/rpython/jit/metainterp/optimizeopt/pure.py --- a/rpython/jit/metainterp/optimizeopt/pure.py +++ b/rpython/jit/metainterp/optimizeopt/pure.py @@ -221,9 +221,9 @@ ops = self.optimizer._newoperations for i, op in enumerate(ops): if op.is_always_pure(): - sb.add_potential(op) + sb.add_pure_op(op) if op.is_ovf() and ops[i + 1].getopnum() == rop.GUARD_NO_OVERFLOW: - sb.add_potential(op) + sb.add_pure_op(op) for i in self.call_pure_positions: yyy op = ops[i] diff --git a/rpython/jit/metainterp/optimizeopt/shortpreamble.py b/rpython/jit/metainterp/optimizeopt/shortpreamble.py --- a/rpython/jit/metainterp/optimizeopt/shortpreamble.py +++ b/rpython/jit/metainterp/optimizeopt/shortpreamble.py @@ -1,55 +1,119 @@ from rpython.jit.metainterp.resoperation import ResOperation, OpHelpers,\ - AbstractInputArg + AbstractInputArg, rop from rpython.jit.metainterp.history import Const +from rpython.jit.metainterp.optimizeopt import info +class InputArgPlaceholder(AbstractInputArg): + def __repr__(self): + return "placeholder" +placeholder = InputArgPlaceholder() class ShortBoxes(object): def __init__(self): - self.potential_ops = [] - self.produced_short_boxes = {} - self.extra_same_as = [] + self.potential_ops = {} + #self.extra_same_as = [] def create_short_boxes(self, optimizer, inputargs): + self.produced_short_boxes = {} + self.const_short_boxes = [] + self.short_inputargs = [] for box in inputargs: - self.produced_short_boxes[box] = None + renamed = OpHelpers.inputarg_from_tp(box.type) + self.produced_short_boxes[box] = (placeholder, renamed) + self.short_inputargs.append(renamed) optimizer.produce_potential_short_preamble_ops(self) - self.short_boxes = [] - # short boxes is a list of (op, preamble_op) - # where op can be - # anything, but the preamble_op has to be either pure - # or a heap cache op + short_boxes = [] - for op, preamble_op in self.potential_ops: - self.produce_short_preamble_op(op, preamble_op) - self.produced_short_boxes = None - return self.short_boxes + for op, getfield_op in self.potential_ops.items(): + self.add_op_to_short(op, getfield_op) + # + for op, (getfield_op, preamble_op) in self.produced_short_boxes.iteritems(): + if getfield_op is not placeholder: + short_boxes.append((op, preamble_op)) + return short_boxes + self.const_short_boxes - def add_to_short(self, op, short_op): - self.short_boxes.append((op, short_op)) - self.produced_short_boxes[op] = None + def produce_short_inputargs(self): + return self.short_inputargs - def produce_short_preamble_op(self, op, preamble_op): + def produce_arg(self, op): + if op in self.produced_short_boxes: + return self.produced_short_boxes[op][1] + elif isinstance(op, Const): + return op + elif op in self.potential_ops: + return self.add_op_to_short(op, self.potential_ops[op]) + else: + return None + + def add_op_to_short(self, op, sop): + if sop: + preamble_arg = self.produce_arg(sop.getarg(0)) + if preamble_arg is None: + return False + preamble_op = ResOperation(sop.getopnum(), [preamble_arg], + descr=sop.getdescr()) + else: + arglist = [] + for arg in op.getarglist(): + newarg = self.produce_arg(arg) + if newarg is None: + return False + arglist.append(newarg) + preamble_op = op.copy_and_change(op.getopnum(), args=arglist) + self.produced_short_boxes[op] = (sop, preamble_op) + return True + + def add_pure_op(self, op): + assert not self.potential_ops.get(op, None) + self.potential_ops[op] = None + + def add_heap_op(self, op, getfield_op): + assert not self.potential_ops.get(op, None) + if isinstance(op, Const): + self.const_short_boxes.append((op, getfield_op)) + return # we should not be called from anywhere + self.potential_ops[op] = getfield_op + +class EmptyInfo(info.AbstractInfo): + pass + +empty_info = EmptyInfo() + +class ShortPreambleBuilder(object): + def __init__(self, short_boxes, short_inputargs, exported_infos): + self.producable_ops = {} + for op, preamble_op in short_boxes: + self.producable_ops[op] = preamble_op + preamble_op.set_forwarded(exported_infos.get(op, empty_info)) + self.short = [] + self.used_boxes = [] + self.short_inputargs = short_inputargs + + def use_box(self, box): + preamble_op = self.producable_ops.get(box, None) + if preamble_op is None: + return + del self.producable_ops[box] for arg in preamble_op.getarglist(): if isinstance(arg, Const): pass - elif arg in self.produced_short_boxes: + elif arg.get_forwarded() is None: pass else: - return # can't produce - if op in self.produced_short_boxes: - opnum = OpHelpers.same_as_for_type(op.type) - same_as_op = ResOperation(opnum, [op]) - self.extra_same_as.append(same_as_op) - self.add_to_short(same_as_op, preamble_op) - else: - self.add_to_short(op, preamble_op) + xxx + self.short.append(preamble_op) + info = preamble_op.get_forwarded() + if info is not empty_info: + info.make_guards(preamble_op, self.short) + if info.is_constant(): + return + self.used_boxes.append(preamble_op) - def add_potential(self, op, short_preamble_op=None): - if short_preamble_op is None: - self.potential_ops.append((op, op)) - else: - self.potential_ops.append((op, short_preamble_op)) + def build_short_preamble(self): + label_op = ResOperation(rop.LABEL, self.short_inputargs[:]) + jump_op = ResOperation(rop.JUMP, self.used_boxes) + return [label_op] + self.short + [jump_op] diff --git a/rpython/jit/metainterp/optimizeopt/test/test_short.py b/rpython/jit/metainterp/optimizeopt/test/test_short.py --- a/rpython/jit/metainterp/optimizeopt/test/test_short.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_short.py @@ -2,6 +2,7 @@ """ Short preamble tests """ +import py from rpython.jit.metainterp.resoperation import InputArgInt, ResOperation, rop from rpython.jit.metainterp.optimizeopt.shortpreamble import ShortBoxes from rpython.jit.metainterp.history import AbstractDescr @@ -16,10 +17,9 @@ def produce_potential_short_preamble_ops(self, sb): for op in self.oplist: if isinstance(op, tuple): - op, r = op + sb.add_heap_op(*op) else: - op, r = op, op - sb.add_potential(op, r) + sb.add_pure_op(op) class TestShortBoxes(object): def test_pure_ops(self): @@ -27,16 +27,16 @@ i1 = InputArgInt() op = ResOperation(rop.INT_ADD, [i0, i1]) sb = ShortBoxes() - sb.create_short_boxes(Opt([op]), [i0, i1]) - assert sb.short_boxes == [(op, op)] + short_boxes = sb.create_short_boxes(Opt([op]), [i0, i1]) + assert short_boxes == [(op, None)] def test_pure_ops_does_not_work(self): i0 = InputArgInt() i1 = InputArgInt() op = ResOperation(rop.INT_ADD, [i0, i1]) sb = ShortBoxes() - sb.create_short_boxes(Opt([op]), [i0]) - assert sb.short_boxes == [] + short_boxes = sb.create_short_boxes(Opt([op]), [i0]) + assert short_boxes == [] def test_multiple_similar_ops(self): """ This can happen e.g. if heap cache and pure ops produce @@ -49,6 +49,7 @@ we store both in short preamble (in case someone else who inlines the short preamble does not share them) """ + py.test.skip("l8r") i0 = InputArgInt() i1 = InputArgInt() op = ResOperation(rop.INT_ADD, [i0, i1]) diff --git a/rpython/jit/metainterp/optimizeopt/test/test_unroll.py b/rpython/jit/metainterp/optimizeopt/test/test_unroll.py --- a/rpython/jit/metainterp/optimizeopt/test/test_unroll.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_unroll.py @@ -6,10 +6,12 @@ from rpython.jit.metainterp.optimizeopt.test.test_util import BaseTest,\ LLtypeMixin +from rpython.jit.metainterp.optimizeopt.util import equaloplists from rpython.jit.metainterp.history import (TreeLoop, ConstInt, JitCellToken, TargetToken) from rpython.jit.metainterp.resoperation import rop, ResOperation,\ InputArgRef +from rpython.jit.metainterp.optimizeopt.shortpreamble import ShortPreambleBuilder from rpython.jit.metainterp.compile import LoopCompileData from rpython.jit.metainterp.optimizeopt.virtualstate import \ NotVirtualStateInfo, LEVEL_CONSTANT, LEVEL_UNKNOWN, LEVEL_KNOWNCLASS,\ @@ -51,6 +53,16 @@ preamble.inputargs = start_state.renamed_inputargs return start_state, loop, preamble + def compare_short(self, short, expected_short): + expected_short = self.parse(expected_short, + postprocess=self.postprocess) + remap = {} + exp = ([ResOperation(rop.LABEL, expected_short.inputargs)] + + expected_short.operations) + for k, v in zip(short[0].getarglist(), expected_short.inputargs): + remap[v] = k + equaloplists(short, exp, remap=remap) + class TestUnroll(BaseTestUnroll): def test_simple(self): loop = """ @@ -69,7 +81,25 @@ # we have exported values for i1, which happens to be an inputarg assert es.inputarg_mapping[0][1].getint() == 1 assert isinstance(es.inputarg_mapping[0][1], ConstInt) - assert es.short_boxes == [] + sb = ShortPreambleBuilder(es.short_boxes, es.short_inputargs, + es.exported_infos) + sp = sb.build_short_preamble() + exp = """ + [i0] + jump() + """ + self.compare_short(sp, exp) + sb = ShortPreambleBuilder(es.short_boxes, es.short_inputargs, + es.exported_infos) + sb.use_box(es.short_boxes[0][0]) + assert len(es.short_boxes) == 1 + exp = """ + [i0] + i1 = int_add(i0, 1) + guard_value(i1, 1) [] + jump() + """ + self.compare_short(sb.build_short_preamble(), exp) def test_not_constant(self): loop = """ @@ -82,7 +112,7 @@ assert isinstance(vs.state[0], NotVirtualStateInfo) assert vs.state[0].level == LEVEL_UNKNOWN op = preamble.operations[0] - assert es.short_boxes == [(op, op)] + assert es.short_boxes[0][0] == op def test_guard_class(self): loop = """ @@ -131,7 +161,18 @@ jump(p0, i0) """ es, loop, preamble = self.optimize(loop) - assert es.short_boxes[0][0] == preamble.operations[0] + op = preamble.operations[0] + assert len(es.short_boxes) == 1 + assert es.short_boxes[0][0] is op + sb = ShortPreambleBuilder(es.short_boxes, es.short_inputargs, + es.exported_infos) + sb.use_box(preamble.operations[0]) + exp_short = """ + [p0, i1] + i0 = getfield_gc_i(p0, descr=valuedescr) + jump(i0) + """ + self.compare_short(sb.build_short_preamble(), exp_short) def test_int_is_true(self): loop = """ @@ -142,14 +183,34 @@ """ es, loop, preamble = self.optimize(loop) op = preamble.operations[0] - assert es.short_boxes == [(op,op)] + assert es.short_boxes[0][0] is op assert es.exported_infos[op].is_constant() def test_only_setfield(self): loop = """ + [p0, p1] + setfield_gc(p0, 5, descr=valuedescr) + setfield_gc(p1, 5, descr=nextdescr) + jump(p0, p1) + """ + es, loop, preamble = self.optimize(loop) + p0, p1 = preamble.inputargs + assert es.short_boxes[0][0].getint() == 5 + assert es.short_boxes[1][0].getint() == 5 + assert es.short_boxes[0][1].getarg(0) is p0 + assert es.short_boxes[1][1].getarg(0) is p1 + + def test_double_getfield_plus_pure(self): + loop = """ [p0] - setfield_gc(p0, 5, descr=valuedescr) + pc = getfield_gc_pure_r(p0, descr=nextdescr) + escape_n(p0) # that should flush the caches + p1 = getfield_gc_r(pc, descr=nextdescr) + i0 = getfield_gc_i(p1, descr=valuedescr) jump(p0) """ es, loop, preamble = self.optimize(loop) - assert es.short_boxes[0][0] == preamble.operations[0].getarg(1) + assert len(es.short_boxes) == 3 + # both getfields are available as + # well as getfield_gc_pure + diff --git a/rpython/jit/metainterp/optimizeopt/unroll.py b/rpython/jit/metainterp/optimizeopt/unroll.py --- a/rpython/jit/metainterp/optimizeopt/unroll.py +++ b/rpython/jit/metainterp/optimizeopt/unroll.py @@ -1,7 +1,8 @@ import sys from rpython.jit.metainterp.history import TargetToken, JitCellToken, Const -from rpython.jit.metainterp.optimizeopt.shortpreamble import ShortBoxes +from rpython.jit.metainterp.optimizeopt.shortpreamble import ShortBoxes,\ + ShortPreambleBuilder from rpython.jit.metainterp.optimize import InvalidLoop from rpython.jit.metainterp.optimizeopt import info, intutils from rpython.jit.metainterp.optimizeopt.optimizer import Optimizer,\ @@ -228,22 +229,23 @@ end_args = [self.get_box_replacement(a) for a in original_label_args] virtual_state = self.get_virtual_state(end_args) sb = ShortBoxes() - sb.create_short_boxes(self.optimizer, [self.get_box_replacement(a) - for a in start_label.getarglist()]) + short_boxes = sb.create_short_boxes(self.optimizer, renamed_inputargs) inparg_mapping = [(start_label.getarg(i), end_args[i]) for i in range(len(end_args)) if start_label.getarg(i) is not end_args[i]] infos = {} for arg in end_args: infos[arg] = self.optimizer.getinfo(arg) - for box, _ in sb.short_boxes: + for box, _ in short_boxes: if not isinstance(box, Const): infos[box] = self.optimizer.getinfo(box) label_args = virtual_state.make_inputargs(end_args, self.optimizer) + short_inputargs = sb.produce_short_inputargs() self.optimizer._clean_optimization_info(end_args) self.optimizer._clean_optimization_info(start_label.getarglist()) return ExportedState(label_args, inparg_mapping, virtual_state, infos, - sb.short_boxes, renamed_inputargs) + short_boxes, renamed_inputargs, + short_inputargs) inputargs = virtual_state.make_inputargs(jump_args, self.optimizer) @@ -302,22 +304,41 @@ self.optimizer.setinfo_from_preamble(source, info) # import the optimizer state, starting from boxes that can be produced # by short preamble - for op, preamble_op in exported_state.short_boxes: - if not isinstance(op, Const): - self.ops_to_import[op] = preamble_op - if preamble_op.is_always_pure(): - self.pure(op.getopnum(), PreambleOp(op, preamble_op, + self.short_preamble_producer = ShortPreambleProducer() + for op, getfield_op in exported_state.short_boxes: + if getfield_op is None: + optpure = self.optimizer.optpure + if optpure is None: + continue + self.pure(op.getopnum(), PreambleOp(op, None, exported_state.exported_infos.get(op, None))) else: - assert preamble_op.is_getfield() optheap = self.optimizer.optheap if optheap is None: continue - opinfo = self.optimizer.ensure_ptr_info_arg0(preamble_op) + opinfo = self.optimizer.ensure_ptr_info_arg0(getfield_op) pre_info = exported_state.exported_infos.get(op, None) - pop = PreambleOp(op, preamble_op, pre_info) + pop = PreambleOp(op, None, pre_info) assert not opinfo.is_virtual() - opinfo._fields[preamble_op.getdescr().get_index()] = pop + opinfo._fields[getfield_op.getdescr().get_index()] = pop + #if not isinstance(op, Const): + # self.ops_to_import[op] = None + # XXX think later about the short preamble + #if not isinstance(op, Const): + # self.ops_to_import[op] = preamble_op + #if preamble_op.is_always_pure(): + # self.pure(op.getopnum(), PreambleOp(op, preamble_op, + # exported_state.exported_infos.get(op, None))) + #else: + # assert preamble_op.is_getfield() + # optheap = self.optimizer.optheap + # if optheap is None: + # continue + # opinfo = self.optimizer.ensure_ptr_info_arg0(preamble_op) + # pre_info = exported_state.exported_infos.get(op, None) + # pop = PreambleOp(op, preamble_op, pre_info) + # assert not opinfo.is_virtual() + # opinfo._fields[preamble_op.getdescr().get_index()] = pop return self.inputargs = targetop.getarglist() @@ -774,13 +795,16 @@ of virtuals at this label * short boxes - a mapping op -> preamble_op * renamed_inputargs - the start label arguments in optimized version + * short_inputargs - the renamed inputargs for short preamble """ def __init__(self, end_args, inputarg_mapping, virtual_state, - exported_infos, short_boxes, renamed_inputargs): + exported_infos, short_boxes, renamed_inputargs, + short_inputargs): self.end_args = end_args self.inputarg_mapping = inputarg_mapping self.virtual_state = virtual_state self.exported_infos = exported_infos self.short_boxes = short_boxes self.renamed_inputargs = renamed_inputargs + self.short_inputargs = short_inputargs diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -12,6 +12,7 @@ _repr_memo = weakref.WeakKeyDictionary() is_info_class = False _attrs_ = () + namespace = None def _get_hash_(self): return compute_identity_hash(self) @@ -185,7 +186,10 @@ return name def __repr__(self): - return self.repr(self._repr_memo) + r = self.repr(self._repr_memo) + if self.namespace is not None: + return "<" + self.namespace + ">" + r + return r def getopname(self): try: _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit