Author: Armin Rigo <[email protected]>
Branch: conditional_call_value_4
Changeset: r88580:be014558712e
Date: 2016-11-23 15:54 +0100
http://bitbucket.org/pypy/pypy/changeset/be014558712e/
Log: More tests, more fixes
diff --git a/rpython/jit/metainterp/optimizeopt/pure.py
b/rpython/jit/metainterp/optimizeopt/pure.py
--- a/rpython/jit/metainterp/optimizeopt/pure.py
+++ b/rpython/jit/metainterp/optimizeopt/pure.py
@@ -197,13 +197,17 @@
optimize_COND_CALL_VALUE_R = optimize_COND_CALL_VALUE_I
def optimize_call_pure_old(self, op, old_op, start_index):
- if (op.numargs() != old_op.numargs() or
- op.getdescr() is not old_op.getdescr()):
+ if op.getdescr() is not old_op.getdescr():
return False
- for i in range(start_index, old_op.numargs()):
+ # this will match a call_pure and a cond_call_value with
+ # the same function and arguments
+ j = start_index
+ old_start_index = OpHelpers.is_cond_call_value(old_op.opnum)
+ for i in range(old_start_index, old_op.numargs()):
box = old_op.getarg(i)
- if not self.get_box_replacement(op.getarg(i)).same_box(box):
+ if not self.get_box_replacement(op.getarg(j)).same_box(box):
break
+ j += 1
else:
# all identical
# this removes a CALL_PURE that has the same (non-constant)
@@ -260,10 +264,17 @@
# don't move call_pure_with_exception in the short preamble...
# issue #2015
+ # Also, don't move cond_call_value in the short preamble.
+ # The issue there is that it's usually pointless to try to
+ # because the 'value' argument is typically not a loop
+ # invariant, and would really need to be in order to end up
+ # in the short preamble. Maybe the code works anyway in the
+ # other rare case, but better safe than sorry and don't try.
effectinfo = op.getdescr().get_extra_info()
if not effectinfo.check_can_raise(ignore_memoryerror=True):
assert rop.is_call(op.opnum)
- sb.add_pure_op(op)
+ if not OpHelpers.is_cond_call_value(op.opnum):
+ sb.add_pure_op(op)
dispatch_opt = make_dispatcher_method(OptPure, 'optimize_',
default=OptPure.optimize_default)
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
@@ -115,6 +115,29 @@
self.check_resops({'int_sub': 2, 'int_gt': 2, 'guard_true': 2,
'jump': 1})
+ def test_cond_call_constant_in_optimizer_1(self):
+ # same as test_cond_call_constant_in_optimizer, but the 'value'
+ # argument changes
+ myjitdriver = jit.JitDriver(greens = ['m'], reds = ['n', 'p'])
+ def externfn(x):
+ return x - 3
+ class V:
+ def __init__(self, value):
+ self.value = value
+ def f(n, m, p):
+ while n > 0:
+ myjitdriver.can_enter_jit(n=n, p=p, m=m)
+ myjitdriver.jit_merge_point(n=n, p=p, m=m)
+ m1 = noConst(m)
+ n -= jit.conditional_call_elidable(p, externfn, m1)
+ return n
+ assert f(21, 5, 0) == -1
+ 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({'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'])
def externfn(x):
@@ -148,12 +171,12 @@
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])
+ res = self.meta_interp(f, [21, 5, 0])
assert res == -1
# same as test_cond_call_constant_in_optimizer_2, but the two
# intermediate CALL_PUREs are replaced with only one, because
# they are called with the same arguments
- self.check_resops(call_pure_i=0, cond_call_pure_i=0, call_i=2,
+ self.check_resops(call_pure_i=0, cond_call_value_i=0, call_i=2,
int_sub=4)
def test_cond_call_constant_in_optimizer_4(self):
@@ -167,13 +190,71 @@
def get_triple(self):
return jit.conditional_call_elidable(self.triple,
X._compute_triple, self)
+
+ myjitdriver = jit.JitDriver(greens = [], reds = 'auto')
def main(n):
- x = X(n)
- return x.get_triple() + x.get_triple()
+ total = 0
+ while n > 1:
+ myjitdriver.jit_merge_point()
+ x = X(n)
+ total += x.get_triple() + x.get_triple() + x.get_triple()
+ n -= 10
+ return total
- assert self.interp_operations(main, [100]) == 600
- XXX
- self.check_operations_history(finish=1) # empty history
+ res = self.meta_interp(main, [100])
+ assert res == main(100)
+ # remaining: only the first call to get_triple(), as a call_i
+ # because we know that x.triple == 0 here. The remaining calls
+ # are removed because equal to the first one.
+ self.check_resops(call_i=2, cond_call_value_i=0)
+
+ def test_cond_call_multiple_in_optimizer_1(self):
+ # test called several times with the same arguments, but
+ # the condition is not available to the short preamble.
+ # This means that the second cond_call_value after unrolling
+ # can't be removed.
+ myjitdriver = jit.JitDriver(greens = [], reds = ['n', 'p', 'm'])
+ def externfn(x):
+ return 2000 # never actually called
+ @jit.dont_look_inside
+ def randomish(p):
+ return p + 1
+ def f(n, m, p):
+ while n > 0:
+ myjitdriver.can_enter_jit(n=n, p=p, m=m)
+ myjitdriver.jit_merge_point(n=n, p=p, m=m)
+ n -= jit.conditional_call_elidable(randomish(p), externfn, m)
+ return n
+ assert f(21, 5, 1) == -1
+ res = self.meta_interp(f, [21, 5, 1])
+ assert res == -1
+ self.check_resops(call_pure_i=0, cond_call_value_i=2,
+ call_i=2, # randomish()
+ int_sub=2)
+
+ def test_cond_call_multiple_in_optimizer_2(self):
+ # test called several times with the same arguments. Ideally
+ # we would like them to be consolidated into one call even if
+ # the 'value' are different but available from the short
+ # preamble. We don't do it so far---it's a mess, because the
+ # short preamble is supposed to depend only on loop-invariant
+ # things, and 'value' is (most of the time) not loop-invariant.
+ myjitdriver = jit.JitDriver(greens = [], reds = ['n', 'p', 'm'])
+ def externfn(x):
+ return 2 # called only the first time
+ def f(n, m, p):
+ while n > 0:
+ myjitdriver.can_enter_jit(n=n, p=p, m=m)
+ myjitdriver.jit_merge_point(n=n, p=p, m=m)
+ p = jit.conditional_call_elidable(p, externfn, m)
+ n -= p
+ return n
+ assert f(219, 5, 0) == -1
+ res = self.meta_interp(f, [219, 5, 0])
+ assert res == -1
+ self.check_resops(call_pure_i=0,
+ cond_call_value_i=2, # ideally 1, but see above
+ int_sub=2)
class TestCall(LLJitMixin, CallTest):
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit