[pypy-commit] pypy optinfo-into-bridges: optimize heap knowledge too
cfbolz
pypy.commits at gmail.com
Wed Oct 12 14:12:47 EDT 2016
Author: Carl Friedrich Bolz <cfbolz at gmx.de>
Branch: optinfo-into-bridges
Changeset: r87736:6e71ace09797
Date: 2016-10-12 20:10 +0200
http://bitbucket.org/pypy/pypy/changeset/6e71ace09797/
Log: optimize heap knowledge too (just simple cases, only GC objects, no
lazy getfields, no arrays)
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
@@ -102,7 +102,7 @@
self.call_pure_results,
self.inline_short_preamble,
self.box_names_memo,
- self.resumestorage.rd_numb)
+ self.resumestorage)
class UnrolledLoopData(CompileData):
""" This represents label() ops jump with extra info that's from the
diff --git a/rpython/jit/metainterp/optimizeopt/bridgeopt.py b/rpython/jit/metainterp/optimizeopt/bridgeopt.py
--- a/rpython/jit/metainterp/optimizeopt/bridgeopt.py
+++ b/rpython/jit/metainterp/optimizeopt/bridgeopt.py
@@ -15,9 +15,43 @@
# (the class is found by actually looking at the runtime value)
# the bits are bunched in bunches of 7
#
+# ---- heap knowledge
+# <length>
+# (<box1> <descr> <box2>) length times, if getfield(box1, descr) == box2
+# both boxes should be in the liveboxes
+#
# ----
-def serialize_optimizer_knowledge(optimizer, numb_state, liveboxes, memo):
+def tag_box(box, liveboxes_from_env, memo):
+ from rpython.jit.metainterp.history import Const
+ # XXX bit of code duplication (but it's a subset)
+ if isinstance(box, Const):
+ return memo.getconst(box)
+ else:
+ return liveboxes_from_env[box] # has to exist
+
+def decode_box(resumestorage, tagged, liveboxes, cpu):
+ from rpython.jit.metainterp.resume import untag, TAGCONST, TAGINT, TAGBOX
+ from rpython.jit.metainterp.resume import NULLREF, TAG_CONST_OFFSET, tagged_eq
+ from rpython.jit.metainterp.history import ConstInt
+ num, tag = untag(tagged)
+ if tag == TAGCONST:
+ if tagged_eq(tagged, NULLREF):
+ box = cpu.ts.CONST_NULL
+ else:
+ box = resumestorage.rd_consts[num - TAG_CONST_OFFSET]
+ elif tag == TAGINT:
+ box = ConstInt(num)
+ elif tag == TAGBOX:
+ box = liveboxes[num]
+ else:
+ raise AssertionError("unreachable")
+ return box
+
+def serialize_optimizer_knowledge(optimizer, numb_state, liveboxes, liveboxes_from_env, memo):
+ liveboxes_set = set(liveboxes)
+ metainterp_sd = optimizer.metainterp_sd
+
numb_state.grow(len(liveboxes)) # bit too much
# class knowledge
bitfield = 0
@@ -36,9 +70,26 @@
if shifts:
numb_state.append_int(bitfield << (7 - shifts))
-def deserialize_optimizer_knowledge(optimizer, numb, runtime_boxes, liveboxes):
+ # heap knowledge
+ if optimizer.optheap:
+ triples = optimizer.optheap.serialize_optheap(liveboxes_set)
+ numb_state.grow(len(triples) * 3 + 1)
+ numb_state.append_int(len(triples))
+ for box1, descr, box2 in triples:
+ numb_state.append_short(tag_box(box1, liveboxes_from_env, memo))
+ numb_state.append_int(metainterp_sd.descrs_dct[descr])
+ numb_state.append_short(tag_box(box2, liveboxes_from_env, memo))
+ else:
+ numb_state.grow(1)
+ numb_state.append_int(0)
+
+def deserialize_optimizer_knowledge(optimizer, resumestorage, runtime_boxes, liveboxes):
+ numb = resumestorage.rd_numb
+ metainterp_sd = optimizer.metainterp_sd
+
# skip resume section
index = skip_resume_section(numb, optimizer)
+
# class knowledge
bitfield = 0
mask = 0
@@ -54,6 +105,20 @@
cls = optimizer.cpu.ts.cls_of_box(runtime_boxes[i])
optimizer.make_constant_class(box, cls)
+ # heap knowledge
+ length, index = numb_next_item(numb, index)
+ result = []
+ for i in range(length):
+ tagged, index = numb_next_item(numb, index)
+ box1 = decode_box(resumestorage, tagged, liveboxes, metainterp_sd.cpu)
+ tagged, index = numb_next_item(numb, index)
+ descr = metainterp_sd.opcode_descrs[tagged]
+ tagged, index = numb_next_item(numb, index)
+ box2 = decode_box(resumestorage, tagged, liveboxes, metainterp_sd.cpu)
+ result.append((box1, descr, box2))
+ if optimizer.optheap:
+ optimizer.optheap.deserialize_optheap(result)
+
def skip_resume_section(numb, optimizer):
startcount, index = numb_next_item(numb, 0)
return numb_next_n_items(numb, startcount, 0)
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
@@ -48,6 +48,7 @@
# that has a non-None entry at
# info._fields[descr.get_index()]
# must be in cache_infos
+ assert structop.type == 'r'
self.cached_structs.append(structop)
self.cached_infos.append(info)
@@ -693,6 +694,37 @@
self._seen_guard_not_invalidated = True
return self.emit(op)
+ def serialize_optheap(self, liveboxes_set):
+ # XXX wrong complexity?
+ result = []
+ for descr, cf in self.cached_fields.iteritems():
+ if cf._lazy_set:
+ continue # XXX safe default for now
+ parent_descr = descr.get_parent_descr()
+ if not parent_descr.is_object():
+ continue
+ for i, box1 in enumerate(cf.cached_structs):
+ if box1 not in liveboxes_set:
+ continue
+ structinfo = cf.cached_infos[i]
+ box2 = structinfo.getfield(descr).get_box_replacement()
+ if isinstance(box2, Const) or box2 in liveboxes_set:
+ result.append((box1, descr, box2))
+ return result
+
+ def deserialize_optheap(self, triples):
+ for box1, descr, box2 in triples:
+ parent_descr = descr.get_parent_descr()
+ assert parent_descr.is_object()
+ structinfo = box1.get_forwarded()
+ if not isinstance(structinfo, info.AbstractVirtualPtrInfo):
+ structinfo = info.InstancePtrInfo(parent_descr)
+ structinfo.init_fields(parent_descr, descr.get_index())
+ box1.set_forwarded(structinfo)
+
+ cf = self.field_cache(descr)
+ structinfo.setfield(descr, box1, box2, optheap=self, cf=cf)
+
dispatch_opt = make_dispatcher_method(OptHeap, 'optimize_',
default=OptHeap.emit)
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
@@ -74,13 +74,13 @@
descr = self.getfield_op.getdescr()
if rop.is_getfield(g.opnum):
cf = optheap.field_cache(descr)
- opinfo.setfield(preamble_op.getdescr(), self.res, pop,
+ opinfo.setfield(preamble_op.getdescr(), g.getarg(0), pop,
optheap, cf)
else:
index = g.getarg(1).getint()
assert index >= 0
cf = optheap.arrayitem_cache(descr, index)
- opinfo.setitem(self.getfield_op.getdescr(), index, self.res,
+ opinfo.setitem(self.getfield_op.getdescr(), index, g.getarg(0),
pop, optheap, cf)
def repr(self, memo):
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
@@ -237,12 +237,12 @@
return label_vs
def optimize_bridge(self, trace, runtime_boxes, call_pure_results,
- inline_short_preamble, box_names_memo, numb):
+ inline_short_preamble, box_names_memo, resumestorage):
from rpython.jit.metainterp.optimizeopt.bridgeopt import deserialize_optimizer_knowledge
trace = trace.get_iter()
self._check_no_forwarding([trace.inputargs])
deserialize_optimizer_knowledge(self.optimizer,
- numb, runtime_boxes,
+ resumestorage, runtime_boxes,
trace.inputargs)
info, ops = self.optimizer.propagate_all_forward(trace,
call_pure_results, False)
diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py
--- a/rpython/jit/metainterp/pyjitpl.py
+++ b/rpython/jit/metainterp/pyjitpl.py
@@ -1815,6 +1815,9 @@
def setup_descrs(self, descrs):
self.opcode_descrs = descrs
+ self.descrs_dct = {}
+ for index, descr in enumerate(descrs):
+ self.descrs_dct[descr] = index
def setup_indirectcalltargets(self, indirectcalltargets):
self.indirectcalltargets = list(indirectcalltargets)
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
@@ -748,7 +748,6 @@
def __init__(self, r=lltype.nullptr(llmemory.GCREF.TO)):
self.setref_base(r)
- self.datatype = 'r'
def reset_value(self):
self.setref_base(lltype.nullptr(llmemory.GCREF.TO))
diff --git a/rpython/jit/metainterp/resume.py b/rpython/jit/metainterp/resume.py
--- a/rpython/jit/metainterp/resume.py
+++ b/rpython/jit/metainterp/resume.py
@@ -483,7 +483,7 @@
self._number_virtuals(liveboxes, optimizer, num_virtuals)
self._add_pending_fields(optimizer, pending_setfields)
- self._add_optimizer_sections(numb_state, liveboxes)
+ self._add_optimizer_sections(numb_state, liveboxes, liveboxes_from_env)
storage.rd_numb = numb_state.create_numbering()
storage.rd_consts = self.memo.consts
return liveboxes[:]
@@ -603,10 +603,11 @@
return self.liveboxes_from_env[box]
return self.liveboxes[box]
- def _add_optimizer_sections(self, numb_state, liveboxes):
+ def _add_optimizer_sections(self, numb_state, liveboxes, liveboxes_from_env):
# add extra information about things the optimizer learned
from rpython.jit.metainterp.optimizeopt.bridgeopt import serialize_optimizer_knowledge
- serialize_optimizer_knowledge(self.optimizer, numb_state, liveboxes, self.memo)
+ serialize_optimizer_knowledge(
+ self.optimizer, numb_state, liveboxes, liveboxes_from_env, self.memo)
class AbstractVirtualInfo(object):
kind = REF
diff --git a/rpython/jit/metainterp/test/test_bridgeopt.py b/rpython/jit/metainterp/test/test_bridgeopt.py
--- a/rpython/jit/metainterp/test/test_bridgeopt.py
+++ b/rpython/jit/metainterp/test/test_bridgeopt.py
@@ -22,6 +22,7 @@
class FakeOptimizer(object):
metainterp_sd = None
+ optheap = None
def __init__(self, dct={}, cpu=None):
self.dct = dct
@@ -37,6 +38,10 @@
class FakeClass(object):
pass
+class FakeStorage(object):
+ def __init__(self, numb):
+ self.rd_numb = numb
+
def test_simple():
box1 = InputArgRef()
box2 = InputArgRef()
@@ -50,16 +55,16 @@
numb_state.append_int(1) # vinfo
liveboxes = [InputArgInt(), box2, box1, box3]
- serialize_optimizer_knowledge(optimizer, numb_state, liveboxes, None)
+ serialize_optimizer_knowledge(optimizer, numb_state, liveboxes, {}, None)
- assert numb_state.current[:numb_state._pos] == [1, 0b0100000]
+ assert numb_state.current[:numb_state._pos] == [1, 0b0100000, 0]
rbox1 = InputArgRef()
rbox2 = InputArgRef()
rbox3 = InputArgRef()
after_optimizer = FakeOptimizer(cpu=FakeCPU({rbox1: cls}))
deserialize_optimizer_knowledge(
- after_optimizer, numb_state.create_numbering(),
+ after_optimizer, FakeStorage(numb_state.create_numbering()),
[InputArgInt(), rbox2, rbox1, rbox3], liveboxes)
assert box1 in after_optimizer.constant_classes
assert box2 not in after_optimizer.constant_classes
@@ -68,7 +73,7 @@
class TestOptBridge(LLJitMixin):
# integration tests
- def test_bridge(self):
+ def test_bridge_guard_class(self):
myjitdriver = jit.JitDriver(greens=[], reds=['y', 'res', 'n', 'a'])
class A(object):
def f(self):
@@ -96,3 +101,50 @@
assert res == f(6, 32, 16)
self.check_trace_count(3)
self.check_resops(guard_class=1)
+
+ def test_bridge_field_read(self):
+ myjitdriver = jit.JitDriver(greens=[], reds=['y', 'res', 'n', 'a'])
+ class A(object):
+ def f(self):
+ return 1
+ class B(A):
+ def f(self):
+ return 2
+ class M(object):
+ _immutable_fields_ = ['x']
+ def __init__(self, x):
+ self.x = x
+
+ m1 = M(1)
+ m2 = M(2)
+ def f(x, y, n):
+ if x:
+ a = A()
+ a.m = m1
+ a.n = n
+ else:
+ a = B()
+ a.m = m2
+ a.n = n
+ a.x = 0
+ res = 0
+ while y > 0:
+ myjitdriver.jit_merge_point(y=y, n=n, res=res, a=a)
+ n1 = a.n
+ m = jit.promote(a.m)
+ res += m.x
+ a.x += 1
+ if y > n:
+ res += 1
+ m = jit.promote(a.m)
+ res += m.x
+ res += n1 + a.n
+ y -= 1
+ return res
+ res = self.meta_interp(f, [6, 32, 16])
+ assert res == f(6, 32, 16)
+ self.check_trace_count(3)
+ self.check_resops(guard_value=1)
+ self.check_resops(getfield_gc_i=4) # 3x a.x, 1x a.n
+ self.check_resops(getfield_gc_r=1) # in main loop
+
More information about the pypy-commit
mailing list