Author: Armin Rigo <[email protected]>
Branch:
Changeset: r73886:6f51f0dc9cb0
Date: 2014-10-10 18:09 +0200
http://bitbucket.org/pypy/pypy/changeset/6f51f0dc9cb0/
Log: Fix for RPython code like '[0] * n', which was incorrectly jitted
with 'new_array', i.e. the version that doesn't fill the result with
zeroes.
diff --git a/rpython/jit/codewriter/jtransform.py
b/rpython/jit/codewriter/jtransform.py
--- a/rpython/jit/codewriter/jtransform.py
+++ b/rpython/jit/codewriter/jtransform.py
@@ -1653,41 +1653,34 @@
self._get_list_nonneg_canraise_flags(op)
def _get_initial_newlist_length(self, op, args):
- # normalize number of arguments to the 'newlist' function
- if len(args) > 1:
- v_default = args[1] # initial value: must be 0 or NULL
- ARRAY = deref(op.result.concretetype)
- if (not isinstance(v_default, Constant) or
- v_default.value != arrayItem(ARRAY)._defl()):
- raise NotSupported("variable or non-null initial value")
- if len(args) >= 1:
- return args[0]
+ assert len(args) <= 1
+ if len(args) == 1:
+ v_length = args[0]
+ assert v_length.concretetype is lltype.Signed
+ return v_length
else:
return Constant(0, lltype.Signed) # length: default to 0
# ---------- fixed lists ----------
def do_fixed_newlist(self, op, args, arraydescr):
+ # corresponds to rtyper.lltypesystem.rlist.newlist:
+ # the items may be uninitialized.
v_length = self._get_initial_newlist_length(op, args)
- assert v_length.concretetype is lltype.Signed
- ops = []
- if isinstance(v_length, Constant):
- if v_length.value >= 0:
- v = v_length
- else:
- v = Constant(0, lltype.Signed)
- else:
- v = Variable('new_length')
- v.concretetype = lltype.Signed
- ops.append(SpaceOperation('int_force_ge_zero', [v_length], v))
ARRAY = op.result.concretetype.TO
if ((isinstance(ARRAY.OF, lltype.Ptr) and ARRAY.OF._needsgc()) or
isinstance(ARRAY.OF, lltype.Struct)):
opname = 'new_array_clear'
else:
opname = 'new_array'
- ops.append(SpaceOperation(opname, [v, arraydescr], op.result))
- return ops
+ return SpaceOperation(opname, [v_length, arraydescr], op.result)
+
+ def do_fixed_newlist_clear(self, op, args, arraydescr):
+ # corresponds to rtyper.rlist.ll_alloc_and_clear:
+ # needs to clear the items.
+ v_length = self._get_initial_newlist_length(op, args)
+ return SpaceOperation('new_array_clear', [v_length, arraydescr],
+ op.result)
def do_fixed_list_len(self, op, args, arraydescr):
if args[0] in self.vable_array_vars: # virtualizable array
@@ -1757,6 +1750,14 @@
arraydescr],
op.result)
+ def do_resizable_newlist_clear(self, op, args, arraydescr, lengthdescr,
+ itemsdescr, structdescr):
+ v_length = self._get_initial_newlist_length(op, args)
+ return SpaceOperation('newlist_clear',
+ [v_length, structdescr, lengthdescr, itemsdescr,
+ arraydescr],
+ op.result)
+
def do_resizable_newlist_hint(self, op, args, arraydescr, lengthdescr,
itemsdescr, structdescr):
v_hint = self._get_initial_newlist_length(op, args)
diff --git a/rpython/jit/codewriter/support.py
b/rpython/jit/codewriter/support.py
--- a/rpython/jit/codewriter/support.py
+++ b/rpython/jit/codewriter/support.py
@@ -180,11 +180,11 @@
return LIST.ll_newlist(0)
def _ll_1_newlist(LIST, count):
return LIST.ll_newlist(count)
-def _ll_2_newlist(LIST, count, item):
- return rlist.ll_alloc_and_set(LIST, count, item)
_ll_0_newlist.need_result_type = True
_ll_1_newlist.need_result_type = True
-_ll_2_newlist.need_result_type = True
+
+_ll_1_newlist_clear = rlist._ll_alloc_and_clear
+_ll_1_newlist_clear.need_result_type = True
def _ll_1_newlist_hint(LIST, hint):
return LIST.ll_newlist_hint(hint)
diff --git a/rpython/jit/codewriter/test/test_codewriter.py
b/rpython/jit/codewriter/test/test_codewriter.py
--- a/rpython/jit/codewriter/test/test_codewriter.py
+++ b/rpython/jit/codewriter/test/test_codewriter.py
@@ -232,18 +232,3 @@
assert 'setarrayitem_raw_i' in s
assert 'getarrayitem_raw_i' in s
assert 'residual_call_ir_v $<* fn _ll_1_raw_free__arrayPtr>' in s
-
-def test_newlist_negativ():
- def f(n):
- l = [0] * n
- return len(l)
-
- rtyper = support.annotate(f, [-1])
- jitdriver_sd = FakeJitDriverSD(rtyper.annotator.translator.graphs[0])
- cw = CodeWriter(FakeCPU(rtyper), [jitdriver_sd])
- graphs = cw.find_all_graphs(FakePolicy())
- backend_optimizations(rtyper.annotator.translator, graphs=graphs)
- cw.make_jitcodes(verbose=True)
- s = jitdriver_sd.mainjitcode.dump()
- assert 'int_force_ge_zero' in s
- assert 'new_array' in s
diff --git a/rpython/jit/codewriter/test/test_list.py
b/rpython/jit/codewriter/test/test_list.py
--- a/rpython/jit/codewriter/test/test_list.py
+++ b/rpython/jit/codewriter/test/test_list.py
@@ -87,20 +87,10 @@
"""new_array $0, <ArrayDescr> -> %r0""")
builtin_test('newlist', [Constant(5, lltype.Signed)], FIXEDLIST,
"""new_array $5, <ArrayDescr> -> %r0""")
- builtin_test('newlist', [Constant(-2, lltype.Signed)], FIXEDLIST,
- """new_array $0, <ArrayDescr> -> %r0""")
builtin_test('newlist', [varoftype(lltype.Signed)], FIXEDLIST,
- """int_force_ge_zero %i0 -> %i1\n"""
- """new_array %i1, <ArrayDescr> -> %r0""")
- builtin_test('newlist', [Constant(5, lltype.Signed),
- Constant(0, lltype.Signed)], FIXEDLIST,
- """new_array $5, <ArrayDescr> -> %r0""")
- builtin_test('newlist', [Constant(5, lltype.Signed),
- Constant(1, lltype.Signed)], FIXEDLIST,
- NotSupported)
- builtin_test('newlist', [Constant(5, lltype.Signed),
- varoftype(lltype.Signed)], FIXEDLIST,
- NotSupported)
+ """new_array %i0, <ArrayDescr> -> %r0""")
+ builtin_test('newlist_clear', [Constant(5, lltype.Signed)], FIXEDLIST,
+ """new_array_clear $5, <ArrayDescr> -> %r0""")
builtin_test('newlist', [], FIXEDPTRLIST,
"""new_array_clear $0, <ArrayDescr> -> %r0""")
@@ -179,15 +169,8 @@
"""newlist $5, """+alldescrs+""" -> %r0""")
builtin_test('newlist', [varoftype(lltype.Signed)], VARLIST,
"""newlist %i0, """+alldescrs+""" -> %r0""")
- builtin_test('newlist', [Constant(5, lltype.Signed),
- Constant(0, lltype.Signed)], VARLIST,
- """newlist $5, """+alldescrs+""" -> %r0""")
- builtin_test('newlist', [Constant(5, lltype.Signed),
- Constant(1, lltype.Signed)], VARLIST,
- NotSupported)
- builtin_test('newlist', [Constant(5, lltype.Signed),
- varoftype(lltype.Signed)], VARLIST,
- NotSupported)
+ builtin_test('newlist_clear', [Constant(5, lltype.Signed)], VARLIST,
+ """newlist_clear $5, """+alldescrs+""" -> %r0""")
def test_resizable_getitem():
builtin_test('list.getitem/NONNEG',
diff --git a/rpython/jit/metainterp/blackhole.py
b/rpython/jit/metainterp/blackhole.py
--- a/rpython/jit/metainterp/blackhole.py
+++ b/rpython/jit/metainterp/blackhole.py
@@ -1017,6 +1017,15 @@
return result
@arguments("cpu", "i", "d", "d", "d", "d", returns="r")
+ def bhimpl_newlist_clear(cpu, length, structdescr, lengthdescr,
+ itemsdescr, arraydescr):
+ result = cpu.bh_new(structdescr)
+ cpu.bh_setfield_gc_i(result, length, lengthdescr)
+ items = cpu.bh_new_array_clear(length, arraydescr)
+ cpu.bh_setfield_gc_r(result, items, itemsdescr)
+ return result
+
+ @arguments("cpu", "i", "d", "d", "d", "d", returns="r")
def bhimpl_newlist_hint(cpu, lengthhint, structdescr, lengthdescr,
itemsdescr, arraydescr):
result = cpu.bh_new(structdescr)
diff --git a/rpython/jit/metainterp/pyjitpl.py
b/rpython/jit/metainterp/pyjitpl.py
--- a/rpython/jit/metainterp/pyjitpl.py
+++ b/rpython/jit/metainterp/pyjitpl.py
@@ -522,6 +522,15 @@
return sbox
@arguments("box", "descr", "descr", "descr", "descr")
+ def opimpl_newlist_clear(self, sizebox, structdescr, lengthdescr,
+ itemsdescr, arraydescr):
+ sbox = self.opimpl_new(structdescr)
+ self._opimpl_setfield_gc_any(sbox, sizebox, lengthdescr)
+ abox = self.opimpl_new_array_clear(sizebox, arraydescr)
+ self._opimpl_setfield_gc_any(sbox, abox, itemsdescr)
+ return sbox
+
+ @arguments("box", "descr", "descr", "descr", "descr")
def opimpl_newlist_hint(self, sizehintbox, structdescr, lengthdescr,
itemsdescr, arraydescr):
sbox = self.opimpl_new(structdescr)
diff --git a/rpython/jit/metainterp/test/test_ajit.py
b/rpython/jit/metainterp/test/test_ajit.py
--- a/rpython/jit/metainterp/test/test_ajit.py
+++ b/rpython/jit/metainterp/test/test_ajit.py
@@ -12,7 +12,7 @@
AssertGreenFailed, unroll_safe, current_trace_length, look_inside_iff,
isconstant, isvirtual, set_param, record_known_class)
from rpython.rlib.longlong2float import float2longlong, longlong2float
-from rpython.rlib.rarithmetic import ovfcheck, is_valid_int
+from rpython.rlib.rarithmetic import ovfcheck, is_valid_int, int_force_ge_zero
from rpython.rtyper.lltypesystem import lltype, rffi
@@ -4111,3 +4111,11 @@
res = self.meta_interp(f, [10])
assert res == 42
+
+ def test_int_force_ge_zero(self):
+ def f(n):
+ return int_force_ge_zero(n)
+ res = self.interp_operations(f, [42])
+ assert res == 42
+ res = self.interp_operations(f, [-42])
+ assert res == 0
diff --git a/rpython/jit/metainterp/test/test_list.py
b/rpython/jit/metainterp/test/test_list.py
--- a/rpython/jit/metainterp/test/test_list.py
+++ b/rpython/jit/metainterp/test/test_list.py
@@ -414,3 +414,13 @@
res = self.meta_interp(f, [10])
assert res == 0
self.check_resops(call=0, cond_call=2)
+
+ def test_zero_init_resizable(self):
+ def f(n):
+ l = [0] * n
+ l.append(123)
+ return len(l) + l[0] + l[1] + l[2] + l[3] + l[4] + l[5] + l[6]
+
+ res = self.interp_operations(f, [10], listops=True, inline=True)
+ assert res == 11
+ self.check_operations_history(new_array_clear=1)
diff --git a/rpython/rlib/rarithmetic.py b/rpython/rlib/rarithmetic.py
--- a/rpython/rlib/rarithmetic.py
+++ b/rpython/rlib/rarithmetic.py
@@ -635,6 +635,12 @@
assert n <= p
return llop.int_between(lltype.Bool, n, m, p)
+def int_force_ge_zero(n):
+ """ The JIT special-cases this too. """
+ from rpython.rtyper.lltypesystem import lltype
+ from rpython.rtyper.lltypesystem.lloperation import llop
+ return llop.int_force_ge_zero(lltype.Signed, n)
+
@objectmodel.specialize.ll()
def byteswap(arg):
""" Convert little->big endian and the opposite
diff --git a/rpython/rtyper/lltypesystem/lloperation.py
b/rpython/rtyper/lltypesystem/lloperation.py
--- a/rpython/rtyper/lltypesystem/lloperation.py
+++ b/rpython/rtyper/lltypesystem/lloperation.py
@@ -216,6 +216,7 @@
'int_xor': LLOp(canfold=True),
'int_between': LLOp(canfold=True), # a <= b < c
+ 'int_force_ge_zero': LLOp(canfold=True), # 0 if a < 0 else a
'int_add_ovf': LLOp(canraise=(OverflowError,), tryfold=True),
'int_add_nonneg_ovf': LLOp(canraise=(OverflowError,), tryfold=True),
diff --git a/rpython/rtyper/lltypesystem/opimpl.py
b/rpython/rtyper/lltypesystem/opimpl.py
--- a/rpython/rtyper/lltypesystem/opimpl.py
+++ b/rpython/rtyper/lltypesystem/opimpl.py
@@ -225,6 +225,12 @@
assert lltype.typeOf(c) is lltype.Signed
return a <= b < c
+def op_int_force_ge_zero(a):
+ assert lltype.typeOf(a) is lltype.Signed
+ if a < 0:
+ return 0
+ return a
+
def op_int_and(x, y):
if not is_valid_int(x):
from rpython.rtyper.lltypesystem import llgroup
diff --git a/rpython/rtyper/rlist.py b/rpython/rtyper/rlist.py
--- a/rpython/rtyper/rlist.py
+++ b/rpython/rtyper/rlist.py
@@ -2,9 +2,10 @@
from rpython.flowspace.model import Constant
from rpython.rlib import rgc, jit, types
from rpython.rlib.debug import ll_assert
-from rpython.rlib.objectmodel import malloc_zero_filled, enforceargs
+from rpython.rlib.objectmodel import malloc_zero_filled, enforceargs,
specialize
from rpython.rlib.signature import signature
from rpython.rlib.rarithmetic import ovfcheck, widen, r_uint, intmask
+from rpython.rlib.rarithmetic import int_force_ge_zero
from rpython.rtyper.annlowlevel import ADTInterface
from rpython.rtyper.error import TyperError
from rpython.rtyper.lltypesystem.lltype import typeOf, Ptr, Void, Signed, Bool
@@ -474,15 +475,8 @@
# when we compute "ll_length() + 1".
-# jit note: this is normally special-cased by the oopspec,
-# but if item != const(0), then the special-casing fails and
-# we fall back to the look_inside_iff.
[email protected]_inside_iff(lambda LIST, count, item: jit.isconstant(count) and count
< 137)
[email protected]("newlist(count, item)")
-def ll_alloc_and_set(LIST, count, item):
- if count < 0:
- count = 0
- l = LIST.ll_newlist(count)
+def _ll_zero_or_null(item):
+ # Check if 'item' is zero/null, or not.
T = typeOf(item)
if T is Char or T is UniChar:
check = ord(item)
@@ -490,13 +484,60 @@
check = widen(item)
else:
check = item
- # as long as malloc is known to zero the allocated memory avoid zeroing
- # twice
- if jit.we_are_jitted() or (not malloc_zero_filled) or check:
- i = 0
- while i < count:
- l.ll_setitem_fast(i, item)
- i += 1
+ return not check
+
[email protected]()
+def _null_of_type(T):
+ return T._defl()
+
+def ll_alloc_and_set(LIST, count, item):
+ count = int_force_ge_zero(count)
+ if jit.we_are_jitted():
+ return _ll_alloc_and_set_jit(LIST, count, item)
+ else:
+ return _ll_alloc_and_set_nojit(LIST, count, item)
+
+def _ll_alloc_and_set_nojit(LIST, count, item):
+ l = LIST.ll_newlist(count)
+ if malloc_zero_filled and _ll_zero_or_null(item):
+ return l
+ i = 0
+ while i < count:
+ l.ll_setitem_fast(i, item)
+ i += 1
+ return l
+
+def _ll_alloc_and_set_jit(LIST, count, item):
+ if _ll_zero_or_null(item):
+ # 'item' is zero/null. Do the list allocation with the
+ # function _ll_alloc_and_clear(), which the JIT knows about.
+ return _ll_alloc_and_clear(LIST, count)
+ else:
+ # 'item' is not zero/null. Do the list allocation with the
+ # function _ll_alloc_and_set_nonnull(). That function has
+ # a JIT marker to unroll it, but only if the 'count' is
+ # a not-too-large constant.
+ return _ll_alloc_and_set_nonnull(LIST, count, item)
+
[email protected]("newlist_clear(count)")
+def _ll_alloc_and_clear(LIST, count):
+ l = LIST.ll_newlist(count)
+ if malloc_zero_filled:
+ return l
+ zeroitem = _null_of_type(LIST.ITEM)
+ i = 0
+ while i < count:
+ l.ll_setitem_fast(i, zeroitem)
+ i += 1
+ return l
+
[email protected]_inside_iff(lambda LIST, count, item: jit.isconstant(count) and count
< 137)
+def _ll_alloc_and_set_nonnull(LIST, count, item):
+ l = LIST.ll_newlist(count)
+ i = 0
+ while i < count:
+ l.ll_setitem_fast(i, item)
+ i += 1
return l
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit