Author: Armin Rigo <[email protected]>
Branch: conditional_call_value_4
Changeset: r88572:1e9f2a40fd2e
Date: 2016-11-23 11:00 +0100
http://bitbucket.org/pypy/pypy/changeset/1e9f2a40fd2e/
Log: From conditional_call_value_2: found out again why we'd like the
function to be only "almost" elidable
diff --git a/rpython/jit/metainterp/test/test_ajit.py
b/rpython/jit/metainterp/test/test_ajit.py
--- a/rpython/jit/metainterp/test/test_ajit.py
+++ b/rpython/jit/metainterp/test/test_ajit.py
@@ -4577,12 +4577,11 @@
self.check_resops(guard_true=10) # 5 unrolled, plus 5 unrelated
def test_conditional_call_value(self):
- from rpython.rlib.jit import conditional_call_value
- @elidable
+ from rpython.rlib.jit import conditional_call_elidable
def g(j):
return j + 5
def f(i, j):
- return conditional_call_value(i, g, j)
+ return conditional_call_elidable(i, g, j)
res = self.interp_operations(f, [-42, 200])
assert res == -42
res = self.interp_operations(f, [0, 200])
diff --git a/rpython/jit/metainterp/test/test_call.py
b/rpython/jit/metainterp/test/test_call.py
--- a/rpython/jit/metainterp/test/test_call.py
+++ b/rpython/jit/metainterp/test/test_call.py
@@ -1,5 +1,5 @@
-from rpython.jit.metainterp.test.support import LLJitMixin
+from rpython.jit.metainterp.test.support import LLJitMixin, noConst
from rpython.rlib import jit
class CallTest(object):
@@ -54,18 +54,16 @@
self.check_resops(guard_no_exception=0)
def test_cond_call_i(self):
- @jit.elidable
def f(n):
return n * 200
def main(n, m):
- return jit.conditional_call_value(n, f, m)
+ return jit.conditional_call_elidable(n, f, m)
assert self.interp_operations(main, [0, 10]) == 2000
assert self.interp_operations(main, [15, 42]) == 15
def test_cond_call_r(self):
- @jit.elidable
def f(n):
return [n]
@@ -74,7 +72,7 @@
l = []
else:
l = None
- l = jit.conditional_call_value(l, f, n)
+ l = jit.conditional_call_elidable(l, f, n)
return len(l)
assert main(10) == 0
@@ -83,24 +81,22 @@
assert self.interp_operations(main, [5]) == 1
def test_cond_call_constant_in_pyjitpl(self):
- @jit.elidable
def f(a, b):
return a + b
def main(n):
# this is completely constant-folded because the arguments
# to f() are constants.
- return jit.conditional_call_value(n, f, 40, 2)
+ return jit.conditional_call_elidable(n, f, 40, 2)
assert main(12) == 12
assert main(0) == 42
assert self.interp_operations(main, [12]) == 12
- self.check_operations_history(finish=1) # empty history
+ self.check_operations_history({'finish': 1}) # empty history
assert self.interp_operations(main, [0]) == 42
- self.check_operations_history(finish=1) # empty history
+ self.check_operations_history({'finish': 1}) # empty history
def test_cond_call_constant_in_optimizer(self):
myjitdriver = jit.JitDriver(greens = ['m'], reds = ['n', 'p'])
- @jit.elidable
def externfn(x):
return x - 3
class V:
@@ -110,18 +106,17 @@
while n > 0:
myjitdriver.can_enter_jit(n=n, p=p, m=m)
myjitdriver.jit_merge_point(n=n, p=p, m=m)
- v = V(m)
- n -= jit.conditional_call_value(p, externfn, v.value)
+ m1 = noConst(m)
+ n -= jit.conditional_call_elidable(p, externfn, m1)
return n
res = self.meta_interp(f, [21, 5, 0])
assert res == -1
# the COND_CALL_VALUE is constant-folded away by optimizeopt.py
- self.check_resops(call_pure_i=0, cond_call_pure_i=0, call_i=0,
- int_sub=2)
+ self.check_resops({'int_sub': 2, 'int_gt': 2, 'guard_true': 2,
+ 'jump': 1})
def test_cond_call_constant_in_optimizer_2(self):
myjitdriver = jit.JitDriver(greens = ['m'], reds = ['n', 'p'])
- @jit.elidable
def externfn(x):
return 2
def f(n, m, p):
@@ -130,7 +125,7 @@
myjitdriver.jit_merge_point(n=n, p=p, m=m)
assert p > -1
assert p < 1
- n -= jit.conditional_call_value(p, externfn, n)
+ n -= jit.conditional_call_elidable(p, externfn, n)
return n
res = self.meta_interp(f, [21, 5, 0])
assert res == -1
@@ -141,7 +136,6 @@
def test_cond_call_constant_in_optimizer_3(self):
myjitdriver = jit.JitDriver(greens = ['m'], reds = ['n', 'p'])
- @jit.elidable
def externfn(x):
return 1
def f(n, m, p):
@@ -151,8 +145,8 @@
assert p > -1
assert p < 1
n0 = n
- n -= jit.conditional_call_value(p, externfn, n0)
- n -= jit.conditional_call_value(p, externfn, n0)
+ n -= jit.conditional_call_elidable(p, externfn, n0)
+ n -= jit.conditional_call_elidable(p, externfn, n0)
return n
res = self.meta_interp(f, [21, 5, 15])
assert res == -1
@@ -167,12 +161,11 @@
def __init__(self, value):
self.value = value
self.triple = 0
- @jit.elidable
def _compute_triple(self):
self.triple = self.value * 3
return self.triple
def get_triple(self):
- return jit.conditional_call_value(self.triple,
+ return jit.conditional_call_elidable(self.triple,
X._compute_triple, self)
def main(n):
x = X(n)
diff --git a/rpython/rlib/jit.py b/rpython/rlib/jit.py
--- a/rpython/rlib/jit.py
+++ b/rpython/rlib/jit.py
@@ -1218,7 +1218,7 @@
return value # special-cased below
@specialize.call_location()
-def conditional_call_value(value, function, *args):
+def conditional_call_elidable(value, function, *args):
"""Does the same as:
if value == <0 or None>:
@@ -1226,10 +1226,21 @@
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: they must be either regular 'int', or something
- that turns into a pointer.
+ typically used for caching. The value and the function's return
+ type must match and cannot be a float: they must be either regular
+ 'int', or something that turns into a pointer.
+
+ Even if the function is not marked @elidable, it is still treated
+ mostly like one. The only difference is that (in heapcache.py)
+ we don't assume this function won't change anything observable.
+ This is useful for caches, as you can write:
+
+ def _compute_and_cache(...):
+ self.cache = ...compute...
+ return self.cache
+
+ x = jit.conditional_call_elidable(self.cache, _compute_and_cache, ...)
+
"""
if we_are_jitted():
return _jit_conditional_call_value(value, function, *args)
@@ -1243,7 +1254,7 @@
value = function(*args)
assert not isinstance(value, int)
return value
-conditional_call_value._always_inline_ = True
+conditional_call_elidable._always_inline_ = True
class ConditionalCallEntry(ExtRegistryEntry):
_about_ = _jit_conditional_call, _jit_conditional_call_value
@@ -1253,10 +1264,6 @@
args_s[1], args_s[2:])
if self.instance == _jit_conditional_call_value:
from rpython.annotator import model as annmodel
- func = args_s[1].const
- assert getattr(func, '_elidable_function_', None), (
- "%r used in jit.conditional_call_value() should be "
- "@jit.elidable" % (func,))
return annmodel.unionof(s_res, args_s[0])
def specialize_call(self, hop):
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,8 +3,8 @@
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,
conditional_call_value,
- elidable, unroll_safe, dont_look_inside,
+ JitHintError, oopspec, isconstant, conditional_call,
+ elidable, unroll_safe, dont_look_inside, conditional_call_elidable,
enter_portal_frame, leave_portal_frame)
from rpython.rlib.rarithmetic import r_uint
from rpython.rtyper.test.tool import BaseRtypingTest
@@ -302,12 +302,11 @@
mix.getgraph(later, [annmodel.s_Bool], annmodel.s_None)
mix.finish()
- def test_conditional_call_value(self):
- @elidable
+ def test_conditional_call_elidable(self):
def g(x, y):
return x - y + 5
def f(n, x, y):
- return conditional_call_value(n, g, x, y)
+ return conditional_call_elidable(n, g, x, y)
assert f(0, 1000, 100) == 905
res = self.interpret(f, [0, 1000, 100])
assert res == 905
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit