[pypy-commit] pypy jit-opaque-licm: Allow getitems of opaque pointers to be moved out of loops when the class of the pointer is known. Also, check that such a pointer has the correct class before inlining such getitems into bridges jumping to the loop
hakanardo
noreply at buildbot.pypy.org
Fri Jul 20 16:52:09 CEST 2012
Author: Hakan Ardo <hakan at debian.org>
Branch: jit-opaque-licm
Changeset: r56289:77dce024e344
Date: 2012-07-20 16:02 +0200
http://bitbucket.org/pypy/pypy/changeset/77dce024e344/
Log: Allow getitems of opaque pointers to be moved out of loops when the
class of the pointer is known. Also, check that such a pointer has
the correct class before inlining such getitems into bridges jumping
to the loop
diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py
--- a/pypy/jit/metainterp/optimizeopt/heap.py
+++ b/pypy/jit/metainterp/optimizeopt/heap.py
@@ -1,7 +1,7 @@
import os
from pypy.jit.metainterp.jitexc import JitException
-from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, MODE_ARRAY
+from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, MODE_ARRAY, LEVEL_KNOWNCLASS
from pypy.jit.metainterp.history import ConstInt, Const
from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method
from pypy.jit.metainterp.resoperation import rop, ResOperation
@@ -128,8 +128,12 @@
op = self._cached_fields_getfield_op[structvalue]
if not op:
continue
- if optimizer.getvalue(op.getarg(0)) in optimizer.opaque_pointers:
- continue
+ value = optimizer.getvalue(op.getarg(0))
+ if value in optimizer.opaque_pointers:
+ if value.level < LEVEL_KNOWNCLASS:
+ continue
+ if op.getopnum() != rop.SETFIELD_GC and op.getopnum() != rop.GETFIELD_GC:
+ continue
if structvalue in self._cached_fields:
if op.getopnum() == rop.SETFIELD_GC:
result = op.getarg(1)
diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
--- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
+++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
@@ -7872,6 +7872,24 @@
self.raises(InvalidLoop, self.optimize_loop,
ops, ops)
+ def test_licm_array_attrib_len(self):
+ ops = """
+ [p8]
+ p44 = getfield_gc(p8, descr=nextdescr) # inst__value0
+ mark_opaque_ptr(p44)
+ guard_nonnull(p44) []
+ guard_class(p44, ConstClass(node_vtable)) []
+ i55 = getfield_gc(p44, descr=otherdescr) # inst_buffer
+ jump(p8)
+ """
+ expected = """
+ [p8]
+ jump(p8)
+ """
+ self.optimize_loop(ops, expected)
+
+
+
class TestLLtype(OptimizeOptTest, LLtypeMixin):
pass
diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py
--- a/pypy/jit/metainterp/optimizeopt/unroll.py
+++ b/pypy/jit/metainterp/optimizeopt/unroll.py
@@ -341,6 +341,9 @@
op = self.short[i]
newop = self.short_inliner.inline_op(op)
self.optimizer.send_extra_operation(newop)
+ if op.result in self.short_boxes.assumed_classes:
+ classbox = self.getvalue(newop.result).get_constant_class(self.optimizer.cpu)
+ assert classbox.same_constant(self.short_boxes.assumed_classes[op.result])
i += 1
# Import boxes produced in the preamble but used in the loop
@@ -432,9 +435,13 @@
newargs[i] = a.clonebox()
boxmap[a] = newargs[i]
inliner = Inliner(short_inputargs, newargs)
+ target_token.assumed_classes = {}
for i in range(len(short)):
- short[i] = inliner.inline_op(short[i])
-
+ op = short[i]
+ newop = inliner.inline_op(op)
+ if op.result and op.result in self.short_boxes.assumed_classes:
+ target_token.assumed_classes[newop.result] = self.short_boxes.assumed_classes[op.result]
+ short[i] = newop
target_token.resume_at_jump_descr = target_token.resume_at_jump_descr.clone_if_mutable()
inliner.inline_descr_inplace(target_token.resume_at_jump_descr)
@@ -588,6 +595,12 @@
for shop in target.short_preamble[1:]:
newop = inliner.inline_op(shop)
self.optimizer.send_extra_operation(newop)
+ if shop.result in target.assumed_classes:
+ classbox = self.getvalue(newop.result).get_constant_class(self.optimizer.cpu)
+ if not classbox or not classbox.same_constant(target.assumed_classes[shop]):
+ raise InvalidLoop('The class of an opaque pointer at the end ' +
+ 'of the bridge does not mach the class ' +
+ 'it has at the start of the target loop')
except InvalidLoop:
#debug_print("Inlining failed unexpectedly",
# "jumping to preamble instead")
diff --git a/pypy/jit/metainterp/optimizeopt/virtualstate.py b/pypy/jit/metainterp/optimizeopt/virtualstate.py
--- a/pypy/jit/metainterp/optimizeopt/virtualstate.py
+++ b/pypy/jit/metainterp/optimizeopt/virtualstate.py
@@ -585,6 +585,7 @@
self.rename = {}
self.optimizer = optimizer
self.availible_boxes = availible_boxes
+ self.assumed_classes = {}
if surviving_boxes is not None:
for box in surviving_boxes:
@@ -678,6 +679,13 @@
raise BoxNotProducable
def add_potential(self, op, synthetic=False):
+ if op.result:
+ value = self.optimizer.getvalue(op.result)
+ if value in self.optimizer.opaque_pointers:
+ classbox = value.get_constant_class(self.optimizer.cpu)
+ if classbox is None:
+ return
+ self.assumed_classes[op.result] = classbox
if op.result not in self.potential_ops:
self.potential_ops[op.result] = op
else:
diff --git a/pypy/jit/metainterp/test/test_loop.py b/pypy/jit/metainterp/test/test_loop.py
--- a/pypy/jit/metainterp/test/test_loop.py
+++ b/pypy/jit/metainterp/test/test_loop.py
@@ -871,6 +871,42 @@
res = self.meta_interp(f, [20, 10, 1])
assert res == f(20, 10, 1)
+ def test_boxed_unerased_pointers_in_short_preamble(self):
+ from pypy.rlib.rerased import new_erasing_pair
+ from pypy.rpython.lltypesystem import lltype
+ class A(object):
+ def __init__(self, val):
+ self.val = val
+ def tst(self):
+ return self.val
+
+ class Box(object):
+ def __init__(self, val):
+ self.val = val
+
+ erase_A, unerase_A = new_erasing_pair('A')
+ erase_TP, unerase_TP = new_erasing_pair('TP')
+ TP = lltype.GcArray(lltype.Signed)
+ myjitdriver = JitDriver(greens = [], reds = ['n', 'm', 'i', 'sa', 'p'])
+ def f(n, m):
+ i = sa = 0
+ p = Box(erase_A(A(7)))
+ while i < n:
+ myjitdriver.jit_merge_point(n=n, m=m, i=i, sa=sa, p=p)
+ if i < m:
+ sa += unerase_A(p.val).tst()
+ elif i == m:
+ a = lltype.malloc(TP, 5)
+ a[0] = 42
+ p = Box(erase_TP(a))
+ else:
+ sa += unerase_TP(p.val)[0]
+ sa -= A(i).val
+ i += 1
+ return sa
+ res = self.meta_interp(f, [20, 10])
+ assert res == f(20, 10)
+
class TestOOtype(LoopTest, OOJitMixin):
pass
More information about the pypy-commit
mailing list