[pypy-commit] pypy default: hg merge array-propagate-len
arigo
noreply at buildbot.pypy.org
Sat Feb 15 18:21:29 CET 2014
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r69165:754284731a51
Date: 2014-02-15 18:20 +0100
http://bitbucket.org/pypy/pypy/changeset/754284731a51/
Log: hg merge array-propagate-len
Kill some guards and operations in JIT traces by adding integer
bounds propagation for getfield_(raw|gc) and getarrayitem_(raw|gc).
diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -70,3 +70,7 @@
.. branch: NonConstant
Simplify implementation of NonConstant.
+
+.. branch: array-propagate-len
+Kill some guards and operations in JIT traces by adding integer bounds
+propagation for getfield_(raw|gc) and getarrayitem_(raw|gc).
diff --git a/rpython/jit/backend/llgraph/runner.py b/rpython/jit/backend/llgraph/runner.py
--- a/rpython/jit/backend/llgraph/runner.py
+++ b/rpython/jit/backend/llgraph/runner.py
@@ -1,10 +1,12 @@
import py, weakref
from rpython.jit.backend import model
from rpython.jit.backend.llgraph import support
+from rpython.jit.backend.llsupport import symbolic
from rpython.jit.metainterp.history import AbstractDescr
from rpython.jit.metainterp.history import Const, getkind
from rpython.jit.metainterp.history import INT, REF, FLOAT, VOID
from rpython.jit.metainterp.resoperation import rop
+from rpython.jit.metainterp.optimizeopt import intbounds
from rpython.jit.codewriter import longlong, heaptracker
from rpython.jit.codewriter.effectinfo import EffectInfo
@@ -119,6 +121,24 @@
def is_field_signed(self):
return _is_signed_kind(self.FIELD)
+ def is_integer_bounded(self):
+ return getkind(self.FIELD) == 'int' \
+ and rffi.sizeof(self.FIELD) < symbolic.WORD
+
+ def get_integer_min(self):
+ if getkind(self.FIELD) != 'int':
+ assert False
+
+ return intbounds.get_integer_min(
+ not _is_signed_kind(self.FIELD), rffi.sizeof(self.FIELD))
+
+ def get_integer_max(self):
+ if getkind(self.FIELD) != 'int':
+ assert False
+
+ return intbounds.get_integer_max(
+ not _is_signed_kind(self.FIELD), rffi.sizeof(self.FIELD))
+
def _is_signed_kind(TYPE):
return (TYPE is not lltype.Bool and isinstance(TYPE, lltype.Number) and
rffi.cast(TYPE, -1) == -1)
@@ -144,6 +164,25 @@
def is_array_of_structs(self):
return isinstance(self.A.OF, lltype.Struct)
+ def is_item_integer_bounded(self):
+ return getkind(self.A.OF) == 'int' \
+ and rffi.sizeof(self.A.OF) < symbolic.WORD
+
+ def get_item_integer_min(self):
+ if getkind(self.A.OF) != 'int':
+ assert False
+
+ return intbounds.get_integer_min(
+ not _is_signed_kind(self.A.OF), rffi.sizeof(self.A.OF))
+
+ def get_item_integer_max(self):
+ if getkind(self.A.OF) != 'int':
+ assert False
+
+ return intbounds.get_integer_max(
+ not _is_signed_kind(self.A.OF), rffi.sizeof(self.A.OF))
+
+
class InteriorFieldDescr(AbstractDescr):
def __init__(self, A, fieldname):
self.A = A
@@ -162,6 +201,24 @@
def is_float_field(self):
return getkind(self.FIELD) == 'float'
+ def is_integer_bounded(self):
+ return getkind(self.FIELD) == 'int' \
+ and rffi.sizeof(self.FIELD) < symbolic.WORD
+
+ def get_integer_min(self):
+ if getkind(self.FIELD) != 'int':
+ assert False
+
+ return intbounds.get_integer_min(
+ not _is_signed_kind(self.FIELD), rffi.sizeof(self.FIELD))
+
+ def get_integer_max(self):
+ if getkind(self.FIELD) != 'int':
+ assert False
+
+ return intbounds.get_integer_max(
+ not _is_signed_kind(self.FIELD), rffi.sizeof(self.FIELD))
+
_example_res = {'v': None,
'r': lltype.nullptr(llmemory.GCREF.TO),
'i': 0,
diff --git a/rpython/jit/backend/llsupport/descr.py b/rpython/jit/backend/llsupport/descr.py
--- a/rpython/jit/backend/llsupport/descr.py
+++ b/rpython/jit/backend/llsupport/descr.py
@@ -6,6 +6,7 @@
from rpython.jit.metainterp import history
from rpython.jit.codewriter import heaptracker, longlong
from rpython.jit.codewriter.longlong import is_longlong
+from rpython.jit.metainterp.optimizeopt import intbounds
class GcCache(object):
@@ -103,6 +104,26 @@
def is_field_signed(self):
return self.flag == FLAG_SIGNED
+ def is_integer_bounded(self):
+ return self.flag in (FLAG_SIGNED, FLAG_UNSIGNED) \
+ and self.field_size < symbolic.WORD
+
+ def get_integer_min(self):
+ if self.flag == FLAG_UNSIGNED:
+ return intbounds.get_integer_min(True, self.field_size)
+ elif self.flag == FLAG_SIGNED:
+ return intbounds.get_integer_min(False, self.field_size)
+
+ assert False
+
+ def get_integer_max(self):
+ if self.flag == FLAG_UNSIGNED:
+ return intbounds.get_integer_max(True, self.field_size)
+ elif self.flag == FLAG_SIGNED:
+ return intbounds.get_integer_max(False, self.field_size)
+
+ assert False
+
def sort_key(self):
return self.offset
@@ -182,6 +203,28 @@
def is_array_of_structs(self):
return self.flag == FLAG_STRUCT
+ def is_item_integer_bounded(self):
+ return self.flag in (FLAG_SIGNED, FLAG_UNSIGNED) \
+ and self.itemsize < symbolic.WORD
+
+ def get_item_integer_min(self):
+ if self.flag == FLAG_UNSIGNED:
+ return intbounds.get_integer_min(True, self.itemsize)
+ elif self.flag == FLAG_SIGNED:
+ return intbounds.get_integer_min(False, self.itemsize)
+
+ assert False
+
+ def get_item_integer_max(self):
+ if self.flag == FLAG_UNSIGNED:
+ return intbounds.get_integer_max(True, self.itemsize)
+ elif self.flag == FLAG_SIGNED:
+ return intbounds.get_integer_max(False, self.itemsize)
+
+ assert False
+
+
+
def repr_of_descr(self):
return '<Array%s %s>' % (self.flag, self.itemsize)
@@ -230,6 +273,15 @@
def is_float_field(self):
return self.fielddescr.is_float_field()
+ def is_integer_bounded(self):
+ return self.fielddescr.is_integer_bounded()
+
+ def get_integer_min(self):
+ return self.fielddescr.get_integer_min()
+
+ def get_integer_max(self):
+ return self.fielddescr.get_integer_max()
+
def repr_of_descr(self):
return '<InteriorFieldDescr %s>' % self.fielddescr.repr_of_descr()
diff --git a/rpython/jit/backend/llsupport/test/test_descr.py b/rpython/jit/backend/llsupport/test/test_descr.py
--- a/rpython/jit/backend/llsupport/test/test_descr.py
+++ b/rpython/jit/backend/llsupport/test/test_descr.py
@@ -432,3 +432,24 @@
assert descr.basesize == struct.calcsize("PP") # hash, length
assert descr.lendescr.offset == struct.calcsize("P") # hash
assert not descr.is_array_of_pointers()
+
+
+def test_descr_integer_bounded():
+ descr = FieldDescr('descr', 0, symbolic.SIZEOF_CHAR, FLAG_SIGNED)
+ assert descr.is_integer_bounded()
+
+ descr = FieldDescr('descr', 0, symbolic.WORD, FLAG_UNSIGNED)
+ assert not descr.is_integer_bounded()
+
+ descr = FieldDescr('descr', 0, symbolic.SIZEOF_FLOAT, FLAG_FLOAT)
+ assert not descr.is_integer_bounded()
+
+
+def test_descr_get_integer_bounds():
+ descr = FieldDescr('decr', 0, 1, FLAG_UNSIGNED)
+ assert descr.get_integer_min() == 0
+ assert descr.get_integer_max() == 255
+
+ descr = FieldDescr('descr', 0, 1, FLAG_SIGNED)
+ assert descr.get_integer_min() == -128
+ assert descr.get_integer_max() == 127
diff --git a/rpython/jit/metainterp/optimizeopt/__init__.py b/rpython/jit/metainterp/optimizeopt/__init__.py
--- a/rpython/jit/metainterp/optimizeopt/__init__.py
+++ b/rpython/jit/metainterp/optimizeopt/__init__.py
@@ -63,7 +63,7 @@
optimizer.propagate_all_forward()
finally:
debug_stop("jit-optimize")
-
+
if __name__ == '__main__':
print ALL_OPTS_NAMES
diff --git a/rpython/jit/metainterp/optimizeopt/intbounds.py b/rpython/jit/metainterp/optimizeopt/intbounds.py
--- a/rpython/jit/metainterp/optimizeopt/intbounds.py
+++ b/rpython/jit/metainterp/optimizeopt/intbounds.py
@@ -9,6 +9,20 @@
from rpython.jit.metainterp.resoperation import rop
+def get_integer_min(is_unsigned, byte_size):
+ if is_unsigned:
+ return 0
+ else:
+ return -(1 << ((byte_size << 3) - 1))
+
+
+def get_integer_max(is_unsigned, byte_size):
+ if is_unsigned:
+ return (1 << (byte_size << 3)) - 1
+ else:
+ return (1 << ((byte_size << 3) - 1)) - 1
+
+
class OptIntBounds(Optimization):
"""Keeps track of the bounds placed on integers by guards and remove
redundant guards"""
@@ -322,6 +336,29 @@
v1.intbound.make_ge(IntLowerBound(0))
v1.intbound.make_lt(IntUpperBound(256))
+ def optimize_GETFIELD_RAW(self, op):
+ self.emit_operation(op)
+ descr = op.getdescr()
+ if descr.is_integer_bounded():
+ v1 = self.getvalue(op.result)
+ v1.intbound.make_ge(IntLowerBound(descr.get_integer_min()))
+ v1.intbound.make_lt(IntUpperBound(descr.get_integer_max() + 1))
+
+ optimize_GETFIELD_GC = optimize_GETFIELD_RAW
+
+ optimize_GETINTERIORFIELD_GC = optimize_GETFIELD_RAW
+
+ def optimize_GETARRAYITEM_RAW(self, op):
+ self.emit_operation(op)
+ descr = op.getdescr()
+ if descr and descr.is_item_integer_bounded():
+ v1 = self.getvalue(op.result)
+ v1.intbound.make_ge(IntLowerBound(descr.get_item_integer_min()))
+ v1.intbound.make_lt(
+ IntUpperBound(descr.get_item_integer_max() + 1))
+
+ optimize_GETARRAYITEM_GC = optimize_GETARRAYITEM_RAW
+
def optimize_UNICODEGETITEM(self, op):
self.emit_operation(op)
v1 = self.getvalue(op.result)
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py
@@ -5200,6 +5200,104 @@
"""
self.optimize_loop(ops, ops)
+ def test_getfield_cmp_above_bounds(self):
+ ops = """
+ [p0]
+ i0 = getfield_gc(p0, descr=chardescr)
+ i1 = int_lt(i0, 256)
+ guard_true(i1) []
+ """
+
+ expected = """
+ [p0]
+ i0 = getfield_gc(p0, descr=chardescr)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_getfield_cmp_below_bounds(self):
+ ops = """
+ [p0]
+ i0 = getfield_gc(p0, descr=chardescr)
+ i1 = int_gt(i0, -1)
+ guard_true(i1) []
+ """
+
+ expected = """
+ [p0]
+ i0 = getfield_gc(p0, descr=chardescr)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_getfield_cmp_in_bounds(self):
+ ops = """
+ [p0]
+ i0 = getfield_gc(p0, descr=chardescr)
+ i1 = int_gt(i0, 0)
+ guard_true(i1) []
+ i2 = int_lt(i0, 255)
+ guard_true(i2) []
+ """
+ self.optimize_loop(ops, ops)
+
+ def test_getfieldraw_cmp_outside_bounds(self):
+ ops = """
+ [p0]
+ i0 = getfield_raw(p0, descr=chardescr)
+ i1 = int_gt(i0, -1)
+ guard_true(i1) []
+ """
+
+ expected = """
+ [p0]
+ i0 = getfield_raw(p0, descr=chardescr)
+ """
+ self.optimize_loop(ops, expected)
+
+
+ def test_rawarray_cmp_outside_intbounds(self):
+ ops = """
+ [i0]
+ i1 = getarrayitem_raw(i0, 0, descr=rawarraydescr_char)
+ i2 = int_lt(i1, 256)
+ guard_true(i2) []
+ """
+
+ expected = """
+ [i0]
+ i1 = getarrayitem_raw(i0, 0, descr=rawarraydescr_char)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_gcarray_outside_intbounds(self):
+ ops = """
+ [p0]
+ i0 = getarrayitem_gc(p0, 0, descr=chararraydescr)
+ i1 = int_lt(i0, 256)
+ guard_true(i1) []
+ """
+
+ expected = """
+ [p0]
+ i0 = getarrayitem_gc(p0, 0, descr=chararraydescr)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_getinterior_outside_intbounds(self):
+ ops = """
+ [p0]
+ f0 = getinteriorfield_gc(p0, 0, descr=fc_array_floatdescr)
+ i0 = getinteriorfield_gc(p0, 0, descr=fc_array_chardescr)
+ i1 = int_lt(i0, 256)
+ guard_true(i1) []
+ """
+
+ expected = """
+ [p0]
+ f0 = getinteriorfield_gc(p0, 0, descr=fc_array_floatdescr)
+ i0 = getinteriorfield_gc(p0, 0, descr=fc_array_chardescr)
+ """
+ self.optimize_loop(ops, expected)
+
class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin):
pass
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py
@@ -5563,6 +5563,8 @@
self.name = name
def sort_key(self):
return id(self)
+ def is_integer_bounded(self):
+ return False
for n in ('inst_w_seq', 'inst_index', 'inst_w_list', 'inst_length',
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_util.py b/rpython/jit/metainterp/optimizeopt/test/test_util.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_util.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_util.py
@@ -92,6 +92,7 @@
NODE.become(lltype.GcStruct('NODE', ('parent', OBJECT),
('value', lltype.Signed),
('floatval', lltype.Float),
+ ('charval', lltype.Char),
('next', lltype.Ptr(NODE))))
NODE2 = lltype.GcStruct('NODE2', ('parent', NODE),
('other', lltype.Ptr(NODE)))
@@ -108,6 +109,7 @@
nodesize2 = cpu.sizeof(NODE2)
valuedescr = cpu.fielddescrof(NODE, 'value')
floatdescr = cpu.fielddescrof(NODE, 'floatval')
+ chardescr = cpu.fielddescrof(NODE, 'charval')
nextdescr = cpu.fielddescrof(NODE, 'next')
otherdescr = cpu.fielddescrof(NODE2, 'other')
@@ -204,6 +206,8 @@
EffectInfo.EF_CANNOT_RAISE,
oopspecindex=EffectInfo.OS_RAW_FREE))
+ chararray = lltype.GcArray(lltype.Char)
+ chararraydescr = cpu.arraydescrof(chararray)
# array of structs (complex data)
complexarray = lltype.GcArray(
@@ -221,6 +225,12 @@
rawarraydescr_char = cpu.arraydescrof(lltype.Array(lltype.Char,
hints={'nolength': True}))
+ fc_array = lltype.GcArray(
+ lltype.Struct(
+ "floatchar", ("float", lltype.Float), ("char", lltype.Char)))
+ fc_array_descr = cpu.arraydescrof(fc_array)
+ fc_array_floatdescr = cpu.interiorfielddescrof(fc_array, "float")
+ fc_array_chardescr = cpu.interiorfielddescrof(fc_array, "char")
for _name, _os in [
('strconcatdescr', 'OS_STR_CONCAT'),
diff --git a/rpython/jit/metainterp/optimizeopt/util.py b/rpython/jit/metainterp/optimizeopt/util.py
--- a/rpython/jit/metainterp/optimizeopt/util.py
+++ b/rpython/jit/metainterp/optimizeopt/util.py
@@ -1,3 +1,5 @@
+import itertools
+
import py
from rpython.rlib.objectmodel import r_dict, compute_identity_hash
from rpython.rlib.rarithmetic import intmask
@@ -136,13 +138,16 @@
print ' Comparing lists '.center(totwidth, '-')
text_right = text_right or 'expected'
print '%s| %s' % ('optimized'.center(width), text_right.center(width))
- for op1, op2 in zip(oplist1, oplist2):
+ for op1, op2 in itertools.izip_longest(oplist1, oplist2, fillvalue=''):
txt1 = str(op1)
txt2 = str(op2)
while txt1 or txt2:
print '%s| %s' % (txt1[:width].ljust(width), txt2[:width])
txt1 = txt1[width:]
txt2 = txt2[width:]
+ print '-' * totwidth
+
+ for op1, op2 in zip(oplist1, oplist2):
assert op1.getopnum() == op2.getopnum()
assert op1.numargs() == op2.numargs()
for i in range(op1.numargs()):
@@ -177,6 +182,5 @@
else:
assert False
assert len(oplist1) == len(oplist2)
- print '-'*totwidth
return True
More information about the pypy-commit
mailing list