Author: Carl Friedrich Bolz <cfb...@gmx.de> Branch: guard-compatible Changeset: r83002:03482b008a97 Date: 2016-03-12 23:00 +0100 http://bitbucket.org/pypy/pypy/changeset/03482b008a97/
Log: some optimization support for guard_compatible, including storing which elidable functions were applied to its argument diff --git a/rpython/jit/metainterp/compatible.py b/rpython/jit/metainterp/compatible.py new file mode 100644 --- /dev/null +++ b/rpython/jit/metainterp/compatible.py @@ -0,0 +1,10 @@ +from rpython.jit.metainterp.history import newconst + +class CompatibilityCondition(object): + """ A collections of conditions that an object needs to fulfil. """ + def __init__(self, ptr): + self.known_valid = ptr + self.pure_call_conditions = [] + + def record_pure_call(self, op, res): + self.pure_call_conditions.append((op, res)) diff --git a/rpython/jit/metainterp/optimizeopt/info.py b/rpython/jit/metainterp/optimizeopt/info.py --- a/rpython/jit/metainterp/optimizeopt/info.py +++ b/rpython/jit/metainterp/optimizeopt/info.py @@ -35,7 +35,8 @@ class PtrInfo(AbstractInfo): - _attrs_ = () + _attrs_ = ('_compatibility_conditions', ) + _compatibility_conditions = None def is_nonnull(self): return False @@ -785,7 +786,7 @@ targetbox, CONST_0, offsetbox, lgt, mode) - + class FloatConstInfo(AbstractInfo): def __init__(self, const): self._const = const diff --git a/rpython/jit/metainterp/optimizeopt/optimizer.py b/rpython/jit/metainterp/optimizeopt/optimizer.py --- a/rpython/jit/metainterp/optimizeopt/optimizer.py +++ b/rpython/jit/metainterp/optimizeopt/optimizer.py @@ -713,6 +713,12 @@ # if op.getopnum() == rop.GUARD_VALUE: op = self._maybe_replace_guard_value(op, descr) + elif op.getopnum() == rop.GUARD_COMPATIBLE: + # XXX randomly stuff things into the descr + info = self.getptrinfo(op.getarg(0)) + assert isinstance(descr, compile.GuardCompatibleDescr) + if info is not None and info._compatibility_conditions: + descr._compatibility_conditions = info._compatibility_conditions return op def _maybe_replace_guard_value(self, op, descr): 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 @@ -4,6 +4,7 @@ from rpython.jit.metainterp.optimizeopt.util import make_dispatcher_method from rpython.jit.metainterp.optimizeopt.shortpreamble import PreambleOp from rpython.jit.metainterp.optimize import SpeculativeError +from rpython.jit.metainterp.compatible import CompatibilityCondition class RecentPureOps(object): @@ -130,6 +131,25 @@ return recentops def optimize_CALL_PURE_I(self, op): + # Step 0: check if first argument is subject of guard_compatible + # XXX maybe don't do this with absolutely *all* call_pure functions + # that have a guard_compatible ptr as first arg + if op.numargs() > 1: + arg1 = self.get_box_replacement(op.getarg(1)) + if arg1.type == 'r': + info = self.getptrinfo(arg1) + ccond = info._compatibility_conditions + if info and ccond: + # it's subject to guard_compatible + copied_op = op.copy() + copied_op.setarg(1, ccond.known_valid) + result = self._can_optimize_call_pure(copied_op) + if result is not None: + self.make_constant(op, result) + self.last_emitted_operation = REMOVED + ccond.record_pure_call(copied_op, result) + return + # Step 1: check if all arguments are constant for arg in op.getarglist(): self.optimizer.force_box(arg) @@ -186,6 +206,29 @@ return True return False + def optimize_GUARD_COMPATIBLE(self, op): + arg0 = self.get_box_replacement(op.getarg(0)) + if arg0.is_constant(): + # already subject of guard_value + return + assert arg0.type == 'r' + info = self.getptrinfo(arg0) + if info: + if info.is_virtual(): + raise InvalidLoop("guard_compatible of a virtual") + else: + self.make_nonnull(arg0) + info = self.getptrinfo(arg0) + if info._compatibility_conditions: + # seen a previous guard_compatible + # check that it's the same previous constant + assert info._compatibility_conditions.known_valid.same_constant(op.getarg(1)) + return + else: + info._compatibility_conditions = CompatibilityCondition( + op.getarg(1)) + self.emit_operation(op) + def optimize_GUARD_NO_EXCEPTION(self, op): if self.last_emitted_operation is REMOVED: # it was a CALL_PURE that was killed; so we also kill the diff --git a/rpython/jit/metainterp/optimizeopt/test/test_compatible.py b/rpython/jit/metainterp/optimizeopt/test/test_compatible.py new file mode 100644 --- /dev/null +++ b/rpython/jit/metainterp/optimizeopt/test/test_compatible.py @@ -0,0 +1,56 @@ +from rpython.jit.metainterp.optimizeopt.test.test_util import ( + LLtypeMixin) +from rpython.jit.metainterp.optimizeopt.test.test_optimizebasic import ( + BaseTestBasic) +from rpython.jit.metainterp.history import ConstInt, ConstPtr + +class TestCompatible(BaseTestBasic, LLtypeMixin): + + enable_opts = "intbounds:rewrite:virtualize:string:earlyforce:pure:heap" + + def test_guard_compatible_after_guard_value(self): + ops = """ + [p1] + guard_value(p1, ConstPtr(myptr)) [] + guard_compatible(p1, ConstPtr(myptr)) [] + jump(ConstPtr(myptr)) + """ + expected = """ + [p1] + guard_value(p1, ConstPtr(myptr)) [] + jump(ConstPtr(myptr)) + """ + self.optimize_loop(ops, expected) + + def test_guard_compatible_after_guard_compatible(self): + ops = """ + [p1] + guard_compatible(p1, ConstPtr(myptr)) [] + guard_compatible(p1, ConstPtr(myptr)) [] + jump(ConstPtr(myptr)) + """ + expected = """ + [p1] + guard_compatible(p1, ConstPtr(myptr)) [] + jump(ConstPtr(myptr)) + """ + self.optimize_loop(ops, expected) + + def test_guard_compatible_call_pure(self): + call_pure_results = { + (ConstInt(123), ConstPtr(self.myptr)): ConstInt(5), + } + ops = """ + [p1] + guard_compatible(p1, ConstPtr(myptr)) [] + i3 = call_pure_i(123, p1, descr=plaincalldescr) + escape_n(i3) + jump(ConstPtr(myptr)) + """ + expected = """ + [p1] + guard_compatible(p1, ConstPtr(myptr)) [] + escape_n(5) + jump(ConstPtr(myptr)) + """ + self.optimize_loop(ops, expected, call_pure_results=call_pure_results) _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit