[pypy-commit] pypy conditional_call_value_4: Revert the @jit.call_shortcut support (6305cfb3bad2)

arigo pypy.commits at gmail.com
Thu Nov 24 06:06:28 EST 2016


Author: Armin Rigo <arigo at 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()


More information about the pypy-commit mailing list