[pypy-commit] pypy guard-compatible: some optimization support for guard_compatible, including storing which
cfbolz
pypy.commits at gmail.com
Sat Mar 12 17:25:23 EST 2016
Author: Carl Friedrich Bolz <cfbolz at 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)
More information about the pypy-commit
mailing list