[pypy-commit] pypy optresult-unroll: work some more on short preamble
fijal
noreply at buildbot.pypy.org
Fri Jul 17 11:48:18 CEST 2015
Author: Maciej Fijalkowski <fijall at 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:
More information about the pypy-commit
mailing list