Author: Armin Rigo <ar...@tunes.org> Branch: conditional_call_value_4 Changeset: r88630:6d3400d6ed8f Date: 2016-11-24 11:16 +0000 http://bitbucket.org/pypy/pypy/changeset/6d3400d6ed8f/
Log: Revert the @jit.call_shortcut support (6305cfb3bad2) diff --git a/rpython/jit/backend/llsupport/rewrite.py b/rpython/jit/backend/llsupport/rewrite.py --- a/rpython/jit/backend/llsupport/rewrite.py +++ b/rpython/jit/backend/llsupport/rewrite.py @@ -11,7 +11,7 @@ from rpython.jit.backend.llsupport.symbolic import (WORD, get_field_token, get_array_token) from rpython.jit.backend.llsupport.descr import SizeDescr, ArrayDescr,\ - FLAG_POINTER, CallDescr + FLAG_POINTER from rpython.jit.metainterp.history import JitCellToken from rpython.jit.backend.llsupport.descr import (unpack_arraydescr, unpack_fielddescr, unpack_interiorfielddescr) @@ -359,9 +359,7 @@ self.consider_setfield_gc(op) elif op.getopnum() == rop.SETARRAYITEM_GC: self.consider_setarrayitem_gc(op) - # ---------- calls ----------- - if OpHelpers.is_plain_call(op.getopnum()): - self.expand_call_shortcut(op) + # ---------- call assembler ----------- if OpHelpers.is_call_assembler(op.getopnum()): self.handle_call_assembler(op) continue @@ -607,31 +605,6 @@ self.emit_gc_store_or_indexed(None, ptr, ConstInt(0), value, size, 1, ofs) - def expand_call_shortcut(self, op): - descr = op.getdescr() - if descr is None: - return - assert isinstance(descr, CallDescr) - effectinfo = descr.get_extra_info() - if effectinfo is None or effectinfo.call_shortcut is None: - return - if op.type == 'r': - cond_call_opnum = rop.COND_CALL_VALUE_R - elif op.type == 'i': - cond_call_opnum = rop.COND_CALL_VALUE_I - else: - return - cs = effectinfo.call_shortcut - ptr_box = op.getarg(1 + cs.argnum) - if cs.fielddescr is not None: - value_box = self.emit_getfield(ptr_box, descr=cs.fielddescr, - raw=(ptr_box.type == 'i')) - else: - value_box = ptr_box - self.replace_op_with(op, ResOperation(cond_call_opnum, - [value_box] + op.getarglist(), - descr=descr)) - def handle_call_assembler(self, op): descrs = self.gc_ll_descr.getframedescrs(self.cpu) loop_token = op.getdescr() diff --git a/rpython/jit/backend/llsupport/test/test_rewrite.py b/rpython/jit/backend/llsupport/test/test_rewrite.py --- a/rpython/jit/backend/llsupport/test/test_rewrite.py +++ b/rpython/jit/backend/llsupport/test/test_rewrite.py @@ -1,8 +1,7 @@ import py from rpython.jit.backend.llsupport.descr import get_size_descr,\ get_field_descr, get_array_descr, ArrayDescr, FieldDescr,\ - SizeDescr, get_interiorfield_descr, get_call_descr -from rpython.jit.codewriter.effectinfo import EffectInfo, CallShortcut + SizeDescr, get_interiorfield_descr from rpython.jit.backend.llsupport.gc import GcLLDescr_boehm,\ GcLLDescr_framework from rpython.jit.backend.llsupport import jitframe @@ -81,21 +80,6 @@ lltype.malloc(T, zero=True)) self.myT = myT # - call_shortcut = CallShortcut(0, tzdescr) - effectinfo = EffectInfo(None, None, None, None, None, None, - EffectInfo.EF_RANDOM_EFFECTS, - call_shortcut=call_shortcut) - call_shortcut_descr = get_call_descr(self.gc_ll_descr, - [lltype.Ptr(T)], lltype.Signed, - effectinfo) - call_shortcut_2 = CallShortcut(0, None) - effectinfo_2 = EffectInfo(None, None, None, None, None, None, - EffectInfo.EF_RANDOM_EFFECTS, - call_shortcut=call_shortcut_2) - call_shortcut_descr_2 = get_call_descr(self.gc_ll_descr, - [lltype.Signed], lltype.Signed, - effectinfo_2) - # A = lltype.GcArray(lltype.Signed) adescr = get_array_descr(self.gc_ll_descr, A) adescr.tid = 4321 @@ -1452,26 +1436,3 @@ jump() """) assert len(self.gcrefs) == 2 - - def test_handle_call_shortcut(self): - self.check_rewrite(""" - [p0] - i1 = call_i(123, p0, descr=call_shortcut_descr) - jump(i1) - """, """ - [p0] - i2 = gc_load_i(p0, %(tzdescr.offset)s, %(tzdescr.field_size)s) - i1 = cond_call_value_i(i2, 123, p0, descr=call_shortcut_descr) - jump(i1) - """) - - def test_handle_call_shortcut_2(self): - self.check_rewrite(""" - [i0] - i1 = call_i(123, i0, descr=call_shortcut_descr_2) - jump(i1) - """, """ - [i0] - i1 = cond_call_value_i(i0, 123, i0, descr=call_shortcut_descr_2) - jump(i1) - """) diff --git a/rpython/jit/codewriter/call.py b/rpython/jit/codewriter/call.py --- a/rpython/jit/codewriter/call.py +++ b/rpython/jit/codewriter/call.py @@ -7,10 +7,9 @@ from rpython.jit.codewriter.jitcode import JitCode from rpython.jit.codewriter.effectinfo import (VirtualizableAnalyzer, QuasiImmutAnalyzer, RandomEffectsAnalyzer, effectinfo_from_writeanalyze, - EffectInfo, CallInfoCollection, CallShortcut) + EffectInfo, CallInfoCollection) from rpython.rtyper.lltypesystem import lltype, llmemory from rpython.rtyper.lltypesystem.lltype import getfunctionptr -from rpython.flowspace.model import Constant, Variable from rpython.rlib import rposix from rpython.translator.backendopt.canraise import RaiseAnalyzer from rpython.translator.backendopt.writeanalyze import ReadWriteAnalyzer @@ -215,7 +214,6 @@ elidable = False loopinvariant = False call_release_gil_target = EffectInfo._NO_CALL_RELEASE_GIL_TARGET - call_shortcut = None if op.opname == "direct_call": funcobj = op.args[0].value._obj assert getattr(funcobj, 'calling_conv', 'c') == 'c', ( @@ -230,12 +228,6 @@ tgt_func, tgt_saveerr = func._call_aroundstate_target_ tgt_func = llmemory.cast_ptr_to_adr(tgt_func) call_release_gil_target = (tgt_func, tgt_saveerr) - if hasattr(funcobj, 'graph'): - call_shortcut = self.find_call_shortcut(funcobj.graph) - if getattr(func, "_call_shortcut_", False): - assert call_shortcut is not None, ( - "%r: marked as @jit.call_shortcut but shortcut not found" - % (func,)) elif op.opname == 'indirect_call': # check that we're not trying to call indirectly some # function with the special flags @@ -250,8 +242,6 @@ error = '@jit.loop_invariant' if hasattr(graph.func, '_call_aroundstate_target_'): error = '_call_aroundstate_target_' - if hasattr(graph.func, '_call_shortcut_'): - error = '@jit.call_shortcut' if not error: continue raise Exception( @@ -308,7 +298,6 @@ self.readwrite_analyzer.analyze(op, self.seen_rw), self.cpu, extraeffect, oopspecindex, can_invalidate, call_release_gil_target, extradescr, self.collect_analyzer.analyze(op, self.seen_gc), - call_shortcut, ) # assert effectinfo is not None @@ -379,76 +368,3 @@ if GTYPE_fieldname in jd.greenfield_info.green_fields: return True return False - - def find_call_shortcut(self, graph): - """Identifies graphs that start like this: - - def graph(x, y, z): def graph(x, y, z): - if y.field: r = y.field - return y.field if r: return r - """ - block = graph.startblock - operations = block.operations - c_fieldname = None - if not operations: - v_inst = v_result = block.exitswitch - else: - op = operations[0] - if len(op.args) == 0: - return - if op.opname != 'getfield': # check for this form: - v_inst = op.args[0] # if y is not None; - v_result = v_inst # return y - else: - operations = operations[1:] - [v_inst, c_fieldname] = op.args - v_result = op.result - if not isinstance(v_inst, Variable): - return - if v_result.concretetype != graph.getreturnvar().concretetype: - return - if v_result.concretetype == lltype.Void: - return - argnum = i = 0 - while block.inputargs[i] is not v_inst: - if block.inputargs[i].concretetype != lltype.Void: - argnum += 1 - i += 1 - PSTRUCT = v_inst.concretetype - v_check = v_result - fastcase = True - for op in operations: - if (op.opname in ('int_is_true', 'ptr_nonzero', 'same_as') - and v_check is op.args[0]): - v_check = op.result - elif op.opname == 'ptr_iszero' and v_check is op.args[0]: - v_check = op.result - fastcase = not fastcase - elif (op.opname in ('int_eq', 'int_ne') - and v_check is op.args[0] - and isinstance(op.args[1], Constant) - and op.args[1].value == 0): - v_check = op.result - if op.opname == 'int_eq': - fastcase = not fastcase - else: - return - if v_check.concretetype is not lltype.Bool: - return - if block.exitswitch is not v_check: - return - - links = [link for link in block.exits if link.exitcase == fastcase] - if len(links) != 1: - return - [link] = links - if link.args != [v_result]: - return - if not link.target.is_final_block(): - return - - if c_fieldname is not None: - fielddescr = self.cpu.fielddescrof(PSTRUCT.TO, c_fieldname.value) - else: - fielddescr = None - return CallShortcut(argnum, fielddescr) diff --git a/rpython/jit/codewriter/effectinfo.py b/rpython/jit/codewriter/effectinfo.py --- a/rpython/jit/codewriter/effectinfo.py +++ b/rpython/jit/codewriter/effectinfo.py @@ -117,8 +117,7 @@ can_invalidate=False, call_release_gil_target=_NO_CALL_RELEASE_GIL_TARGET, extradescrs=None, - can_collect=True, - call_shortcut=None): + can_collect=True): readonly_descrs_fields = frozenset_or_none(readonly_descrs_fields) readonly_descrs_arrays = frozenset_or_none(readonly_descrs_arrays) readonly_descrs_interiorfields = frozenset_or_none( @@ -136,8 +135,7 @@ extraeffect, oopspecindex, can_invalidate, - can_collect, - call_shortcut) + can_collect) tgt_func, tgt_saveerr = call_release_gil_target if tgt_func: key += (object(),) # don't care about caching in this case @@ -192,7 +190,6 @@ result.oopspecindex = oopspecindex result.extradescrs = extradescrs result.call_release_gil_target = call_release_gil_target - result.call_shortcut = call_shortcut if result.check_can_raise(ignore_memoryerror=True): assert oopspecindex in cls._OS_CANRAISE @@ -278,8 +275,7 @@ call_release_gil_target= EffectInfo._NO_CALL_RELEASE_GIL_TARGET, extradescr=None, - can_collect=True, - call_shortcut=None): + can_collect=True): from rpython.translator.backendopt.writeanalyze import top_set if effects is top_set or extraeffect == EffectInfo.EF_RANDOM_EFFECTS: readonly_descrs_fields = None @@ -368,8 +364,7 @@ can_invalidate, call_release_gil_target, extradescr, - can_collect, - call_shortcut) + can_collect) def consider_struct(TYPE, fieldname): if fieldType(TYPE, fieldname) is lltype.Void: @@ -392,24 +387,6 @@ # ____________________________________________________________ - -class CallShortcut(object): - def __init__(self, argnum, fielddescr): - self.argnum = argnum - self.fielddescr = fielddescr - - def __eq__(self, other): - return (isinstance(other, CallShortcut) and - self.argnum == other.argnum and - self.fielddescr == other.fielddescr) - def __ne__(self, other): - return not (self == other) - def __hash__(self): - return hash((self.argnum, self.fielddescr)) - -# ____________________________________________________________ - - class VirtualizableAnalyzer(BoolGraphAnalyzer): def analyze_simple_operation(self, op, graphinfo): return op.opname in ('jit_force_virtualizable', diff --git a/rpython/jit/codewriter/test/test_call.py b/rpython/jit/codewriter/test/test_call.py --- a/rpython/jit/codewriter/test/test_call.py +++ b/rpython/jit/codewriter/test/test_call.py @@ -6,7 +6,7 @@ from rpython.rlib import jit from rpython.jit.codewriter import support, call from rpython.jit.codewriter.call import CallControl -from rpython.jit.codewriter.effectinfo import EffectInfo, CallShortcut +from rpython.jit.codewriter.effectinfo import EffectInfo class FakePolicy: @@ -368,121 +368,3 @@ assert call_op.opname == 'direct_call' call_descr = cc.getcalldescr(call_op) assert call_descr.extrainfo.check_can_collect() == expected - -def test_find_call_shortcut(): - class FakeCPU: - def fielddescrof(self, TYPE, fieldname): - if isinstance(TYPE, lltype.GcStruct): - if fieldname == 'inst_foobar': - return 'foobardescr' - if fieldname == 'inst_fooref': - return 'foorefdescr' - if TYPE == RAW and fieldname == 'x': - return 'xdescr' - assert False, (TYPE, fieldname) - cc = CallControl(FakeCPU()) - - class B(object): - foobar = 0 - fooref = None - - def f1(a, b, c): - if b.foobar: - return b.foobar - b.foobar = a + c - return b.foobar - - def f2(x, y, z, b): - r = b.fooref - if r is not None: - return r - r = b.fooref = B() - return r - - class Space(object): - def _freeze_(self): - return True - space = Space() - - def f3(space, b): - r = b.foobar - if not r: - r = b.foobar = 123 - return r - - def f4(raw): - r = raw.x - if r != 0: - return r - raw.x = 123 - return 123 - RAW = lltype.Struct('RAW', ('x', lltype.Signed)) - - def f5(b): - r = b.foobar - if r == 0: - r = b.foobar = 123 - return r - - def f6(b): - if b is not None: - return b - return B() - - def f7(c, a): - if a: - return a - return 123 - - def b_or_none(c): - if c > 15: - return B() - return None - - def f(a, c): - b = B() - f1(a, b, c) - f2(a, c, a, b) - f3(space, b) - r = lltype.malloc(RAW, flavor='raw') - f4(r) - f5(b) - f6(b_or_none(c)) - f7(c, a) - - rtyper = support.annotate(f, [10, 20]) - f1_graph = rtyper.annotator.translator._graphof(f1) - assert cc.find_call_shortcut(f1_graph) == CallShortcut(1, "foobardescr") - f2_graph = rtyper.annotator.translator._graphof(f2) - assert cc.find_call_shortcut(f2_graph) == CallShortcut(3, "foorefdescr") - f3_graph = rtyper.annotator.translator._graphof(f3) - assert cc.find_call_shortcut(f3_graph) == CallShortcut(0, "foobardescr") - f4_graph = rtyper.annotator.translator._graphof(f4) - assert cc.find_call_shortcut(f4_graph) == CallShortcut(0, "xdescr") - f5_graph = rtyper.annotator.translator._graphof(f5) - assert cc.find_call_shortcut(f5_graph) == CallShortcut(0, "foobardescr") - f6_graph = rtyper.annotator.translator._graphof(f6) - assert cc.find_call_shortcut(f6_graph) == CallShortcut(0, None) - f7_graph = rtyper.annotator.translator._graphof(f7) - assert cc.find_call_shortcut(f7_graph) == CallShortcut(1, None) - -def test_cant_find_call_shortcut(): - from rpython.jit.backend.llgraph.runner import LLGraphCPU - - @jit.dont_look_inside - @jit.call_shortcut - def f1(n): - return n + 17 # no call shortcut found - - def f(n): - return f1(n) - - rtyper = support.annotate(f, [1]) - jitdriver_sd = FakeJitDriverSD(rtyper.annotator.translator.graphs[0]) - cc = CallControl(LLGraphCPU(rtyper), jitdrivers_sd=[jitdriver_sd]) - res = cc.find_all_graphs(FakePolicy()) - [f_graph] = [x for x in res if x.func is f] - call_op = f_graph.startblock.operations[0] - assert call_op.opname == 'direct_call' - e = py.test.raises(AssertionError, cc.getcalldescr, call_op) - assert "shortcut not found" in str(e.value) diff --git a/rpython/rlib/jit.py b/rpython/rlib/jit.py --- a/rpython/rlib/jit.py +++ b/rpython/rlib/jit.py @@ -257,27 +257,6 @@ func.oopspec = "jit.not_in_trace()" # note that 'func' may take arguments return func -def call_shortcut(func): - """A decorator to ensure that a function has a fast-path. - DOES NOT RELIABLY WORK ON METHODS, USE ONLY ON FUNCTIONS! - - Only useful on functions that the JIT doesn't normally look inside. - It still replaces residual calls to that function with inline code - that checks for a fast path, and only does the call if not. For - now, graphs made by the following kinds of functions are detected: - - def func(x, y, z): def func(x, y, z): - if y.field: r = y.field - return y.field if r is None: - ... ... - return r - - Fast-path detection is always on, but this decorator makes the - codewriter complain if it cannot find the promized fast-path. - """ - func._call_shortcut_ = True - return func - @oopspec("jit.isconstant(value)") @specialize.call_location() _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit