Author: Carl Friedrich Bolz <cfb...@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 + _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit