[pypy-commit] pypy conditional_call_value_4: copy and adapt from the conditional_call_value_2 branch: goal

arigo pypy.commits at gmail.com
Tue Nov 22 05:52:54 EST 2016


Author: Armin Rigo <arigo at tunes.org>
Branch: conditional_call_value_4
Changeset: r88540:c73bebe15c32
Date: 2016-11-22 11:52 +0100
http://bitbucket.org/pypy/pypy/changeset/c73bebe15c32/

Log:	copy and adapt from the conditional_call_value_2 branch: goal

diff --git a/rpython/rlib/jit.py b/rpython/rlib/jit.py
--- a/rpython/rlib/jit.py
+++ b/rpython/rlib/jit.py
@@ -1194,10 +1194,19 @@
         return hop.gendirectcall(ll_record_exact_class, v_inst, v_cls)
 
 def _jit_conditional_call(condition, function, *args):
-    pass
+    pass           # special-cased below
 
 @specialize.call_location()
 def conditional_call(condition, function, *args):
+    """Does the same as:
+
+         if condition:
+             function(*args)
+
+    but is better for the JIT, in case the condition is often false
+    but could be true occasionally.  It allows the JIT to always produce
+    bridge-free code.  The function is never looked inside.
+    """
     if we_are_jitted():
         _jit_conditional_call(condition, function, *args)
     else:
@@ -1205,21 +1214,58 @@
             function(*args)
 conditional_call._always_inline_ = True
 
+def _jit_conditional_call_value(value, function, *args):
+    return value    # special-cased below
+
+ at specialize.call_location()
+def conditional_call_value(value, function, *args):
+    """Does the same as:
+
+        if not value:
+            value = function(*args)
+        return value
+
+    For the JIT.  Allows one branch which doesn't create a bridge,
+    typically used for caching.  The function must be @elidable.
+    The value and the function's return type must match and cannot
+    be a float.
+    """
+    if we_are_jitted():
+        return _jit_conditional_call_value(value, function, *args)
+    else:
+        if not value:
+            value = function(*args)
+        return value
+conditional_call_value._always_inline_ = True
+
 class ConditionalCallEntry(ExtRegistryEntry):
-    _about_ = _jit_conditional_call
+    _about_ = _jit_conditional_call, _jit_conditional_call_value
 
     def compute_result_annotation(self, *args_s):
-        self.bookkeeper.emulate_pbc_call(self.bookkeeper.position_key,
-                                         args_s[1], args_s[2:])
+        s_res = self.bookkeeper.emulate_pbc_call(self.bookkeeper.position_key,
+                                                 args_s[1], args_s[2:])
+        if self.instance == _jit_conditional_call_value:
+            from rpython.annotator import model as annmodel
+            return annmodel.unionof(s_res, args_s[0])
 
     def specialize_call(self, hop):
         from rpython.rtyper.lltypesystem import lltype
 
-        args_v = hop.inputargs(lltype.Bool, lltype.Void, *hop.args_r[2:])
+        if self.instance == _jit_conditional_call:
+            opname = 'jit_conditional_call'
+            COND = lltype.Bool
+            resulttype = None
+        elif self.instance == _jit_conditional_call_value:
+            opname = 'jit_conditional_call_value'
+            COND = hop.r_result
+            resulttype = hop.r_result.lowleveltype
+        else:
+            assert False
+        args_v = hop.inputargs(COND, lltype.Void, *hop.args_r[2:])
         args_v[1] = hop.args_r[1].get_concrete_llfn(hop.args_s[1],
                                                     hop.args_s[2:], hop.spaceop)
         hop.exception_is_here()
-        return hop.genop('jit_conditional_call', args_v)
+        return hop.genop(opname, args_v, resulttype=resulttype)
 
 def enter_portal_frame(unique_id):
     """call this when starting to interpret a function. calling this is not
diff --git a/rpython/rlib/test/test_jit.py b/rpython/rlib/test/test_jit.py
--- a/rpython/rlib/test/test_jit.py
+++ b/rpython/rlib/test/test_jit.py
@@ -3,7 +3,7 @@
 from rpython.conftest import option
 from rpython.annotator.model import UnionError
 from rpython.rlib.jit import (hint, we_are_jitted, JitDriver, elidable_promote,
-    JitHintError, oopspec, isconstant, conditional_call,
+    JitHintError, oopspec, isconstant, conditional_call, conditional_call_value,
     elidable, unroll_safe, dont_look_inside,
     enter_portal_frame, leave_portal_frame)
 from rpython.rlib.rarithmetic import r_uint
@@ -302,6 +302,18 @@
         mix.getgraph(later, [annmodel.s_Bool], annmodel.s_None)
         mix.finish()
 
+    def test_conditional_call_value(self):
+        def g(x, y):
+            return x - y + 5
+        def f(n, x, y):
+            return conditional_call_value(n, g, x, y)
+        assert f(0, 1000, 100) == 905
+        res = self.interpret(f, [0, 1000, 100])
+        assert res == 905
+        assert f(-42, 1000, 100) == -42
+        res = self.interpret(f, [-42, 1000, 100])
+        assert res == -42
+
     def test_enter_leave_portal_frame(self):
         from rpython.translator.interactive import Translation
         def g():


More information about the pypy-commit mailing list